block结构示意图

sstable中Block 头文件如下:

  1. class Block {
  2. public:
  3. // Initialize the block with the specified contents.
  4. // Takes ownership of data[] and will delete[] it when done.
  5. Block(const char* data, size_t size);
  6.  
  7. ~Block();
  8.  
  9. size_t size() const { return size_; }
  10. Iterator* NewIterator(const Comparator* comparator);
  11.  
  12. private:
  13. uint32_t NumRestarts() const;
  14.  
  15. const char* data_;
  16. size_t size_;
  17. uint32_t restart_offset_; // Offset in data_ of restart array
  18.  
  19. // No copying allowed
  20. Block(const Block&);
  21. void operator=(const Block&);
  22.  
  23. class Iter;
  24. };

重启点在上个章节已经介绍过了

"“重启点”是干什么的呢?简单来说就是进行数据压缩,减少存储空间。我们一再强调,Block内容里的KV记录是按照Key大小有序的,这样的话,相邻的两条记录很可能Key部分存在重叠,比如key i=“the car”,Key i+1=“the color”,那么两者存在重叠部分“the c”,为了减少Key的存储量,Key i+1可以只存储和上一条Key不同的部分“olor”,两者的共同部分从Key i中可以获得。记录的Key在Block内容部分就是这么存储的,主要目的是减少存储开销。“重启点”的意思是:在这条记录开始,不再采取只记载不同的Key部分,而是重新记录所有的Key值,假设Key i+1是一个重启点,那么Key里面会完整存储“the color”,而不是采用简略的“olor”方式。但是如果记录条数比较多,随机访问一条记录,需要从头开始一直解析才行,这样也产生很大的开销,所以设置了多个重启点,Block尾部就是指出哪些记录是这些重启点的。 "

  1. //获取BLOCK中的重启点数目
  2. inline uint32_t Block::NumRestarts() const {
  3. assert(size_ >= *sizeof(uint32_t));
  4. return DecodeFixed32(data_ + size_ - sizeof(uint32_t));  //重启点在block最后8字节(uint32_t)中
    }

Block的创建和销毁

  1. Block::Block(const char* data, size_t size)
  2. : data_(data),
  3. size_(size) {
  4. if (size_ < sizeof(uint32_t)) {
  5. size_ = ; // Error marker
  6. } else {
  7. restart_offset_ = size_ - ( + NumRestarts()) * sizeof(uint32_t);  //重启点数目1个uint32 每个重启点的偏移记录 uint32 合记共(1+NumRestarts())* sizeof(uint32_t)
  8. if (restart_offset_ > size_ - sizeof(uint32_t)) {
  9. // The size is too small for NumRestarts() and therefore
  10. // restart_offset_ wrapped around.
  11. size_ = ;
  12. }
  13. }
  14. }
  15.  
  16. Block::~Block() {
  17. delete[] data_;
  18. }

Block中每个entry的解码

entry结构如上图的 KeyValuePair

  1. static inline const char* DecodeEntry(const char* p, const char* limit,
  2. uint32_t* shared,
  3. uint32_t* non_shared,
  4. uint32_t* value_length) {
  5. if (limit - p < ) return NULL; //至少包含3个 共享字节
  6. *shared = reinterpret_cast<const unsigned char*>(p)[];
  7. *non_shared = reinterpret_cast<const unsigned char*>(p)[];
  8. *value_length = reinterpret_cast<const unsigned char*>(p)[];
  9. if ((*shared | *non_shared | *value_length) < ) {
  10. // Fast path: all three values are encoded in one byte each
       //三个记录的值或操作后 均没有超过128 即最高位为0
  11. p += ;
  12. } else {
  13. if ((p = GetVarint32Ptr(p, limit, shared)) == NULL) return NULL;
  14. if ((p = GetVarint32Ptr(p, limit, non_shared)) == NULL) return NULL;
  15. if ((p = GetVarint32Ptr(p, limit, value_length)) == NULL) return NULL;
  16. }
  17.  
  18. if (static_cast<uint32_t>(limit - p) < (*non_shared + *value_length)) {
  19. return NULL;
  20. }
  21. return p;
  22. }

Block使用的迭代器

class Block::Iter : public Iterator

