内存数据库内核开发 工作日志(内存索引实现原理)(附红黑树实现清晰完整直接可编译运行代码)(十)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介:

 

   之前由于考虑到使用Page的内存和磁盘互换的机制实现了B-tree做为数据库的键值索引,在真实的生产环境下2000万以上的数据建立索引会使到B-tree层数增多,效率明显下降,在运算工程中使用AIX大型机都用了数天才将2000多万的数据生成出来,效果非常不理想。
   全新的框架采用了纯内存的红黑树作为数据的索引,效果很好,性能测试中,用thinkpad 201i 电脑建立1000万的红黑树只用了3分钟,消耗内存270M这在电信项目的生产环境是完全可以接受的。
   该代码使用内存池和红黑树的技术,参考主要文献包括:
   http://zh.wikipedia.org/zh/%E7%BA%A2%E9%BB%91%E6%A0%91 维基百科
   IBM文章,http://www.ibm.com/developerworks/cn/linux/l-cn-ppp/index6.html
   当然网上许多人的实现也给了我很好的启示,恕在下不能一一列出。
   也许你会说,不就实现了STL MAP的功能吗?可以这么说,因为内存中建立数据结构,红黑树是最优的方案,我只能使用这样的---像map一样的东西。
   以下是大致实现代码的思路,使用内存池来存放两类数据,一类是存放红黑树节点的内存池,一类是存放键值节点的内存池。

 

   实例代码并不是用于项目中的实现,而是呈现内存索引的DEMO,其中delete的实现我没有实现内存释放,读者可以自己添加,相信它是网上能找到的最好,最清晰的红黑树能直接编译并稳定使用的代码,网上文章的代码都有这样那样的问题,最后还是根据理论自己实现了。

   很多朋友对于内存数据库开发Email给我不能一一回复很抱歉,希望代码对各位有帮助。 

 

  另外内存池的代码请参考我的另一篇文章,内存池的实现 内存池完整实现代码及一些思考

 

 

 


复制代码
复制代码
//该代码参照维基百科提供http://zh.wikipedia.org/zh/%E7%BA%A2%E9%BB%91%E6%A0%91 提供理论基础,2010-2011年由 konyellin Email: konyel@163.com进行整理修改



#include <string>
#include "MemoryPool.h"

#define    RB_INT        0
#define    RB_FLOAR    1
#define    RB_CHAR     2



struct rb_node
{
    unsigned short  color;
#define    RB_RED        0
#define    RB_BLACK    1
    struct rb_node* right;
    struct rb_node* left;
    struct rb_node* parent;
    void* memoryblock;
    void* key;
};

class rb_tree{
public:
    rb_tree(unsigned short type);
   //search
   rb_node* rb_search(void* key);
   void  rb_insert(void* key);
   rb_node*  rb_delete(void* key);
   //debug
   void print_tree(struct rb_node* root,int nLayer);


   struct rb_node* root;
   
private:
   MemoryPool* pool;
   unsigned short datetype;
  
   //insert case
   void __insert_case1(struct rb_node* n);
   void __insert_case2(struct rb_node* n);
   void __insert_case3(struct rb_node* n);
   void __insert_case4(struct rb_node* n);
   void __insert_case5(struct rb_node* n);

   //delete case
   void __delete_case1(struct rb_node* n);
   void __delete_case2(struct rb_node* n);
   void __delete_case3(struct rb_node* n);
   void __delete_case4(struct rb_node* n);
   void __delete_case5(struct rb_node* n);
   void __delete_case6(struct rb_node* n);

   //rotate
   void __rotate_left(struct rb_node *node);
   void __rotate_right(struct rb_node *node);
   void __replace_node(struct rb_node* node ,struct rb_node*  child);
   bool __is_leaf(struct rb_node* n);
   
   //查户口
   rb_node* __grandparent(struct rb_node* n);
   rb_node* __uncle(struct rb_node* n);
   rb_node* __sibling(struct rb_node* n);

   //比较键值查询
   int __rb_cmpkey(void* key1,void* key2);

   rb_node* __createnode(void* key);
};
复制代码
复制代码

 

复制代码
复制代码
#include "Rbtree.h"


rb_tree::rb_tree(unsigned short type):datetype(type){
   root=NULL;
   pool=new MemoryPool(sizeof(rb_node));
}

/*----------------------------------------------------------- 
|   node           right 
|   / \    ==>     / \ 
|   a  right     node  y 
|       / \       / \     
|       b  y     a   b    //左旋 
-----------------------------------------------------------*/  
rb_node* rb_tree::rb_search(void* key){
  struct rb_node* fnode=root;
  bool iskey=true;int ret=0;
  while(ret=__rb_cmpkey(fnode->key,key)){
      if(__is_leaf(fnode)){
         iskey=0;
         break;
      }
      if(ret>0)
            fnode=fnode->right;
      else
            fnode=fnode->left;
            
  }
  if(iskey)
    return fnode;
  else
    return NULL;
}



