leveldb源码分析--Comparator
既然leveldb是一个按Key序组织的LSM-Tree实现,那么对于Key的比较就是非常之重要了,这个Key的比较在leveldb中是Comparator的形式出现的。我们首先来看看Comparator的基本方法有哪些
// 实际的比较函数
virtual int Compare(const Slice& a, const Slice& b) const = ; // 名称,主要是为了防止建立和读取时使用了不同的Comparator
virtual const char* Name() const = ; //找出 [start, limit)之间的一个短的串,主要作用是降低一些存储空间
virtual void FindShortestSeparator(
std::string* start,
const Slice& limit) const = ; //作用类似,但无上端限制
virtual void FindShortSuccessor(std::string* key) const = ;
在leveldb中已经实现的类有两个,一个是内置的BytewiseComparatorImpl,另一个是InternalKeyComparator。我们首先来分析BytewiseComparatorImpl的实现,实现十分简单,我们这里只对实现的功能用注释的方式进行说明
// Bytewise直接调用Slice的Compare,按memcmp的方式进行比较,然后再比较长短
int Compare(const Slice& a, const Slice& b)
//对start和limit的公共部分外的start中的可以uint8方式+1的字节+1,清除该位之后的数据
void FindShortestSeparator(std::string* start, const Slice& limit)//直接对key中第一个可以uint8方式+1的字节+1,清除该位后面的数据
void FindShortSuccessor(std::string* key)
我们分析InternalKeyComparator的内部实现,看其成员变量其包含了一个Comparator类型的user_comparator_,其比较都用到了这个成员变量的方法,这个类的实现是在使用这些方法的过程中加入了一些解码的过程。根据其解码过程和名字我们可以看出这个比较器是用来比较传入为InternalKey对象,我们知道其组成为
user_key (string) | sequence ( byte) | value_type ( byte)
对于InternalKeyComparator的三个函数的具体实现说明为
// 传入的值解码得到user_key后对user_key进行比较
int Compare(const Slice& a, const Slice& b)
//解码后对user_key FindShortestSeparator,然后再最后加入kMaxSequenceNumber|kValueTypeForSeek
void FindShortestSeparator(std::string* start, const Slice& limit)//将key的第一个可以+1的字节+1,然后加上kMaxSequenceNumber|kValueTypeForSeek
void FindShortSuccessor(std::string* key)
我们再来看看MemTable关于Table 的定义
typedef SkipList<const char*, KeyComparator> Table;
Table table_; 而 KeyComparator的定义为:
struct KeyComparator {
const InternalKeyComparator comparator;
explicit KeyComparator(const InternalKeyComparator& c) : comparator(c) { }
int operator()(const char* a, const char* b) const;
};
由此可知KeyComparator是一个引用了InternalKeyComparator作为成员变量的结构体,而InternalKeyComparator又引用了一个 Comparator类型的user_comparator_。理清了了这些所谓的Comparator的引用层次关系以后,我们来看看leveldb中定义SkipList是使用的哪个Comparator。首先看MemTable的构造函数
MemTable::MemTable(const InternalKeyComparator& cmp)
: comparator_(cmp),
refs_(),
table_(comparator_, &arena_) {
}
可以看到构造函数接收一个InternalKeyComparator类型的参数,然后构建内部的KeyComparator,然后在将其传递给SkipList 的table_,而通过查找我们看到其构造是在DBImpl的构造函数中被调用的,看代码
DBImpl::DBImpl(const Options& raw_options, const std::string& dbname)
: env_(raw_options.env),
internal_comparator_(raw_options.comparator),
......
mem_(new MemTable(
internal_comparator
_)),
再继续往下找到有如下代码
Status DB::Open(const Options& options, const std::string& dbname,
DB** dbptr) {
DBImpl* impl = new DBImpl(options, dbname);
......
}
所以我们可以得出结论是最终的SkipList中使用的Comparator就是在Open数据库的时候传入的参数Option中的成员变量comparator,所以我们在实现自己的Comparator的时候只有仿照BytewiseComparatorImpl实现一个,然后通过option的方式传递给leveldb即可。
最后我们整理一下思路:
1. SkipList中使用的KeyComparator仅仅是对InternalKeyComparator的一个包含式的封装;
2. 而InternalKeyComparator是对key的简单编解码后使用option中传入的Comparator,默认为BytewiseComparatorImpl
InternalKeyComparator中的编解码是user_key和InternalKey之间的转换,所以最终的顺序(大小)的比较其实都是user_key(Put,Get,Delete传入的Key值)根据option中的Comparator(默认为BytewiseComparatorImpl)进行compare得出顺序。
理清这个顺序以后对leveldb中的各个Comparator就比较容易理解了。
leveldb源码分析--Comparator的更多相关文章
- leveldb源码分析--Key结构
[注]本文参考了sparkliang的专栏的Leveldb源码分析--3并进行了一定的重组和排版 经过上一篇文章的分析我们队leveldb的插入流程有了一定的认识,而该文设计最多的又是Batch的概念 ...
- leveldb源码分析--SSTable之block
在SSTable中主要存储数据的地方是data block,block_builder就是这个专门进行block的组织的地方,我们来详细看看其中的内容,其主要有Add,Finish和CurrentSi ...
- leveldb源码分析--WriteBatch
从[leveldb源码分析--插入删除流程]和WriteBatch其名我们就很轻易的知道,这个是leveldb内部的一个批量写的结构,在leveldb为了提高插入和删除的效率,在其插入过程中都采用了批 ...
- Leveldb源码分析--1
coming from http://blog.csdn.net/sparkliang/article/details/8567602 [前言:看了一点oceanbase,没有意志力继续坚持下去了,暂 ...
- leveldb源码分析--日志
我们知道在一个数据库系统中为了保证数据的可靠性,我们都会记录对系统的操作日志.日志的功能就是用来在系统down掉的时候对数据进行恢复,所以日志系统对一个要求可靠性的存储系统是极其重要的.接下来我们分析 ...
- leveldb源码分析之Slice
转自:http://luodw.cc/2015/10/15/leveldb-02/ leveldb和redis这样的优秀开源框架都没有使用C++自带的字符串string,redis自己写了个sds,l ...
- LevelDB源码分析--Cache及Get查找流程
本打算接下来分析version相关的概念,但是在准备的过程中看到了VersionSet的table_cache_这个变量才想起还有这样一个模块尚未分析,经过权衡觉得leveldb的version相对C ...
- leveldb源码分析--SSTable之TableBuilder
上一篇文章讲述了SSTable的格式以后,本文结合源码解析SSTable是如何生成的. void TableBuilder::Add(const Slice& key, const Slice ...
- leveldb源码分析之内存池Arena
转自:http://luodw.cc/2015/10/15/leveldb-04/ 这篇博客主要讲解下leveldb内存池,内存池很多地方都有用到,像linux内核也有个内存池.内存池的存在主要就是减 ...
随机推荐
- Nginx实现tomcat集群进行负载均衡
一.背景 随着业务量和用户数量的激增,单一的tomcat部署应用已经无法满足性能需求,而且对于每次发布项目期间服务不可用的问题也凸显,既然出现了这个问题,那么我们本文就借助nginx来完美的解决这个问 ...
- print默认在末尾添加一个换行符,但其实也可以不用!
白月黑羽今天给大家分享另外一个冷知识:) python中 print函数打印信息时默认添加一个换行符,所以你看到一条print语句,则单独占一行,那是否可以不要换行符呢? 答案是肯定的,当然可以,可用 ...
- C#基础篇二变量与变量类型
说到数据类型,先把基本的数据类型拿出来 byte 0 到 255 无符号 8 位整数sbyte -128 到 127 有符号 8 位整数short -32,768 到 32,767 有符号 16 位整 ...
- linux(centos6.8 64位)下安装mysql5.7(yum方式)
下载mysql源安装包 # wget http:.noarch.rpm 安装mysql源包 #yum localinstall mysql57.noarch.rpm 检查mysql源是否安装成功 # ...
- tensorflow 优化图
当我们把训练好的tensorflow训练图拿来进行预测时,会有多个训练时生成的节点,这些节点是不必要的,我们需要在预测的时候进行删除. 下面以bert的图为例,进行优化 def optimize_gr ...
- JavaScript中十种一步拷贝数组的方法
JavaScript中我们经常会遇到拷贝数组的场景,但是都有哪些方式能够来实现呢,我们不妨来梳理一下. 1.扩展运算符(浅拷贝) 自从ES6出现以来,这已经成为最流行的方法.它是一个很简单的语法,但是 ...
- MathType试用期到了如何继续用
1,卸载原来的MathType(不知道需不需要,其实删不删应该无所谓吧) 2,删除注册表中的一个值(不是默认,而是另外一个值) HKEY_CURRENT_USER\Software\Install O ...
- JSP 基础(二)
五 注释 5.1 JSP注释 <%--注释内容--%> 5.2 HTML注释 <!--注释内容--> 5.3 Java注释 六 JSP指令 在JSP中有三种类型 ...
- 程序员必知的8大排序(一)-------直接插入排序,希尔排序(java实现)
http://blog.csdn.net/pzhtpf/article/details/7559896 程序员必知的8大排序(一)-------直接插入排序,希尔排序(java实现) 程序员必知的8大 ...
- mongorestore 一次踩雷
1.在做mongodb备份后,研发突然有个需求说先看一下昨天备份里面的数据,进行一下核实.因为那部分数据今天已经删除,由于使用---gzip.--archive做的备份,所以必须导入到同名的数据库里面 ...