基本数据结构

  1. class Block::Iter : public Iterator {
  2. private:
  3. const Comparator* const comparator_;
  4. const char* const data_; // underlying block contents
  5. uint32_t const restarts_; // Offset of restart array (list of fixed32)
  6. uint32_t const num_restarts_; // Number of uint32_t entries in restart array
  7.  
  8. // current_ is offset in data_ of current entry. >= restarts_ if !Valid
  9. uint32_t current_;
  10. uint32_t restart_index_; // Index of restart block in which current_ falls
  11. std::string key_;
  12. Slice value_;
  13. Status status_;
  14.  
  15. inline int Compare(const Slice& a, const Slice& b) const {
  16. return comparator_->Compare(a, b);
  17. }
  18. }
  1. // Return the offset in data_ just past the end of the current entry.
  2. //下一个记录的起点就是当前记录的末尾偏移
  3. //当前记录加上记录的长度 和 BLOCK的起点的差 就是偏移
  4. inline uint32_t NextEntryOffset() const {
  5. return (value_.data() + value_.size()) - data_;
  6. }
  7.  
  8. uint32_t GetRestartPoint(uint32_t index) {
  9. //data_ + restarts_就是记录各个重启点偏移的数组
  10. //根据重启点index 计算偏移data_ + restarts_ ,里面就是第index个重启点的偏移
  11. assert(index < num_restarts_);
  12. return DecodeFixed32(data_ + restarts_ + index * sizeof(uint32_t));
  13. }
  14.  
  15. void SeekToRestartPoint(uint32_t index) {
  16. key_.clear();
  17. restart_index_ = index;
  18. // current_ will be fixed by ParseNextKey();
  19.  
  20. //value结束就是KEY的开始 所以使用value_记录
  21. uint32_t offset = GetRestartPoint(index);
  22. value_ = Slice(data_ + offset, );
  23. }
  1. bool ParseNextKey() {
  2. current_ = NextEntryOffset(); //获取下一个entry的偏移
  3. const char* p = data_ + current_;
  4. const char* limit = data_ + restarts_; // 所有BLOCK内数据不可能超过restart
  5. if (p >= limit) {
  6. // No more entries to return. Mark as invalid.
  7. current_ = restarts_;
  8. restart_index_ = num_restarts_;
  9. return false;
  10. }
  11.  
  12. // Decode next entry
  13. uint32_t shared, non_shared, value_length;
  14. //解析获取 key的共享字段长度 非共享字段长度和value的长度
  15. p = DecodeEntry(p, limit, &shared, &non_shared, &value_length);
  16. if (p == NULL || key_.size() < shared) {
  17. CorruptionError();
  18. return false;
  19. } else {
  20. key_.resize(shared); //key保存了其他entry的key 但是可以保留共享长度的字符串
  21. key_.append(p, non_shared); //再添加非共享长度的字符串 就是当前KEY内容
  22. value_ = Slice(p + non_shared, value_length); //value 就是略过key的偏移
  23. //编译restart点 确认restart点的偏移是离自己最近的 restart_index_< current_ < (restart_index_ + 1)
  24. while (restart_index_ + < num_restarts_ &&
  25. GetRestartPoint(restart_index_ + ) < current_) {
  26. ++restart_index_;
  27. }
  28. return true;
  29. }
  30. }
  31. };

参考:

https://www.cnblogs.com/itdef/p/9789620.html