void rb_tree::__rotate_left(struct rb_node *node){
  rb_node* right = node->right;                   //指定指针指向 right<--node->right  
    if ((node->right = right->left))     
        right->left->parent = node;                 //好比上面的注释图,node成为b的父母  
    right->left = node;                             //node成为right的左孩子   
    if ((right->parent = node->parent)) {           //如果node根节点为空,node本身为根节点  
        if (node == node->parent->right)            //如果node为右节点
            node->parent->right = right;  
        else  
            node->parent->left = right;  
    }  
    else  
        root = right;   
    node->parent = right;                           //right成为node的父母   
}

void rb_tree::__rotate_right(struct rb_node *node){
    rb_node* left = node->left;  
    if ((node->left = left->right))
        left->right->parent = node;  
    left->right = node;  
    if ((left->parent = node->parent)){  
        if (node == node->parent->right)  
            node->parent->right = left;  
        else  
            node->parent->left = left;  
    }  
    else  
        root = left;  
    node->parent = left; 
}

rb_node* rb_tree::__grandparent(struct rb_node* n) {
   if(n->parent==NULL)
       return NULL;
   return n->parent->parent;
}
rb_node* rb_tree::__uncle(struct rb_node* n) {
    if(__grandparent(n)==NULL)
        return NULL;
    if (n->parent == __grandparent(n)->left)
    return __grandparent(n)->right;
    else
    return __grandparent(n)->left;
}

rb_node* rb_tree::__sibling(struct rb_node* n){
    if (n == n->parent->left)
    return n->parent->right;
    else
    return n->parent->left;
}

void rb_tree::__replace_node(struct rb_node* n, struct rb_node* child){
    child->memoryblock=n->memoryblock;
    child->key=n->key;
}
rb_node* rb_tree::__createnode(void* key){
       struct rb_node* node=(rb_node*)pool->Alloc();
       memset(node,0x00,sizeof(rb_node));
       node->key=key;
       node->color=RB_RED;
       return node;
}

bool rb_tree::__is_leaf(struct rb_node* n){
    if(n->left==NULL&&n->right==NULL)
        return true;
    return false;
}
int rb_tree::__rb_cmpkey(void* key1,void* key2){
    switch(datetype){
       case RB_INT:{
            if(*((int*)key1)<*((int*)key2))
              return -1;
            else if(*((int*)key1)>*((int*)key2))
              return 1;
            else 
              return 0;
            break;
            }
       case RB_FLOAR:{
            if(*((float*)key1)<*((float*)key2))
                  return -1;
                else if(*((float*)key1)>*((float*)key2))
                  return 1;
                else 
                  return 0;
                break;
            }
       case RB_CHAR:{
            char* s1=(char*)key1;char* s2=(char*)key1;
            return strcmp(s1,s2);
            break;
            }
    }
    return 0;
}
//按树状打印的二叉树
void rb_tree::print_tree(struct rb_node* root,int nLayer)
{
    if(root==NULL)
        return ;
    print_tree(root->right,nLayer+1);
    for(int i=0;i<nLayer;i++){
       printf("   ");
    }
    printf("%d-%d\n",*(int*)root->key,root->color);
    print_tree(root->left,nLayer+1);
}
复制代码
复制代码

 

复制代码
复制代码
#include "Rbtree.h"



//如果插入为根节点
void rb_tree::__insert_case1(struct rb_node* n){
    if (n->parent == NULL){
        n->color = RB_BLACK;
    }
    else
    __insert_case2(n);
}

void rb_tree::__insert_case2(struct rb_node* n){
   if (!(n->parent->color == RB_BLACK))
   __insert_case3(n);
}
//叔叔为红色节点的情况
void rb_tree::__insert_case3(struct rb_node* n){
    if (__uncle(n) != NULL && __uncle(n)->color == RB_RED) {
        n->parent->color = RB_BLACK;
        __uncle(n)->color = RB_BLACK;
        __grandparent(n)->color = RB_RED;
        __insert_case1(__grandparent(n));
    }
    else{
        __insert_case4(n);
    }
}

void rb_tree::__insert_case4(struct rb_node* n) {
    if (n == n->parent->right && n->parent == __grandparent(n)->left) {
        __rotate_left(n->parent);
        n = n->left;
    } else if (n == n->parent->left && n->parent == __grandparent(n)->right) {
        __rotate_right(n->parent);
        n = n->right;
    }
    __insert_case5(n);
}

void rb_tree::__insert_case5(struct rb_node* n) {
    n->parent->color = RB_BLACK;
    __grandparent(n)->color = RB_RED;
    if (n == n->parent->left && n->parent == __grandparent(n)->left) {
        __rotate_right(__grandparent(n));
    } else {
        __rotate_left(__grandparent(n));
   }
}


