OceanBase分布式存储引擎公共模块——基础数据结构

OceanBase分布式存储引擎公共模块——基础数据结构

1.哈希表

为了提高随机读取性能,UpdateServer支持创建哈希索引,这个哈希索引结构就是LightlyHashMap,代码如下:

template <typename Key, typename Value>
class LightlyHashMap
{
public:
    //插入一个<key,value>对到哈希表
    inline int insert(const Key& key, const Value& value);
    //根据key查找value
    inline int get(const Key& key, const Value& value);
    //根据key删除一个<key,value>对,如果value不为空,那么,保存删除的值到value中
    inline int erase(const Key& key, Value& value = NULL);
private;
    struct  Node
    {
        Key key;
        Value value;
        union
        {
            Node* next;
            int64_t flag;
        };
    };
    Node* buckets_; //哈希桶指针
    BitLock bit_lock_;//位锁,用于保护哈希桶
};

LightlyHashMap采用链式冲突处理方法,即将所有哈希值相同的对链到同一哈希桶中,它包含如下三个方法:

  • insert:往哈希表中插入一个对。这个函数首先根据key 的哈希值得到桶号,接着,往哈希桶中插入一个包含key和value值的Node节点。
  • get:根据key查找value。这个函数首先根据key的哈希值得到桶号,接着,遍历对应的链表,找到与传入key相同的Node节点,返回其中的value值。
  • erase:根据key删除一个对。这个函数首先根据key的哈希值得到桶号,接着,遍历对应的链表,找到并删除与传入key相同的Node节点。

LightlyHashMap设计用来存储几千万甚至几亿个元素,它与普通哈希表的不同点在于以下两点:

  1. 位锁(BitLock):LightlyHashMap通过BitLock实现哈希值的锁结构,每个哈希桶的锁结构只需要占用一个位(Bit)。如果哈希桶对应的位锁值为0.表示没有锁冲突;否则,表现出锁冲突。需要注意的是,LightlyHashMap没有区分读锁和写锁,多个get请求也是冲突。可以对LightlyHashMap的BitLock做一些改进,例如用两个位(Bit)表示哈希桶对应的锁,其中一个位表示是否有读冲突,另外一个位表示是否有写冲突。
  2. 延迟初始化(Lazy Initialization):LightlyHashMap的哈希桶个数往往特别多(默认为1000万个),即使仅仅对所有哈希桶执行一次memset操作,消耗的时间也是相当可观的。因此,LightlyHashMap采用延迟初始化的策略,即将哈希桶划分为多个单元,默认情况下每个单元包含65536个哈希桶。每次执行insert、get或者erase操作时都会判断哈希桶所属的单元是否已经初始化,如果未初始化,则对该单元内的所有哈希桶执行初始化操作。

2.B树

UpdateServer的MemTable结构底层采用B树结构索引其中的数据,代码如下:

template<class K, class V, class Alloc>
class BTreeBase
{
public:
    //把,<key, value>对加到B树中,overwrite参数表示是否覆盖原有值
    int put(const K& key, const V& value, const bool overwrite = false);
    //获取key对应的value
    int get(const K& key, V& value);
    //获取扫描操作描述符
    int get_scan_handle(TScanHandle& handle);
    //设置扫描的数据范围
    int set_key_range(TScanHandle& handle, const K& start_key, int32_t start_exclude, const K& end_key, int32_t end_exclude);
    //读取下一行数据
    int get_next(TScanHandle& handle, K& key, V& value);
};

支持的功能如下:

  • Put:插入一个对。
  • Get:根据key获取对应的value。
  • Scan:扫描一段范围内的数据行。首先,调用get_scan_handle获取扫描操作描述符,其次,调用set_key_range设置扫描的数据范围,最后,不断地diao'yon调用get_next读取下一行数据直到全部读完。

为了提高读写并发能力,B树实现时采用写时复制(Copy-on-write)技术,修改每个索引节点时首先将该节点拷贝出来,接着在拷贝出来的节点上执行修改操作,最后在原子地修改其父节点的指针使其指向拷贝出来的节点。这种实现方式的好处在于修改操作不影响读取,读取操作永远不会被阻塞。

时间: 2024-11-30 17:36:49

OceanBase分布式存储引擎公共模块——基础数据结构的相关文章

OceanBase分布式存储引擎公共模块——内存管理

OceanBase分布式存储引擎公共模块--内存管理 内存管理是C++高性能服务器的核心问题.一些通用的内存管理库,比如Google TCMalloc,在内存申请/释放速度.小内存管理.所开销等方面都已经做得相当卓越了,然而,我们并没有采用.这是因为,通用内存管理库在性能上毕竟不如专用的内存池,更为严重的问题是,它鼓励了开发人员忽视内存管理的陋习,比如在服务器程序中滥用C++标准模板库(STL). 在分布式存储系统开发初期,内存相关的Bug相当常见,比如内存越界.服务器出现Core Comp,这