leveldb 学习记录(六)SSTable:Block操作的更多相关文章

  1. leveldb 学习记录(五)SSTable格式介绍

    本节主要记录SSTable的结构 为下一步代码阅读打好基础,考虑到已经有大量优秀博客解析透彻 就不再编写了 这里推荐 https://blog.csdn.net/tankles/article/det ...

  2. leveldb 学习记录(七) SSTable构造

    使用TableBuilder构造一个Table struct TableBuilder::Rep { // TableBuilder内部使用的结构,记录当前的一些状态等 Options options ...

  3. leveldb 学习记录(四)Log文件

    前文记录 leveldb 学习记录(一) skiplistleveldb 学习记录(二) Sliceleveldb 学习记录(三) MemTable 与 Immutable Memtablelevel ...

  4. leveldb 学习记录(四) skiplist补与变长数字

    在leveldb 学习记录(一) skiplist 已经将skiplist的插入 查找等操作流程用图示说明 这里在介绍 下skiplist的代码 里面有几个模块 template<typenam ...

  5. leveldb 学习记录(三) MemTable 与 Immutable Memtable

    前文: leveldb 学习记录(一) skiplist leveldb 学习记录(二) Slice 存储格式: leveldb数据在内存中以 Memtable存储(核心结构是skiplist 已介绍 ...

  6. MyBatis学习 之 六、insert操作返回主键

       数据库操作怎能少了INSERT操作呢?下面记录MyBatis关于INSERT操作的笔记,以便日后查阅. 二. insert元素 属性详解   其属性如下: parameterType ,入参的全 ...

  7. 实验楼Python学习记录_挑战字符串操作

    自我学习记录 Python3 挑战实验 -- 字符串操作 目标 在/home/shiyanlou/Code创建一个 名为 FindDigits.py 的Python 脚本,请读取一串字符串并且把其中所 ...

  8. leveldb 学习记录(八) compact

    随着运行时间的增加,memtable会慢慢 转化成 sstable. sstable会越来越多 我们就需要进行整合 compact 代码会在写入查询key值 db写入时等多出位置调用MaybeSche ...

  9. ElasticSearch 学习记录之ES如何操作Lucene段

    近实时搜索 提交(Commiting)一个新的段到磁盘需要一个 fsync 来确保段被物理性地写入磁盘,这样在断电的时候就不会丢失数据.但是每次提交的一个新的段都fsync 这样操作代价过大.可以使用 ...

随机推荐

  1. Kubernetes Kubelet安全认证连接Apiserver

    Kubelet使用安全认证连接Apiserver,可以用Token或证书连接.配置步骤如下. 1,生成Token命令 head -c /dev/urandom | od -An -t x | tr - ...

  2. KPPW2.5 漏洞利用--CSRF

    kppw2.5 CSRF漏洞复现 漏洞说明 http://192.168.50.157/kppw25/index.php?do=user&view=message&op=send 收件 ...

  3. CodeSmith和Powerdesigner的搭建和实例化操作 转载自黄聪同学

    好了,废话少说,开始我们的CodeSmith旅程吧,我先讲讲这个系列教程要完成的目标吧,众所周知,CodeSmith其中一个强大的功能就是依照模板生成批量代码,这也是吸引着众多编程人士使用它的原因,它 ...

  4. ORM对象关系映射

    ORM 总结: ORM:对象关系映射 作用: 1.将定义数据库模型类--> 数据库表 2.将定义数据库模型类中的属性--->数据库表字段 3.将模型对象的操作(add,delete,com ...

  5. python3基础: 元组tuple、 列表list、 字典dict、集合set。 迭代器、生成器

    一.元组: tuple Python 的元组与列表类似,不同之处在于元组的元素不能修改. 元组中的元素值是不允许删除的,但我们可以使用del语句来删除整个元组 tup2 = (111, 22, 33, ...

  6. Halcon旋转图片的研究

    在Halcon中有两个用于图像旋转的函数: 1,rotate_image *Image和ImageRotate分别是输入和输出图像 *Phi是输入的旋转度数 *interpolation是内插方式,默 ...

  7. SpringCloud系列一:SpringCloud的简介和架构

    一.SpringCloud简介 SpringCloud就是一套分布式服务治理的框架,既然它是一套服务治理的框架,那么它本身不会提供具体功能性的操作,更专注于服务之间的通讯.熔断.监控等.因此就需要很多 ...

  8. 第二篇*1、Python基本数据类型

    数据类型: 变量可以处理不同类型的值,基本的类型是数和字符串.使用变量时只需要给它们赋一个值.不需要声明或定义数据类型.Python3 中有六个标准的数据类型:Number(数字),String(字符 ...

  9. MySQL统计信息以及执行计划预估方式初探

    数据库中的统计信息在不同(精确)程度上描述了表中数据的分布情况,执行计划通过统计信息获取符合查询条件的数据大小(行数),来指导执行计划的生成.在以Oracle和SQLServer为代表的商业数据库,和 ...

  10. linux下redis4.0.2集群部署(利用原生命令)

    一.部署架构如下 每台服务器准备2个节点,一主一从,主节点为另外两台其中一台的主,从节点为另外两台其中一台的从. 二.准备6个节点配置文件 在172.28.18.75上操作 cd /etc/redis ...