void rb_tree::rb_insert(void* key){
    struct rb_node* addnode = __createnode(key);
    //为空树的情况,创建根节点
    if(root==NULL){
         root=addnode;
         //根节点染黑
         root->color=RB_BLACK;
         return;
    }
    struct rb_node* fnode=root;
    int ret=0;
    while(ret=__rb_cmpkey(fnode->key,key)){
        if(__is_leaf(fnode)){
            if(ret>0){
                fnode->right=addnode;
                addnode->parent=fnode;
            }
            else{
                fnode->left=addnode;
                addnode->parent=fnode;
            }
            break;
        }
        if(ret>0)
            fnode=fnode->right;
        else
            fnode=fnode->left;
    }
    __insert_case1(addnode);
}

 

 

复制代码
复制代码
//Rbtree_Delete.cpp by konyel
#include "Rbtree.h"



void rb_tree::__delete_case1(struct rb_node* n){
    if (n->parent != NULL)
    __delete_case2(n);
}

void rb_tree::__delete_case2(struct rb_node* n)
{
    struct rb_node* s = __sibling(n);
    if (s->color == RB_RED) {
        n->parent->color = RB_RED;
        s->color = RB_BLACK;
        if (n == n->parent->left)
        __rotate_left(n->parent);
        else
        __rotate_right(n->parent);
    }
    __delete_case3(n);
}

void rb_tree::__delete_case3(struct rb_node* n){
    struct rb_node* s = __sibling(n);
    if ((n->parent->color == RB_BLACK) &&
    (s->color == RB_BLACK) &&
    (s->left==NULL||s->left->color == RB_BLACK) &&
    (s->right==NULL||s->right->color == RB_BLACK)) {
        s->color = RB_RED;
        __delete_case1(n->parent);
    } else
    __delete_case4(n);
}

void rb_tree::__delete_case4(struct rb_node* n){
    struct rb_node* s = __sibling(n);
    if ((n->parent->color == RB_RED) &&
    (s->color == RB_BLACK) &&
    (s->left==NULL||s->left->color == RB_BLACK) &&
    (s->right==NULL||s->right->color == RB_BLACK)) {
            s->color = RB_RED;
            n->parent->color = RB_BLACK;
    } else
    __delete_case5(n);
}

void rb_tree::__delete_case5(struct rb_node* n){
    struct rb_node* s = __sibling(n);
    if (s->color == RB_BLACK) {/* this if statement is trivial,
        due to Case 2 (even though Case two changed the sibling to a sibling's child,
        the sibling's child can't be red, since no red parent can have a red child). */
        // the following statements just force the red to be on the left of the left of the parent,
        // or right of the right, so case six will rotate correctly.
        if ((n == n->parent->left) &&
        (s->right->color == RB_BLACK) &&
        (s->left->color == RB_RED)) { // this last test is trivial too due to cases 2-4.
            s->color = RB_RED;
            s->left->color = RB_BLACK;
            __rotate_right(s);
            } else if ((n == n->parent->right) &&
            (s->left->color == RB_BLACK) &&
            (s->right->color == RB_RED)) {// this last test is trivial too due to cases 2-4.
                s->color = RB_RED;
                s->right->color = RB_BLACK;
                __rotate_left(s);
            }
    }
    __delete_case6(n);
}

void rb_tree::__delete_case6(struct rb_node* n){
    struct rb_node* s = __sibling(n);
    s->color = n->parent->color;
    n->parent->color = RB_BLACK;
    if (n == n->parent->left) {
        s->right->color = RB_BLACK;
        __rotate_left(n->parent);
    } else {
        s->left->color = RB_BLACK;
        __rotate_right(n->parent);
    }
}
rb_node* rb_tree::rb_delete(void* key){
    //两边都不是叶子节点
    struct rb_node* min_node;
    struct rb_node* fnode=root;
    int ret=0;
    while(ret=__rb_cmpkey(fnode->key,key)){
         if(__is_leaf(fnode)){
           return NULL;
         }
         if(ret>0)
             fnode=fnode->right;
         else
             fnode=fnode->left;
    }
    if(fnode->right!=NULL){
          min_node=fnode->right;
          while(min_node->left!=NULL)
              min_node=min_node->left;
    }
    else if(fnode->left!=NULL){
        min_node=fnode->left;
        while(min_node->right!=NULL)
              min_node=min_node->right;
    }
    else{
        min_node=fnode;
    }
    
    __replace_node(fnode, min_node);
    //用非叶子节点替换要删除的节点
    if (fnode->color == RB_BLACK) {
        if (min_node->color == RB_RED)
            min_node->color = RB_BLACK;
        else
            __delete_case1(min_node);
    }
    if(!__is_leaf(min_node)){
       return NULL;
    }
    if(min_node==root)
        root==NULL;
    else if(min_node->parent->right==min_node)
        min_node->parent->right=NULL;
    else
        min_node->parent->left=NULL;
    pool->Free(min_node);
    return NULL;
}
复制代码
复制代码

 


 

