LevelDB源码分析-编码】的更多相关文章

编码(util/coding.h util/coding.cc) LevelDB将整型编码为二进制字符串的形式,同时又能够和ASCII字符区分. 首先是定长编码: void EncodeFixed32(char *buf, uint32_t value) { if (port::kLittleEndian) { memcpy(buf, &value, sizeof(value)); } else { buf[0] = value & 0xff; buf[1] = (value >&g…
从[leveldb源码分析--插入删除流程]和WriteBatch其名我们就很轻易的知道,这个是leveldb内部的一个批量写的结构,在leveldb为了提高插入和删除的效率,在其插入过程中都采用了批量集合相邻的多个具有相同同步设置的写请求以批量的方式进行写入. 其成员变量仅包含了一个  std::string 类型的 rep_变量,其Put和Delete(其实也是插入删除操作,而非删除Put进去的数据,或者你可以将其理解为Put Delete operation的过度简写)都将相应的操作Enc…
[注]本文参考了sparkliang的专栏的Leveldb源码分析--3并进行了一定的重组和排版 经过上一篇文章的分析我们队leveldb的插入流程有了一定的认识,而该文设计最多的又是Batch的概念.这篇文章本来应该顺理成章的介绍Batch相关流程和结构了,但是Batch涉及到了一些编码和Key相关的概念,所以我觉得应该先理清这方面的概念有助于大家更容易理解后面的内容. 在dbformat.h/cc文件中我们首先看到的是 typedef uint64_t SequenceNumber; str…
在SSTable中主要存储数据的地方是data block,block_builder就是这个专门进行block的组织的地方,我们来详细看看其中的内容,其主要有Add,Finish和CurrentSizeEstimate三个函数.Finish的逻辑十分简单就是简单的将restart点信息和restart点个数分别以PutFixed32的格式写入数据最后:CurrentSizeEstimate则是简单的计算当前块需要的存储大小 = 已插入的KV对的大小 + 重启点个数 * 4 + 1 * 4(重启…
coming from http://blog.csdn.net/sparkliang/article/details/8567602 [前言:看了一点oceanbase,没有意志力继续坚持下去了,暂时就此中断,基本上算把master看完了,比较重要的update server和merge server代码却没有细看.中间又陆续研究了hadoop的源码,主要是name node和写入pipeline.主要的目的是想看看name node对namespace的管理,以及hadoop在写入操作时,c…
本篇关键词:指令格式.条件域.类型域.操作域.数据指令.访存指令.跳转指令.SVC(软件中断) 内核汇编相关篇为: v74.01 鸿蒙内核源码分析(编码方式) | 机器指令是如何编码的 v75.03 鸿蒙内核源码分析(汇编基础) | CPU上班也要打卡 v76.04 鸿蒙内核源码分析(汇编传参) | 如何传递复杂的参数 v77.01 鸿蒙内核源码分析(可变参数) | 正在制作中 ... v78.01 鸿蒙内核源码分析(开机启动) | 正在制作中 ... v79.01 鸿蒙内核源码分析(进程切换)…
我们知道在一个数据库系统中为了保证数据的可靠性,我们都会记录对系统的操作日志.日志的功能就是用来在系统down掉的时候对数据进行恢复,所以日志系统对一个要求可靠性的存储系统是极其重要的.接下来我们分析leveldb的日志,首先在leveldb源码目录中有doc/log_format.txt,这个文件详细的描述了leveldb的日志格式: record := checksum: uint32 // crc32c of type and data[] ; little-endian length:…
转自:http://luodw.cc/2015/10/15/leveldb-02/ leveldb和redis这样的优秀开源框架都没有使用C++自带的字符串string,redis自己写了个sds,leveldb写了slice,本质上这三个实现原理都是一样的(当然sds是用C实现的),都有成员属性指向字符串的指针和这个字符串的长度.方法无非就是取字符串取字符串长度,字符串拼接等等. 我把slice作为leveldb源码部分的第一个讲解,主要是slice是这个源码最基础的部分,都是别人使用它,它不…
本打算接下来分析version相关的概念,但是在准备的过程中看到了VersionSet的table_cache_这个变量才想起还有这样一个模块尚未分析,经过权衡觉得leveldb的version相对Cache来说相对复杂,而且version虽然对整个leveldb来说实现上跟其他功能十分紧密,但是从概念上来说却相对弱很多,有点感觉是附加的功能的感觉.所以从介绍系统首先应该注意的是整个系统概念的完整性的角度说还是先分析Cache相关的功能. 我们先来看Cache的基本框架结构数据: struct…
上一篇文章讲述了SSTable的格式以后,本文结合源码解析SSTable是如何生成的. void TableBuilder::Add(const Slice& key, const Slice& value) { //如果已经插入过数据,那么要保证当前插入的key > 之前最后一次插入的key, // SSTable必须是有序的插入数据 ) { assert(r->options.comparator->Compare(key, Slice(r->last_key)…
转自:http://luodw.cc/2015/10/15/leveldb-04/ 这篇博客主要讲解下leveldb内存池,内存池很多地方都有用到,像linux内核也有个内存池.内存池的存在主要就是减少malloc或者new调用的次数,较少内存分配所带来的系统开销. Arena类采用vector来存储每次分配内存的指针,每一次分配的内存,我们称为一个块block.block默认大小为4096kb.我们可以先看下Arena的模型: 我们来看看源码: 首先看下这个类的几个成员变量: 1 2 3 4…
TableBuilder生成sstable(include/table_builder.h table/table_builder.cc) LevelDB使用TableBuilder来构建sstable,并基于TableBuilder封装了一个BuildTable接口,用于将memtable转换为sstable. sstable的格式为: datablock1 | datablock2 | ... | metablock1 | metablock2 | ... | metaindexblock…
sstable中的Block(table/block.h table/block.cc table/block_builder.h table/block_builder.cc) sstable中的block由Block类封装并由BlockBuilder类构建. block的结构为: entry1 | entry2 | ... | restarts(uint32 * num_of_restarts) | num_of_restarts(uint32) | trailer 其中entry格式为:…
先来看看Leveldb的基本框架,几大关键组件,如图1-1所示. Leveldb是一种基于operation log的文件系统,是Log-Structured-Merge Tree的典型实现.LSM源自Ousterhout和Rosenblum在1991年发表的经典论文<The Design and Implementation of a Log-Structured File System>. 由于采用了op log,它就可以把随机的磁盘写操作,变成了对op log的append操作,因此提高…
由于网络上对leveldb的分析文章都比较丰富,一些基础概念和模型都介绍得比较多,所以本人就不再对这些概念以专门的篇幅进行介绍,本文主要以代码流程注释的方式. 首先我们从db的插入和删除开始以对整个体系有一个感性的认识,首先看插入: Status DB::Put(const WriteOptions& opt, const Slice& key, const Slice& value) { WriteBatch batch; //leveldb中不管单个插入还是多个插入都是以Wri…
对于compaction是leveldb中体量最大的一部分,也应该是最为复杂的部分,为了便于理解我们首先从一些基本的概念开始.下面是一些从doc/impl.html中翻译和整理的内容: Level 0 当日志文件超过一定大小的阈值是 (默认为 1MB): 建立一个新的memtable和日志文件,以后的操作都是用新的memtable和日志文件 后台进行如下操作: 将旧的 memtable写到SSTable中(过程为先转为immtable_table,然后遍历写入) 废弃旧的 memtable 删除…
leveldb作为一个KV存储引擎将数据持久化到磁盘,而对于一个存储引擎来说在存储过程中因为一些其他原因导致程序down掉甚至数据文件被破坏等都会导致程序不能按正常流程再次启动.那么遇到这些状况以后如何使程序最大程度的恢复数据就是非常重要的一项工作,leveldb也提供了这方面的工作. 首先来看recover,这是每一次启动数据库的时候都会呗调用到的流程.其功能是恢复数据库在运行中突然因为某些原因down掉而这个时候leveldb中的丢失的当前状态,以及memtable甚至immtable中还未…
Version VersionSet类 VersionSet管理整个LevelDB的当前状态: class VersionSet { public: // ... // Apply *edit to the current version to form a new descriptor that // is both saved to persistent state and installed as the new // current version. Will release *mu w…
Bloom Filter bloom filter是leveldb中用来在一个block中检测key是否存在的工具,主要在BloomFilterPolicy类中实现: class BloomFilterPolicy : public FilterPolicy { private: size_t bits_per_key_; size_t k_; public: explicit BloomFilterPolicy(int bits_per_key) : bits_per_key_(bits_pe…
Write LevelDB提供了write和put两个接口进行插入操作,但是put实际上是调用write实现的,所以我在这里只分析write函数: Status DBImpl::Write(const WriteOptions &options, WriteBatch *my_batch) 首先初始化一个Writer对象,Writer对象用于封装一个插入操作,LevelDB用一个deque来管理Writer对象,新建的Writer对象被插入到这个deque的尾部,如果Writer对象未被处理且不…
Get LevelDB提供了Get接口用于给定key的查找: Status DBImpl::Get(const ReadOptions &options, const Slice &key, std::string *value) Get操作可以指定在某个snapshot的情况下进行,如果指定了snapshot,则获取该snapshot的sequencenumber,如果没有指定snapshot,就取当前最新的sequencenumber: Status s; MutexLock l(&a…
MemTable(db/memtable.h db/memtable.cc db/skiplist.h) LevelDB中存储在内存中的那部分KV数据都存储在memtable中,而memtable中的数据实际是用跳表来存储的.MemTable使用Arena进行内存管理,并提供了添加.查找.迭代器的接口,而实际上这些接口都是调用SkipList的添加和迭代器接口来实现的. MemTable类 MemTable类的声明: class MemTable { public: // ... // Incr…
bloomfilter是leveldb中的一大性能利器,所以为了文章的表现完整性这里新启这么一篇文章.leveldb中的bloomfilter的实现在bloom.cc中,是一个较为简单的实现,所以就不再具体进行分析.本文列出两个参考地址: 那些优雅的数据结构(1) : BloomFilter——大规模数据处理利器 是一个简单的bloomfilter的介绍乐和实现 Bloom Filter  则是一位专业的bloomfilter的研究人士的博客,内容及其的牛逼,对此感兴趣的阅读以下其文章应该有不小…
SSTable是leveldb 的核心模块,这也是其称为leveldb的原因,leveldb正是通过将数据分为不同level的数据分为对应的不同的数据文件存储到磁盘之中的.为了理解其机制,我们首先看看SSTable中的基本概念. 首先看看数据的整体存储结构: 可以从图中看到了几个概念:Datablock,Metablock, MetaIndex block, Indexblock, Footer.具体他们的含义可以大致解释如下: 1. Datablock,我们知道文件中的k/v对是有序存储的,他…
既然leveldb是一个按Key序组织的LSM-Tree实现,那么对于Key的比较就是非常之重要了,这个Key的比较在leveldb中是Comparator的形式出现的.我们首先来看看Comparator的基本方法有哪些 // 实际的比较函数 ; // 名称,主要是为了防止建立和读取时使用了不同的Comparator ; //找出 [start, limit)之间的一个短的串,主要作用是降低一些存储空间 virtual void FindShortestSeparator( std::strin…
在DBImpl中有一个函数声明为Iterator* DBImpl::NewIterator(const ReadOptions& options) ,他返回一个可以遍历或者搜索数据库的迭代器句柄. Iterator* DBImpl::NewIterator(const ReadOptions& options) { SequenceNumber latest_snapshot; uint32_t seed; Iterator* iter = NewInternalIterator(opti…
我们先来参考来至使用Iterator简化代码2-TwoLevelIterator的例子,略微修改希望能帮助更加容易立即,如果有不理解请各位看客阅读原文. 下面我们再来看一个例子,我们为一个书店写程序,书店里有许多书Book,每个书架(BookShelf)上有多本书. 类结构如下所示 class Book { private: string book_name_; }; class Shelf { private: vector<Book> books_; }; 如何遍历书架上所有的书呢?一种实…
Open LevelDB的初始化主要由Open函数实现: Status DB::Open(const Options &options, const std::string &dbname, DB **dbptr) 首先,Open函数调用Recover函数将LevelDB的历史状态恢复: *dbptr = nullptr; DBImpl *impl = new DBImpl(options, dbname); impl->mutex_.Lock(); VersionEdit edit…
一.原理 arena是LevelDB内部实现的内存池. 我们知道,对于一个高性能的服务器端程序来说,内存的使用非常重要.C++提供了new/delete来管理内存的申请和释放,但是对于小对象来说,直接使用new/delete代价比较大,要付出额外的空间和时间,性价比不高.另外,我们也要避免多次的申请和释放引起的内存碎片.一旦碎片到达一定程度,即使剩余内存总量够用,但由于缺乏足够的连续空闲空间,导致内存不够用的假象.        C++ STL为了避免内存碎片,实现一个复杂的内存池,LevelD…
Compaction compact由背景线程完成,代码中触发背景线程的函数为: void DBImpl::MaybeScheduleCompaction() { mutex_.AssertHeld(); if (background_compaction_scheduled_) { // Already scheduled } else if (shutting_down_.Acquire_Load()) { // DB is being deleted; no more background…