Example #1
0
// 自动分割日志文件
wbt_status wbt_log_rotate() {
    // 重命名旧的日志文件
    char log_file[256];
    snprintf( log_file, sizeof(log_file), "%.*s/bmq.log", wbt_conf.logs.len, wbt_conf.logs.str );
  
    char new_log_file[256];
    snprintf( new_log_file, sizeof(new_log_file), "%.*s/bmq_%lu.log", wbt_conf.logs.len, wbt_conf.logs.str, wbt_cur_mtime );

#ifdef WIN32
    if(wbt_close_file(wbt_log_file_fd) < 0) {
        return WBT_ERROR;
    }
    wbt_log_file_fd = 0;

    if(MoveFileEx(log_file, new_log_file, MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH) == 0) {
        // 尝试重新打开日志文件
	    wbt_log_file_fd = wbt_open_logfile(log_file);
        if( (int)wbt_log_file_fd <=0 ) {
            wbt_log_file_fd = 0;
		    wbt_log_debug("can't open log file, errno: %d\n", wbt_errno);
        }

        return WBT_ERROR;
    }
#else
    if( rename(log_file, new_log_file) < 0 ) {
        // Bugfix: 如果 rename 执行失败,继续调用 wbt_lod_add 会导致死循环
        wbt_log_debug("Could not rename log file. "
            "rename: %d\n", wbt_errno);

        return WBT_ERROR;
    }
#endif

    // 创建新的日志文件
    wbt_log_file_fd = wbt_open_logfile(log_file);
    if( (int)wbt_log_file_fd <=0 ) {
        wbt_log_file_fd = 0;
		wbt_log_debug("can't open log file, errno: %d\n", wbt_errno);
        return WBT_ERROR;
    }
    
    // 可选:压缩旧的日志文件
    
    // 可选:清理旧的日志文件
    
    return WBT_OK;
}
Example #2
0
void wbt_rbtree_print(wbt_rbtree_node_t *node) {
    if(node != wbt_rbtree_node_nil) {
        wbt_rbtree_print(node->left);
        wbt_log_debug("%.*s", node->key.len, (char *)node->key.ptr);
        wbt_rbtree_print(node->right);
    }
}
Example #3
0
wbt_status wbt_log_init() {
    char log_file[256];
    snprintf( log_file, sizeof(log_file), "%.*s/bmq.log", wbt_conf.logs.len, wbt_conf.logs.str );
    
    /* O_CLOEXEC 需要 Linux 内核版本大于等于 2.6.23 */
    /* TODO 每个 worker 进程需要单独的日志文件,否则并发写会丢失一部分数据 */
    wbt_log_file_fd = wbt_open_logfile(log_file);
    if( (int)wbt_log_file_fd <=0 ) {
        wbt_log_debug("can't open log file, errno: %d\n", wbt_errno);
        return WBT_ERROR;
    }
    
    // 获取日志文件大小
    wbt_log_file_size = wbt_get_file_size( wbt_log_file_fd );
    if( wbt_log_file_size < 0 ) {
        wbt_log_debug("can't get log file size, errno: %d\n", wbt_errno);
        return WBT_ERROR;
    }
    
    return WBT_OK;
}
Example #4
0
void wbt_file_cleanup_recursive(wbt_rb_node_t *node) {
    /* 从叶节点递归处理至根节点 */
    if(node) {
        wbt_file_cleanup_recursive(node->left);
        wbt_file_cleanup_recursive(node->right);
        
        wbt_file_t * tmp_file = (wbt_file_t *)node->value.str;
        if( tmp_file->refer == 0 && wbt_cur_mtime - tmp_file->last_use_mtime > 10000 ) {
            wbt_log_debug("closed fd:%d %.*s\n", tmp_file->fd, node->key.len, node->key.str.s);
            wbt_close_file(tmp_file->fd);
            wbt_free(tmp_file->ptr);
            wbt_free(tmp_file->gzip_ptr);
            wbt_rb_delete(&wbt_file_rbtree, node);
        }
    }
}
Example #5
0
// 在红黑树 rbt 中删除结点 node
void wbt_rbtree_delete(wbt_rbtree_t * rbt, wbt_rbtree_node_t * node) {
    wbt_rbtree_node_t * y; // 将要被删除的结点 
    wbt_rbtree_node_t * x; // 将要被删除的结点的唯一儿子 
    
    if( node->left == wbt_rbtree_node_nil || node->right == wbt_rbtree_node_nil ) {
        // 如果 node 有一个子树为空的话,那么将直接删除 node,即 y 指向 node
        y = node;
    } else {
        // 如果 node 的左右子树皆不为空的话,则寻找 node 的中序后继 y,
        // 用其值代替 node 的值,然后将 y 删除 ( 注意: y肯定是没有左子树的 ) 
        y = wbt_rbtree_successor(rbt, node);  
    }

    if( y->left != wbt_rbtree_node_nil ) {
        // 如果y的左子树不为空,则 x 指向 y 的左子树 
        x = y->left; 
    } else { 
        x = y->right; 
    }

    // 将原来 y 的父母设为 x 的父母,y 即将被删除
    x->parent = y->parent;

    if( y->parent == wbt_rbtree_node_nil ) { 
        rbt->root=x; 
    } else { 
        if( y == y->parent->left ) { 
            y->parent->left = x; 
        } else { 
            y->parent->right = x; 
        } 
    }

    if( y != node ) {
        // 如果被删除的结点 y 不是原来将要删除的结点 node,
        // 即只是用 y 的值来代替 node 的值,然后变相删除 y 以达到删除 node 的效果
        wbt_free( &node->value );
        node->value = y->value;
        wbt_free( &node->key );
        node->key = y->key;
        
        y->key.ptr = NULL;
        y->key.len = 0;
    }

    if( y->color == WBT_RBT_COLOR_BLACK ) {
        // 如果被删除的结点 y 的颜色为黑色,那么可能会导致树违背性质4,导致某条路径上少了一个黑色 
        wbt_rbtree_delete_fixup(rbt, x); 
    }

    /* 删除 y */
    wbt_mem_t tmp;
    tmp.ptr = y;
    tmp.len = sizeof(wbt_rbtree_node_t);
    wbt_free( &y->key );
    wbt_free( &tmp );

    rbt->size --;
    
    wbt_rbtree_print(rbt->root);
    wbt_log_debug("rbtree delete");
} 
Example #6
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;
}
Example #7
0
wbt_file_t * wbt_file_open( wbt_str_t * file_path ) {    
    //wbt_log_debug("try to open: %.*s\n", file_path->len, file_path->str);
    /* TODO 不存在的文件也可以考虑放入文件树内
     * 如果发生大量的 404 请求,可以提高性能
     */

    if( file_path->len >= 512 ) {
        /* 路径过长则拒绝打开 */
        /* 由于接收数据长度存在限制,这里无需担心溢出 */
        wbt_log_debug("file path too long\n");

        tmp.fd = (wbt_fd_t)-3;
        
        return &tmp;
    }

    wbt_rb_node_t *file =  wbt_rb_get(&wbt_file_rbtree, file_path);
    if( file == NULL ) {
#ifndef WIN32
        struct stat statbuff;  
        if(stat(file_path->str, &statbuff) < 0){  
            /* 文件访问失败 */
            tmp.size = 0;
            if( errno == ENOENT ) {
                tmp.fd   = -1;  /* 文件不存在 */
            } else {
                tmp.fd   = -2;  /* 权限不足或者其他错误 */
            }
            //wbt_log_debug("stat: %s\n", strerror(errno));
        }else{  
            if( S_ISDIR(statbuff.st_mode) ) {
                 /* 尝试打开的是目录 */
                tmp.size = 0;
                tmp.fd   = -2;
            } else {
                /* 尝试打开的是文件 */
                tmp.size = statbuff.st_size;
                tmp.fd = open(file_path->str, O_RDONLY);
                tmp.last_modified =  statbuff.st_mtime;

                if( tmp.fd > 0 ) {
                    file = wbt_rb_insert(&wbt_file_rbtree, file_path);

                    file->value.str = wbt_calloc(sizeof(wbt_file_t));
                    if( file->value.str == NULL ) {
                        // TODO 如果这里失败了,该文件将永远不会被关闭
                        wbt_rb_delete(&wbt_file_rbtree, file);
                    } else {
                        wbt_file_t * tmp_file = (wbt_file_t *)file->value.str;

                        tmp_file->fd = tmp.fd;
                        tmp_file->refer = 1;
                        tmp_file->size = tmp.size;
                        tmp_file->last_modified = tmp.last_modified;
                        tmp_file->mime_type = wbt_file_mime_type(file_path);

                        wbt_log_debug("open file: %d " JL_SIZE_T_SPECIFIER "\n", tmp_file->fd, tmp_file->size);
                        return tmp_file;
                    }
                } else {
                    tmp.size = 0;
                    if( errno == EACCES ) {
                        tmp.fd   = -2;
                    } else {
                        tmp.fd   = -1;
                    }
                }
            }
        }
#else
        tmp.fd = wbt_open_file(file_path->str);
        if (tmp.fd == INVALID_HANDLE_VALUE) {
            tmp.fd = (wbt_fd_t)-1;
        }
        else {
            file = wbt_rb_insert(&wbt_file_rbtree, file_path);

            file->value.str = wbt_calloc(sizeof(wbt_file_t));
            if (file->value.str == NULL) {
                // TODO 如果这里失败了,该文件将永远不会被关闭
                wbt_rb_delete(&wbt_file_rbtree, file);
            }
            else {
                wbt_file_t * tmp_file = (wbt_file_t *)file->value.str;

                tmp_file->fd = tmp.fd;
                tmp_file->refer = 1;
                tmp_file->size = wbt_get_file_size(tmp.fd);
                tmp_file->last_modified = wbt_get_file_last_write_time(tmp.fd);
                tmp_file->mime_type = wbt_file_mime_type(file_path);

                wbt_log_debug( "open file: %d " JL_SIZE_T_SPECIFIER "\n", tmp_file->fd, tmp_file->size );
                return tmp_file;
            }
        }
#endif
    } else {
        wbt_file_t * tmp_file = (wbt_file_t *)file->value.str;
        tmp_file->refer ++;

        return tmp_file;
    }

    return &tmp;
}
Example #8
0
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;
}