复制代码

 

复制代码
 
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
打赏
0
0
0
0
77
分享
相关文章
【赵渝强老师】在Docker中运行达梦数据库
本文介绍了在Docker容器中部署达梦数据库(DM 8)的具体步骤,包括创建文件夹、下载安装包、导入镜像、启动容器、登录数据库及查看状态等操作。同时,通过视频讲解辅助理解。文中还分析了将数据库服务容器化的潜在问题,如数据安全性、硬件资源争用、网络带宽占用和额外隔离带来的挑战,指出数据库服务在生产环境中可能不适合容器化的原因。
【赵渝强老师】在Docker中运行达梦数据库
鸿蒙开发:console日志输出
针对初学者而言,大家只需要掌握住日志打印即可,等到了鸿蒙应用开发的时候,还有一个鸿蒙原生的打印工具HiLog,到时,我们也会详细的去讲述,也会针对HiLog,封装一个通用的工具类。
76 11
鸿蒙开发:console日志输出
Tauri 开发实践 — Tauri 日志记录功能开发
本文介绍了如何为 Tauri 应用配置日志记录。Tauri 是一个利用 Web 技术构建桌面应用的框架。文章详细说明了如何在 Rust 和 JavaScript 代码中设置和集成日志记录,并控制日志输出。通过添加 `log` crate 和 Tauri 日志插件,可以轻松实现多平台日志记录,包括控制台输出、Webview 控制台和日志文件。文章还展示了如何调整日志级别以优化输出内容。配置完成后,日志记录功能将显著提升开发体验和程序稳定性。
274 1
Tauri 开发实践 — Tauri 日志记录功能开发
MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!
《MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!》介绍了MySQL中的三种关键日志:二进制日志(Binary Log)、重做日志(Redo Log)和撤销日志(Undo Log)。这些日志确保了数据库的ACID特性,即原子性、一致性、隔离性和持久性。Redo Log记录数据页的物理修改,保证事务持久性;Undo Log记录事务的逆操作,支持回滚和多版本并发控制(MVCC)。文章还详细对比了InnoDB和MyISAM存储引擎在事务支持、锁定机制、并发性等方面的差异,强调了InnoDB在高并发和事务处理中的优势。通过这些机制,MySQL能够在事务执行、崩溃和恢复过程中保持
216 3
鸿蒙5.0版开发:使用HiLog打印日志(ArkTS)
在HarmonyOS 5.0中,HiLog是系统提供的日志系统,支持DEBUG、INFO、WARN、ERROR、FATAL五种日志级别。本文介绍如何在ArkTS中使用HiLog打印日志,并提供示例代码。通过合理使用HiLog,开发者可以更好地调试和监控应用。
438 16
前端的全栈之路Meteor篇(三):运行在浏览器端的NoSQL数据库副本-MiniMongo介绍及其前后端数据实时同步示例
MiniMongo 是 Meteor 框架中的客户端数据库组件,模拟了 MongoDB 的核心功能,允许前端开发者使用类似 MongoDB 的 API 进行数据操作。通过 Meteor 的数据同步机制,MiniMongo 与服务器端的 MongoDB 实现实时数据同步,确保数据一致性,支持发布/订阅模型和响应式数据源,适用于实时聊天、项目管理和协作工具等应用场景。
165 0
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
本文介绍了Java日志框架的基本概念和使用方法,重点讨论了SLF4J、Log4j、Logback和Log4j2之间的关系及其性能对比。SLF4J作为一个日志抽象层,允许开发者使用统一的日志接口,而Log4j、Logback和Log4j2则是具体的日志实现框架。Log4j2在性能上优于Logback,推荐在新项目中使用。文章还详细说明了如何在Spring Boot项目中配置Log4j2和Logback,以及如何使用Lombok简化日志记录。最后,提供了一些日志配置的最佳实践,包括滚动日志、统一日志格式和提高日志性能的方法。
1619 31
【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
什么是Apache日志?为什么Apache日志分析很重要?
Apache是全球广泛使用的Web服务器软件,支持超过30%的活跃网站。它通过接收和处理HTTP请求,与后端服务器通信,返回响应并记录日志,确保网页请求的快速准确处理。Apache日志分为访问日志和错误日志,对提升用户体验、保障安全及优化性能至关重要。EventLog Analyzer等工具可有效管理和分析这些日志,增强Web服务的安全性和可靠性。
123 9

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等