static wbt_status wbt_save_argv(int argc, char** argv) { size_t len; int i; wbt_argc = argc; wbt_os_argv = argv; wbt_mem_t tmp_buf; if (wbt_malloc(&tmp_buf, (argc + 1) * sizeof(char *)) != WBT_OK) { return WBT_ERROR; } wbt_argv = tmp_buf.ptr; for (i = 0; i < argc; i++) { len = wbt_strlen(argv[i]) + 1; if(wbt_malloc(&tmp_buf, len) != WBT_OK) { return WBT_ERROR; } wbt_argv[i] = tmp_buf.ptr; memcpy((u_char *) wbt_argv[i], (u_char *) argv[i], len); } wbt_argv[i] = NULL; wbt_os_environ = environ; return WBT_OK; }
wbt_status wbt_conf_reload() { /* TODO 清理已保存的配置信息 */ /* 尝试读取配置文件 */ wbt_file_t wbt_config_file; wbt_config_file.fd = wbt_open_file(wbt_config_file_name.str); if( wbt_config_file.fd <= 0 ) { /* 找不到配置文件 */ wbt_log_print("Can't find config file: %.*s\n", wbt_config_file_name.len, wbt_config_file_name.str); return WBT_ERROR; } #ifndef WIN32 int len = wbt_get_file_path_by_fd(wbt_config_file.fd, wbt_config_file_path.str, wbt_config_file_path.len); if( len <= 0 ) { return WBT_ERROR; } wbt_config_file_path.str[len] = '\0'; #endif struct stat statbuff; if(stat(wbt_config_file_name.str, &statbuff) < 0){ return WBT_ERROR; } wbt_config_file.size = statbuff.st_size; wbt_config_file_content.len = wbt_config_file.size; wbt_config_file_content.str = wbt_malloc( wbt_config_file_content.len ); if( wbt_config_file_content.str == NULL ) { return WBT_ERROR; } if( wbt_read_file( wbt_config_file.fd, wbt_config_file_content.str, wbt_config_file_content.len, 0) != wbt_config_file_content.len ) { wbt_log_print("Read config file failed\n"); return WBT_ERROR; } /* 关闭配置文件 */ wbt_close_file(wbt_config_file.fd); /* 解析配置文件 */ if( wbt_conf_parse(&wbt_config_file_content) == WBT_OK ) { //wbt_rbtree_print(wbt_config_rbtree.root); wbt_free(wbt_config_file_content.str); #ifndef WIN32 char tmp[1024]; snprintf(tmp, sizeof(tmp), "bmq: master process (%.*s)", len, wbt_config_file_path.str ); wbt_set_proc_title(tmp); #endif return WBT_OK; } else { wbt_free(wbt_config_file_content.str); wbt_log_print("Syntax error on config file: line %d, charactor %d\n", wbt_conf_line, wbt_conf_charactor); return WBT_ERROR; } }
json_object_t * json_create_array() { json_object_t * obj = (json_object_t *) wbt_malloc(sizeof(json_object_t)); if( obj ) { memset(obj, 0, sizeof(json_object_t)); obj->object_type = JSON_ARRAY; } return obj; }
json_object_t * json_create_object() { json_object_t * obj = (json_object_t *) wbt_malloc(sizeof(json_object_t)); if( obj ) { memset(obj, 0, sizeof(json_object_t)); obj->object_type = JSON_OBJECT; } return obj; }
ssize_t wbt_file_read( wbt_file_t *file ) { if( file->fd <= 0 ) { return -1; } if( !file->ptr ) { file->ptr = wbt_malloc(file->size); if( !file->ptr ) { return -1; } return wbt_read_file(file->fd, file->ptr, file->size, 0); } return 0; }
wbt_status wbt_file_init() { /* 初始化一个红黑树用以保存已打开的文件句柄 */ wbt_rb_init(&wbt_file_rbtree, WBT_RB_KEY_STRING); /* 添加一个定时任务用以清理过期的文件句柄 */ wbt_timer_t *timer = wbt_malloc(sizeof(wbt_timer_t)); timer->on_timeout = wbt_file_cleanup; timer->timeout = wbt_cur_mtime + 10000; timer->heap_idx = 0; if(wbt_timer_add(timer) != WBT_OK) { return WBT_ERROR; } return WBT_OK; }
int main(int argc, char** argv) { /* 保存传入参数 */ if( wbt_save_argv(argc, argv) != WBT_OK ) { return 1; } /* 初始化日至输出缓冲 */ if( wbt_malloc( &wbt_log_buf, 1024 ) != WBT_OK ) { return 1; } /* 更新终端尺寸 */ wbt_term_update_size(); /* 解析传入参数 */ int ch; opterr = 0; while( ( ch = wbt_getopt(argc,argv,"c:hs:tv") ) != -1 ) { switch(ch) { case 'v': wbt_log_print( "webit version: webit/" WBT_VERSION "\n" ); return 0; case 'h': wbt_log_print( "\nOptions:\n" " -h : this help\n" " -v : show version and exit\n" " -s [stop|reload] : send signal to a master process\n" " -t [config-file] : test configuration and exit\n" " -c [config-file] : use the specified configuration\n\n"); return 0; case 'c': if( wbt_conf_set_file(optarg) != WBT_OK ) { return 1; } break; case '?': if( optopt == 'c' || optopt == 's' || optopt == 't' ) { wbt_log_print("option: -%c required parameters\n",optopt); } else { wbt_log_print("invalid option: -%c\n",optopt); } return 1; default: wbt_log_print("option: -%c not yet implemented\n",ch); return 1; } } wbt_init_proc_title(); /* 初始化所有组件 */ wbt_log_print( "webit version: webit/" WBT_VERSION "\n" ); if( wbt_module_init() != WBT_OK ) { wbt_log_print( "\n\n" ); return 1; } /* 设置程序允许打开的最大文件句柄数 */ struct rlimit rlim; rlim.rlim_cur = wbt_conf.max_open_files; rlim.rlim_max = 65535; setrlimit(RLIMIT_NOFILE, &rlim); /* 设置程序允许生成的 core dump 文件大小 */ if( wbt_conf.max_core_file_size < 0 ) { rlim.rlim_cur = RLIM_INFINITY; } else { rlim.rlim_cur = wbt_conf.max_core_file_size; } rlim.rlim_max = RLIM_INFINITY; setrlimit(RLIMIT_CORE, &rlim); /* 屏蔽 umask */ umask(0); /* 接下来的 chroot 会导致程序无法访问 /etc/timezone * TODO 读取 /etc/timezone 的内容并保存 */ if( setenv("TZ", "Asia/Shanghai", 1) != 0 ) { perror("setenv"); return 1; } tzset(); if( !wbt_conf.run_mode ) { wbt_log_print( "\n\nwebit is now running in the background.\n\n" ); /* 转入后台运行 */ if( daemon(1,0) < 0 ) { perror("error daemon"); return 1; } } else { wbt_log_print( "\n\nwebit is now running.\n\n" ); } /* 限制可以访问的目录 * 这个操作会导致 daemon() 不能正常运行 * 只有 root 用户才能执行该操作,为了使非 root 用户也能运行 webit,必须放弃使用 chroot */ //const char * wwwroot = wbt_stdstr(&wbt_conf.root); /* if( chroot( wwwroot ) != 0 ) { wbt_log_add("%s not exists.\n", wwwroot); return; } else { wbt_log_add("Root path: %s\n", wwwroot); }*/ if( !wbt_conf.run_mode ) { wbt_master_process(); } else { wbt_worker_process(); } return 0; }
void wbt_master_process() { /* 设置需要监听的信号(后台模式) */ struct sigaction act; sigset_t set; act.sa_sigaction = wbt_signal; sigemptyset(&act.sa_mask); act.sa_flags = SA_SIGINFO; sigemptyset(&set); sigaddset(&set, SIGCHLD); sigaddset(&set, SIGTERM); sigaddset(&set, SIGPIPE); sigaddset(&set, SIGUSR2); if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) { wbt_log_add("sigprocmask() failed\n"); } sigemptyset(&set); sigaction(SIGCHLD, &act, NULL); /* 子进程退出 */ sigaction(SIGTERM, &act, NULL); /* 命令 Webit 退出 */ sigaction(SIGPIPE, &act, NULL); /* 忽略 */ sigaction(SIGUSR2, &act, NULL); /* 更新二进制文件 */ /* TODO: 自定义的 reload 信号 */ time_t prev_time; int count = 0; while(1) { /* 防止 worker process 出错导致 fork 炸弹 */ wbt_time_update(); if( cur_mtime - prev_time <= 1000 ) { if( ( count ++ ) > 9 ) { wbt_log_add("try to fork child too fast\n"); /* 触发限制后,每 5s 尝试一次 * 由于阻塞了相关信号,这会导致信号处理出现延迟 */ sleep(5); } } else { count = 0; } prev_time = cur_mtime; /* fork + execve */ /* 在 master 进程中,只有监听端口和日志文件是打开状态,其中监听描述符需要被传递给新进程 */ /* 新老进程将共用监听端口同时提提供服务 */ if( wbt_wating_to_update && fork() == 0 ) { // 子进程并且 fork 成功 int i = 0; for (i = 0; wbt_os_environ[i]; i++) { } wbt_mem_t tmp; wbt_malloc(&tmp, (i + 3) * sizeof(char *)); wbt_environ = tmp.ptr; memcpy(wbt_environ, wbt_os_environ, i * sizeof(char *)); wbt_malloc(&tmp, 32 * sizeof(char *)); wbt_sprintf(&tmp, "WBT_LISTEN_FD=%d", listen_fd); wbt_environ[i] = tmp.ptr; wbt_environ[i+1] = "SPARE=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; wbt_environ[i+2] = NULL; if (execve(wbt_argv[0], wbt_argv, wbt_environ) < 0) { wbt_log_add("execve failed: errno:%d error:%s\n", errno, strerror(errno)); } } wbt_wating_to_update = 0; if( wbt_wating_to_exit ) { break; } /* 创建子进程直至指定数量 */ wbt_proc_create(wbt_worker_process, wbt_conf.process); sigsuspend(&set); } /* 结束所有子进程 */ pid_t child; while( ( child = wbt_proc_pop() ) != 0 ) { kill( child, SIGTERM ); } wbt_exit(0); }
wbt_rbtree_node_t * wbt_rbtree_insert(wbt_rbtree_t *rbt, wbt_str_t *key) { wbt_rbtree_node_t *tmp_node, *tail_node; wbt_mem_t buf; wbt_str_t tmp_str; int ret; /* 创建一个新的节点 */ wbt_malloc(&buf, sizeof(wbt_rbtree_node_t)); wbt_memset(&buf, 0); tmp_node = (wbt_rbtree_node_t *)buf.ptr; wbt_malloc(&tmp_node->key, key->len+1); wbt_memcpy(&tmp_node->key, (wbt_mem_t *)key, key->len); *((char *)tmp_node->key.ptr+key->len) = '\0'; tmp_node->left = tmp_node->right = wbt_rbtree_node_nil; tmp_node->parent = wbt_rbtree_node_nil; tmp_node->color = WBT_RBT_COLOR_RED; if( rbt->root == wbt_rbtree_node_nil ) { rbt->root = tmp_node; } else { tail_node = rbt->root; while(1) { tmp_str.len = tail_node->key.len-1; tmp_str.str = tail_node->key.ptr; ret = wbt_strcmp2(key, &tmp_str); if( ret == 0 ) { /* 键值已经存在 */ return NULL; } else if( ret > 0 ) { if( tail_node->right != wbt_rbtree_node_nil ) { tail_node = tail_node->right; } else { /* 找到了插入位置 */ tail_node->right = tmp_node; tmp_node->parent = tail_node; break; } } else { if( tail_node->left != wbt_rbtree_node_nil ) { tail_node = tail_node->left; } else { /* 找到了插入位置 */ tail_node->left = tmp_node; tmp_node->parent = tail_node; break; } } } } /* 插入节点后需要调整 */ wbt_rbtree_insert_fixup( rbt, tmp_node ); rbt->size ++; wbt_log_debug("rbtree insert"); return tmp_node; }
wbt_status wbt_mq_persist_recovery(wbt_timer_t *timer) { wbt_mq_persist_aof_lock(); wbt_msg_block_t *block; wbt_msg_t *msg; uint32_t crc32; ssize_t nread; char *data; block = wbt_malloc(sizeof(wbt_msg_block_t)); if(!block) { goto error; } int wait_time = 50; int n = 1000; while( !timer || n ) { if(wbt_is_oom()) { // 内存不足,等待一会儿再尝试恢复 wait_time = 1000; n = 0; break; } nread = wbt_read_file(wbt_persist_aof_fd, block, sizeof(wbt_msg_block_t), wbt_mq_persist_recovery_offset); if( nread == 0 ) { break; } else if( nread != sizeof(wbt_msg_block_t) ) { goto error; } else { wbt_mq_persist_recovery_offset += sizeof(wbt_msg_block_t); } if( wbt_conf.aof_crc ) { if (wbt_read_file(wbt_persist_aof_fd, &crc32, sizeof(uint32_t), wbt_mq_persist_recovery_offset) != sizeof(uint32_t)) { goto error; } else { wbt_mq_persist_recovery_offset += sizeof(uint32_t); } if( crc32 != wbt_crc32( (unsigned char *)block, sizeof(wbt_msg_block_t) ) ) { // 校验失败 goto error; } } /* 注意,这里可能出现 malloc(0) 的情况 * 目前看来,已知的 malloc 实现都会在 mallc(0) 时返回一个可用指针而不是 NULL * 但是,C 标准规定 malloc(0) 可以返回 NULL。如果发生这种情况,可以考虑故意多 * 申请一个字节的空间。 */ // data = wbt_malloc(block->data_len+1); data = wbt_malloc(block->data_len); if(!data) { goto error; } if (wbt_read_file(wbt_persist_aof_fd, data, block->data_len, wbt_mq_persist_recovery_offset) != block->data_len) { wbt_free( data ); goto error; } else { wbt_mq_persist_recovery_offset += block->data_len; } if( wbt_conf.aof_crc ) { if (wbt_read_file(wbt_persist_aof_fd, &crc32, sizeof(uint32_t), wbt_mq_persist_recovery_offset) != sizeof(uint32_t)) { wbt_free( data ); goto error; } else { wbt_mq_persist_recovery_offset += sizeof(uint32_t); } if( crc32 != wbt_crc32( (unsigned char *)data, block->data_len ) ) { // 校验失败 wbt_free( data ); goto error; } } wbt_log_debug( "msg %lld recovered\n", block->msg_id ); // 由于内存和文件中保存的结构并不一致,这里我们不得不进行内存拷贝 // TODO 修改消息相关的内存操作,尝试直接使用读入的内存 // TODO 使用 mdb 文件加速载入 // 已过期的消息应当被忽略 if( block->type == MSG_ACK ) { // 未过期但是已经收到 ACK 的负载均衡消息可能会在 fast_boot 期间被重复处理 wbt_msg_t *msg = wbt_mq_msg_get(block->consumer_id); if(msg) { wbt_mq_msg_event_expire( &msg->timer ); } wbt_free(data); } else if( block->expire > wbt_cur_mtime ) { msg = wbt_mq_msg_create(block->msg_id); if( msg == NULL ) { // * ID 冲突,忽略该条消息,并将该消息从 aof 文件中移除 // * 注意,只能通过重写 aof 文件来完成移除操作,如果在重写操作完 // 成之前程序再次重启,aof 文件中将存在一部分 msg_id 冲突的消息 // * 不使用 fast_boot 可以避免该问题 wbt_free(data); } else { wbt_memcpy(msg, block, sizeof(wbt_msg_block_t)); msg->data = data; wbt_mq_msg_delivery(msg); } } else { wbt_free(data); } n --; } wbt_log_add( "%d msg recovered\n", 1000-n ); //success: if(timer && ( n == 0 ) && !wbt_wating_to_exit) { /* 重新注册定时事件 */ timer->timeout += wait_time; if(wbt_timer_mod(timer) != WBT_OK) { goto error; } } else { wbt_free(timer); wbt_mq_persist_aof_unlock(); } wbt_free(block); return WBT_OK; error: wbt_free( block ); wbt_free( timer ); wbt_mq_persist_aof_unlock(); return WBT_ERROR; }
// * 遍历并导出内存中的所有活跃消息 // * 目前不允许对已投递消息做任何修改,所以我们可以将这个操作通过定时事件分步完成。 // * 和 fork 新进程的方式相比,这样做可以节省大量的内存。这允许我们更加频繁地执行该 // 操作。而我们需要付出的唯一代价是导出的文件中可能会存在少量刚刚过期的消息 // TODO static wbt_status wbt_mq_persist_dump(wbt_timer_t *timer) { char aof_file[256]; snprintf( aof_file, sizeof(aof_file), "%.*s/bmq.aof", wbt_conf.data.len, wbt_conf.data.str ); char mdp_file[256]; snprintf( mdp_file, sizeof(mdp_file), "%.*s/bmq.mdp", wbt_conf.data.len, wbt_conf.data.str ); // 临时文件 fd static wbt_fd_t rdp_fd = 0; // 记录当前的最大消息 ID max static wbt_mq_id processed_msg_id = 0; if( wbt_mq_persist_aof_is_lock() == 1 ) { // 如果目前正在从 aof 文件中恢复数据,则 dump 操作必须被推迟 // 这是为了保证 dump 完成的时刻,所有未过期消息都在内存中 if(timer && !wbt_wating_to_exit) { /* 重新注册定时事件 */ timer->timeout += 60 * 1000; if(wbt_timer_mod(timer) != WBT_OK) { return WBT_ERROR; } } // 发生数据恢复往往是因为旧的消息被删除了,所以推迟之后,dump 操作应当重新开始 rdp_fd = 0; return WBT_OK; } else if( 0 /* 如果当前负载过高 */) { // 如果当前负载过高,则 dump 操作必须被推迟 if(timer && !wbt_wating_to_exit) { /* 重新注册定时事件 */ timer->timeout += 3600 * 1000; if(wbt_timer_mod(timer) != WBT_OK) { return WBT_ERROR; } } // 负载过高时,会推迟很长一段时间再尝试,所以推迟之后,dump 操作应当重新开始 rdp_fd = 0; return WBT_OK; } if( !rdp_fd ) { // 创建临时文件 rdp_fd = wbt_open_tmpfile(mdp_file); if( (int)rdp_fd <= 0 ) { wbt_log_add("Could not open mdp file: %d\n", wbt_errno); // TODO data目录存在权限问题时会导致错误 return WBT_ERROR; } processed_msg_id = 0; } wbt_str_t key; wbt_variable_to_str(processed_msg_id, key); // 从小到大遍历消息,直至 max int max = 1000; wbt_rb_node_t *node; wbt_msg_t *msg; for (node = wbt_rb_get_greater(wbt_mq_msg_get_all(), &key); node; node = wbt_rb_next(node)) { msg = (wbt_msg_t *)node->value.str; if( wbt_mq_persist_append_to_file(rdp_fd, msg) == WBT_OK ) { processed_msg_id = msg->msg_id; } else { return WBT_ERROR; } if( --max <= 0 && timer ) { break; } } if( node == NULL ) { // 重写完成 // 如果刷盘策略为 AOF_FSYNC_ALWAYS,我们立刻将数据同步到磁盘上。 // 如果刷盘策略为 AOF_FSYNC_EVERYSEC,我们什么都不做,只需要等待定时任务执行 fsync(2)。 // 如果刷盘策略为 AOF_FSYNC_NO,我们什么都不做。 if( wbt_conf.aof_fsync == AOF_FSYNC_ALWAYS ) { wbt_sync_file(rdp_fd); } // 旧的 aof 文件已经无用了,不需要保证数据落盘,所以直接 close 即可 if( wbt_close_file(wbt_persist_aof_fd) < 0 ) { return WBT_ERROR; } wbt_persist_aof_fd = 0; // 用 mdp 文件覆盖 aof 文件 #ifdef WIN32 if(wbt_close_file(rdp_fd) < 0) { return WBT_ERROR; } rdp_fd = 0; if(MoveFileEx(mdp_file, aof_file, MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) == 0) { #else if( rename(mdp_file, aof_file) < 0 ) { #endif wbt_log_add("Could not rename mdp file. " "rename: %d\n", wbt_errno); // 尝试重新打开 aof 文件 wbt_persist_aof_fd = wbt_open_logfile(aof_file); if( (int)wbt_persist_aof_fd < 0 ) { wbt_persist_aof_fd = 0; wbt_log_add("Could not open AOF file: %d\n", wbt_errno); } return WBT_ERROR; } #ifdef WIN32 wbt_persist_aof_fd = wbt_open_logfile(aof_file); if( (int)wbt_persist_aof_fd <= 0 ) { wbt_persist_aof_fd = 0; wbt_log_add("Could not open AOF file: %d\n", wbt_errno); return WBT_ERROR; } #else wbt_persist_aof_fd = rdp_fd; rdp_fd = 0; #endif // 重写完成时,必然所有消息都在内存中生效,所以直接将 offset 设定为文件末尾 wbt_mq_persist_recovery_offset = wbt_get_file_size(wbt_persist_aof_fd); // 重写完成后,下一次重写将在设定的时间间隔之后运行 if(!wbt_wating_to_exit) { if(!timer) { timer = wbt_malloc(sizeof(wbt_timer_t)); timer->on_timeout = wbt_mq_persist_dump; timer->heap_idx = 0; timer->timeout = wbt_cur_mtime; } /* 重新注册定时事件 */ // TODO 从配置文件中读取 timer->timeout += 6 * 3600 * 1000; if(wbt_timer_mod(timer) != WBT_OK) { return WBT_ERROR; } } else { wbt_free(timer); } } else { if(!wbt_wating_to_exit) { /* 重新注册定时事件 */ timer->timeout += 50; if(wbt_timer_mod(timer) != WBT_OK) { return WBT_ERROR; } } else { wbt_free(timer); } } return WBT_OK; }
wbt_status wbt_mq_persist_init() { char mid_file[256]; snprintf( mid_file, sizeof(mid_file), "%.*s/bmq.mid", wbt_conf.data.len, wbt_conf.data.str ); char aof_file[256]; snprintf( aof_file, sizeof(aof_file), "%.*s/bmq.aof", wbt_conf.data.len, wbt_conf.data.str ); // 无论是否启用持久化,mid 都应当被保存,这样可以避免 msg_id 冲突(或减小其发生概率) wbt_persist_mid_fd = wbt_open_datafile(mid_file); if ((int)wbt_persist_mid_fd <= 0) { return WBT_ERROR; } // TODO 记录 wbt_persist_mid_fd 的值 // 读取 mid if (wbt_read_file(wbt_persist_mid_fd, &wbt_mq_persist_count, sizeof(wbt_mq_persist_count), 0) == sizeof(wbt_mq_persist_count)) { wbt_log_add("msg_id %lld recovered\n", wbt_mq_persist_count); wbt_mq_msg_init_snowflake(wbt_mq_persist_count); } else { wbt_mq_persist_count = 0; } if( !wbt_conf.aof ) { return WBT_OK; } wbt_persist_aof_fd = wbt_open_logfile(aof_file); if( (int)wbt_persist_aof_fd <= 0 ) { return WBT_ERROR; } wbt_persist_aof_size = wbt_get_file_size(wbt_persist_aof_fd); if( wbt_persist_aof_size < 0 ) { return WBT_ERROR; } // redis 2.4. 以后开始使用后台线程异步刷盘,我们暂时不那么做 if( wbt_conf.aof_fsync == AOF_FSYNC_EVERYSEC ) { wbt_timer_t *timer = wbt_malloc(sizeof(wbt_timer_t)); timer->on_timeout = wbt_mq_persist_timer; timer->timeout = wbt_cur_mtime + 1 * 1000; timer->heap_idx = 0; if( wbt_timer_add(timer) != WBT_OK ) { return WBT_ERROR; } } if( wbt_conf.aof_fast_boot && wbt_mq_persist_count ) { wbt_timer_t *timer = wbt_malloc(sizeof(wbt_timer_t)); timer->on_timeout = wbt_mq_persist_recovery; timer->timeout = wbt_cur_mtime; timer->heap_idx = 0; if( wbt_timer_add(timer) != WBT_OK ) { return WBT_ERROR; } // TODO 启动后立刻进行重写可能并不合适 timer = wbt_malloc(sizeof(wbt_timer_t)); timer->on_timeout = wbt_mq_persist_dump; timer->timeout = wbt_cur_mtime + 1; // +1 是为了确保先执行 recovery,再执行 dump timer->heap_idx = 0; if( wbt_timer_add(timer) != WBT_OK ) { return WBT_ERROR; } } else { wbt_mq_persist_recovery(NULL); wbt_mq_persist_dump(NULL); } return WBT_OK; }
wbt_status wbt_conf_init() { wbt_rb_init(&wbt_config_rbtree, WBT_RB_KEY_STRING); wbt_config_file_path.len = 64; wbt_config_file_path.str = wbt_malloc( wbt_config_file_path.len ); if( wbt_config_file_path.str == NULL ) { return WBT_ERROR; } if( wbt_conf_reload() != WBT_OK ) { return WBT_ERROR; } /* 初始化 wbt_conf */ const char * value; wbt_str_t * m_value; wbt_conf.listen_port = 80; if( ( value = wbt_conf_get("listen") ) != NULL ) { wbt_conf.listen_port = atoi(value); if( wbt_conf.listen_port < 0 || wbt_conf.listen_port > 65535 ) { wbt_log_print("listen port out of range ( expect 0 - 65535 )\n"); return WBT_ERROR; } } wbt_conf.process = 1; if( ( value = wbt_conf_get("process") ) != NULL ) { wbt_conf.process = atoi(value); if( wbt_conf.process < 1 || wbt_conf.process > 128 ) { wbt_log_print("worker process number out of range ( expect 1 - 128 )\n"); return WBT_ERROR; } } wbt_conf.secure = 0; if( ( m_value = wbt_conf_get_v("secure") ) != NULL ) { if( wbt_strcmp( m_value, &wbt_conf_option_on ) == 0 ) { wbt_conf.secure = 1; } } wbt_conf.secure_port = 443; if( ( value = wbt_conf_get("secure_port") ) != NULL ) { wbt_conf.secure_port = atoi(value); if( wbt_conf.secure_port < 0 || wbt_conf.secure_port > 65535 ) { wbt_log_print("secure port out of range ( expect 0 - 65535 )\n"); return WBT_ERROR; } } wbt_str_set_null(wbt_conf.secure_key); wbt_str_set_null(wbt_conf.secure_crt); if( wbt_conf.secure ) { if( ( m_value = wbt_conf_get_v("secure_key") ) != NULL ) { wbt_conf.secure_key = *m_value; } else { wbt_log_print("option secure_key is required\n"); return WBT_ERROR; } if( ( m_value = wbt_conf_get_v("secure_crt") ) != NULL ) { wbt_conf.secure_crt = *m_value; } else { wbt_log_print("option secure_crt is required\n"); return WBT_ERROR; } } wbt_conf.sendfile = 0; if( !wbt_conf.secure ) { if( ( m_value = wbt_conf_get_v("sendfile") ) != NULL ) { if( wbt_strcmp( (wbt_str_t *)m_value, &wbt_conf_option_on ) == 0 ) { wbt_conf.sendfile = 1; } } } wbt_conf.gzip = 0; if( ( m_value = wbt_conf_get_v("gzip") ) != NULL ) { if( wbt_strcmp( (wbt_str_t *)m_value, &wbt_conf_option_on ) == 0 ) { wbt_conf.gzip = 1; } } wbt_conf.aof = 1; if( ( m_value = wbt_conf_get_v("aof") ) != NULL ) { if( wbt_strcmp( (wbt_str_t *)m_value, &wbt_conf_option_off ) == 0 ) { wbt_conf.aof = 0; } } wbt_conf.aof_crc = 0; if( ( m_value = wbt_conf_get_v("aof_crc") ) != NULL ) { if( wbt_strcmp( (wbt_str_t *)m_value, &wbt_conf_option_on ) == 0 ) { wbt_conf.aof_crc = 1; } } wbt_conf.aof_fsync = AOF_FSYNC_EVERYSEC; if( ( m_value = wbt_conf_get_v("aof_fsync") ) != NULL ) { if( wbt_strcmp( (wbt_str_t *)m_value, &wbt_conf_option_off ) == 0 ) { wbt_conf.aof_fsync = AOF_FSYNC_NO; } else if( wbt_strcmp( (wbt_str_t *)m_value, &wbt_conf_option_always ) == 0 ) { wbt_conf.aof_fsync = AOF_FSYNC_ALWAYS; } else if( wbt_strcmp( (wbt_str_t *)m_value, &wbt_conf_option_everysec ) == 0 ) { wbt_conf.aof_fsync = AOF_FSYNC_EVERYSEC; } else { wbt_log_print("option aof_fsync is illegal ( expect off / always / everysec )\n"); return WBT_ERROR; } } wbt_conf.aof_fast_boot = 1; if( ( m_value = wbt_conf_get_v("aof_fast_boot") ) != NULL ) { if( wbt_strcmp( (wbt_str_t *)m_value, &wbt_conf_option_off ) == 0 ) { wbt_conf.aof_fast_boot = 0; } } wbt_conf.auth = 0; if( ( m_value = wbt_conf_get_v("auth") ) != NULL ) { if( wbt_strcmp( (wbt_str_t *)m_value, &wbt_conf_option_none ) == 0 ) { wbt_conf.auth = 0; } else if( wbt_strcmp( (wbt_str_t *)m_value, &wbt_conf_option_basic ) == 0 ) { wbt_conf.auth = 1; } else if( wbt_strcmp( (wbt_str_t *)m_value, &wbt_conf_option_standard ) == 0 ) { wbt_conf.auth = 2; } else { wbt_log_print("option auth is illegal ( expect none / baisc / standard )\n"); return WBT_ERROR; } } if( wbt_conf.auth == 1 ) { wbt_str_set_null(wbt_conf.auth_password); if( ( m_value = wbt_conf_get_v("auth_password") ) != NULL ) { wbt_conf.auth_key = *m_value; } else { wbt_log_print("option auth_password is required\n"); return WBT_ERROR; } } else if( wbt_conf.auth == 2 ) { wbt_str_set_null(wbt_conf.auth_key); if( ( m_value = wbt_conf_get_v("auth_key") ) != NULL ) { wbt_conf.auth_key = *m_value; } else { wbt_log_print("option auth_key is required\n"); return WBT_ERROR; } } wbt_str_set_null(wbt_conf.auth_anonymous); if( ( m_value = wbt_conf_get_v("auth_anonymous") ) != NULL ) { wbt_conf.auth_anonymous = *m_value; } wbt_conf.keep_alive_timeout = 600000; if( ( value = wbt_conf_get("keep_alive_timeout") ) != NULL ) { wbt_conf.keep_alive_timeout = atoi(value); } wbt_conf.event_timeout = 150000; if( ( value = wbt_conf_get("event_timeout") ) != NULL ) { wbt_conf.event_timeout = atoi(value); } wbt_conf.max_open_files = 65535; if( ( value = wbt_conf_get("max_open_files") ) != NULL ) { wbt_conf.max_open_files = atoi(value); } wbt_conf.max_core_file_size = 0; if( ( value = wbt_conf_get("max_core_file_size") ) != NULL ) { wbt_conf.max_core_file_size = atoi(value); } wbt_conf.max_memory_usage = 0; if( ( value = wbt_conf_get("max_memory_usage") ) != NULL ) { wbt_conf.max_memory_usage = 1024*1024*atoll(value); } wbt_conf.master_port = 1039; if( ( value = wbt_conf_get("master_port") ) != NULL ) { wbt_conf.master_port = atoi(value); } wbt_str_set_null(wbt_conf.root); if( ( m_value = wbt_conf_get_v("root") ) != NULL ) { wbt_conf.root = *m_value; // TODO 检查 root 是否存在 } else { wbt_log_print("option root is required\n"); return WBT_ERROR; } wbt_str_set_null(wbt_conf.index); if( ( m_value = wbt_conf_get_v("default") ) != NULL ) { wbt_conf.index = *m_value; } wbt_str_set_null(wbt_conf.admin); if( ( m_value = wbt_conf_get_v("server_admin") ) != NULL ) { wbt_conf.admin = *m_value; } wbt_str_set_null(wbt_conf.user); if( ( m_value = wbt_conf_get_v("user") ) != NULL ) { wbt_conf.user = *m_value; } wbt_str_set_null(wbt_conf.data); if( ( m_value = wbt_conf_get_v("data") ) != NULL ) { wbt_conf.data = *m_value; } else { wbt_log_print("option data is required\n"); return WBT_ERROR; } wbt_str_set_null(wbt_conf.logs); if( ( m_value = wbt_conf_get_v("logs") ) != NULL ) { wbt_conf.logs = *m_value; } else { wbt_log_print("option logs is required\n"); return WBT_ERROR; } wbt_str_set_null(wbt_conf.master_host); if( ( m_value = wbt_conf_get_v("master_host") ) != NULL ) { wbt_conf.master_host = *m_value; } wbt_conf.worker_id = 0; if( ( value = wbt_conf_get("worker_id") ) != NULL ) { wbt_conf.worker_id = atoi(value); if( wbt_conf.worker_id < 0 || wbt_conf.worker_id > SF_MAX_WORKER_ID ) { wbt_log_print("worker_id out of range ( expect 0 - %d )\n", SF_MAX_WORKER_ID); return WBT_ERROR; } } return WBT_OK; }