Flink内存管理源码解读之基础数据结构

在分布式实时计算领域,如何让框架/引擎足够高效地在内存中存取.处理海量数据是一个非常棘手的问题.在应对这一问题上Flink无疑是做得非常杰出的,Flink的自主内存管理设计也许比它自身的知名度更高一些.正好最近在研读Flink的源码,所以开两篇文章来谈谈Flink的内存管理设计. Flink的内存管理的亮点体现在作为以Java为主的(部分功能用Scala实现,也是一种遵循JVM规范并依赖JVM解释执行的函数式编程语言)的程序却自主实现内存的管理而不完全依赖于JVM的内存管理机制.它的优势在于灵活

介绍Amazon分布式存储引擎Dynamo

Dynamo 是 Amazon 公司的一个分布式存储引擎. 那么这个什么引擎又是什么?首先,假设一个场景,你的网站要存储用户登陆的IP.这个问题怎么解决呢?传统的方法是用数据库.数据库提供了方便的操作接口,复杂的查询能力以及事物的保证.好,现在假设大家都很喜欢你的网站,访问的人越来越多.一个数据库已经处理不过来了.于是你安装了3台数据库主机,把用户分成了三类(男人,女人,IT人;总是有某种方法把用户分成数目大致差不多的几个部分吧).每次访问的时候,先看用户属于哪一类,然后直接访问存储那类用户数据

《深入理解Nginx:模块开发与架构解析》一3.4 HTTP模块的数据结构

3.4 HTTP模块的数据结构 定义HTTP模块方式很简单,例如: ngx_module_t ngx_http_mytest_module; 其中,ngx_module_t 是一个Nginx模块的数据结构(详见8.2节).下面来分析一下Nginx模块中所有的成员,如下所示: typedef struct ngx_module_s ngx_module_t; struct ngx_module_s { /* 下面的ctx_index.index.spare0.spare1.spare2.spare

Redis源码学习——基础数据结构之SDS

Redis数据结构-SDS Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理. 首先介绍下Redis的基础数据结构 -- SDSRedis没有使用传统C语言的字符串(字符数组)表示.而是自己构建了一种名为sds(Simple Dymamic String)的抽象类型,作为redis的默认字符类型. SDS用于保存数据库中的字符串值,用户客户端的输入的缓冲区,AOF模块中的缓冲区都是由SDS实现的. SDS相比于C字符串的优点: 常数复杂度获取字符

DotNetNuke自定义窗体模块的数据结构(三)

在接触国外的CMS等Open Source产品之前,老实说,我写过的存储过程,包括SQL Server的.Oracle的,加起来绝对不会超过5个,而且还基本上都是从网上抄袭的,主要是觉得太麻烦:嗯,是的,如果数据库设计的不够好,经常需要改动,比如加一个字段,修改一下字段类型的话,需要从数据表.存储过程.调用等一路改上来,确实是挺麻烦的.不过习惯了之后,发现用存储过程确实有它的好处,也被迫养成了对数据库设计要每个字段都斟酌半天的习惯,所以,我们看到DotNetNuke有近乎上千个存储过程(安装了所

DotNetNuke自定义窗体模块的数据结构(一)

在讲我们自己的数据结构之前,我们还是先来分析一下DotNetNuke的UserDefinedTable这个模块的数据结构,我个人从这个模块中受益匪浅. 我们之前曾经说过,UserDefinedTable用三张表,就完成了支持无限字段的动态窗体的数据结构,这似乎已经是绝对不可能再精简的数据结构了(当然,还需要借助系统的Users表,来区分用户),这三张表是UserDefinedFields. UserDefinedRows和UserDefinedData这三张表,所有的用户数据,都存储在UserD

Oracle恢复内部原理:基础数据结构

基础数据结构 2.1  控制文件 控制文件包含了数据库中所有其他文件的状态信息. 控制文件包含了如下几类数据: A.      数据库信息记录(一条) B.      数据文件记录(每个数据文件一条) C.      线程记录(每个线程一条.注:每个实例一个线程) D.      日志文件记录(每个日志文件一条) E.       文件名记录(每个数据文件或者日志文件成员一条) F.       日志历史记录(每个已经完成的日志文件一条) 控制文件的被后面文档引用到的字段如下,后面是引用该字段的

模块抽取-Android公共模块的抽取

问题描述 Android公共模块的抽取 解决方案 你的右下那两个点击事件和fragment不是写在同一层?是的话只是判断点击事件,更换fragment就可以了