leveldb 学习记录(六)SSTable:Block操作
block结构示意图
sstable中Block 头文件如下:
- class Block {
- public:
- // Initialize the block with the specified contents.
- // Takes ownership of data[] and will delete[] it when done.
- Block(const char* data, size_t size);
- ~Block();
- size_t size() const { return size_; }
- Iterator* NewIterator(const Comparator* comparator);
- private:
- uint32_t NumRestarts() const;
- const char* data_;
- size_t size_;
- uint32_t restart_offset_; // Offset in data_ of restart array
- // No copying allowed
- Block(const Block&);
- void operator=(const Block&);
- class Iter;
- };
重启点在上个章节已经介绍过了
"“重启点”是干什么的呢?简单来说就是进行数据压缩,减少存储空间。我们一再强调,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尾部就是指出哪些记录是这些重启点的。 "
- //获取BLOCK中的重启点数目
- inline uint32_t Block::NumRestarts() const {
- assert(size_ >= *sizeof(uint32_t));
- return DecodeFixed32(data_ + size_ - sizeof(uint32_t)); //重启点在block最后8字节(uint32_t)中
}
Block的创建和销毁
- Block::Block(const char* data, size_t size)
- : data_(data),
- size_(size) {
- if (size_ < sizeof(uint32_t)) {
- size_ = ; // Error marker
- } else {
- restart_offset_ = size_ - ( + NumRestarts()) * sizeof(uint32_t); //重启点数目1个uint32 每个重启点的偏移记录 uint32 合记共(1+NumRestarts())* sizeof(uint32_t)
- if (restart_offset_ > size_ - sizeof(uint32_t)) {
- // The size is too small for NumRestarts() and therefore
- // restart_offset_ wrapped around.
- size_ = ;
- }
- }
- }
- Block::~Block() {
- delete[] data_;
- }
Block中每个entry的解码
entry结构如上图的 KeyValuePair
- static inline const char* DecodeEntry(const char* p, const char* limit,
- uint32_t* shared,
- uint32_t* non_shared,
- uint32_t* value_length) {
- if (limit - p < ) return NULL; //至少包含3个 共享字节
- *shared = reinterpret_cast<const unsigned char*>(p)[];
- *non_shared = reinterpret_cast<const unsigned char*>(p)[];
- *value_length = reinterpret_cast<const unsigned char*>(p)[];
- if ((*shared | *non_shared | *value_length) < ) {
- // Fast path: all three values are encoded in one byte each
//三个记录的值或操作后 均没有超过128 即最高位为0- p += ;
- } else {
- if ((p = GetVarint32Ptr(p, limit, shared)) == NULL) return NULL;
- if ((p = GetVarint32Ptr(p, limit, non_shared)) == NULL) return NULL;
- if ((p = GetVarint32Ptr(p, limit, value_length)) == NULL) return NULL;
- }
- if (static_cast<uint32_t>(limit - p) < (*non_shared + *value_length)) {
- return NULL;
- }
- return p;
- }
Block使用的迭代器
class Block::Iter : public Iterator
基本数据结构
- class Block::Iter : public Iterator {
- private:
- const Comparator* const comparator_;
- const char* const data_; // underlying block contents
- uint32_t const restarts_; // Offset of restart array (list of fixed32)
- uint32_t const num_restarts_; // Number of uint32_t entries in restart array
- // current_ is offset in data_ of current entry. >= restarts_ if !Valid
- uint32_t current_;
- uint32_t restart_index_; // Index of restart block in which current_ falls
- std::string key_;
- Slice value_;
- Status status_;
- inline int Compare(const Slice& a, const Slice& b) const {
- return comparator_->Compare(a, b);
- }
- }
- // Return the offset in data_ just past the end of the current entry.
- //下一个记录的起点就是当前记录的末尾偏移
- //当前记录加上记录的长度 和 BLOCK的起点的差 就是偏移
- inline uint32_t NextEntryOffset() const {
- return (value_.data() + value_.size()) - data_;
- }
- uint32_t GetRestartPoint(uint32_t index) {
- //data_ + restarts_就是记录各个重启点偏移的数组
- //根据重启点index 计算偏移data_ + restarts_ ,里面就是第index个重启点的偏移
- assert(index < num_restarts_);
- return DecodeFixed32(data_ + restarts_ + index * sizeof(uint32_t));
- }
- void SeekToRestartPoint(uint32_t index) {
- key_.clear();
- restart_index_ = index;
- // current_ will be fixed by ParseNextKey();
- //value结束就是KEY的开始 所以使用value_记录
- uint32_t offset = GetRestartPoint(index);
- value_ = Slice(data_ + offset, );
- }
- bool ParseNextKey() {
- current_ = NextEntryOffset(); //获取下一个entry的偏移
- const char* p = data_ + current_;
- const char* limit = data_ + restarts_; // 所有BLOCK内数据不可能超过restart
- if (p >= limit) {
- // No more entries to return. Mark as invalid.
- current_ = restarts_;
- restart_index_ = num_restarts_;
- return false;
- }
- // Decode next entry
- uint32_t shared, non_shared, value_length;
- //解析获取 key的共享字段长度 非共享字段长度和value的长度
- p = DecodeEntry(p, limit, &shared, &non_shared, &value_length);
- if (p == NULL || key_.size() < shared) {
- CorruptionError();
- return false;
- } else {
- key_.resize(shared); //key保存了其他entry的key 但是可以保留共享长度的字符串
- key_.append(p, non_shared); //再添加非共享长度的字符串 就是当前KEY内容
- value_ = Slice(p + non_shared, value_length); //value 就是略过key的偏移
- //编译restart点 确认restart点的偏移是离自己最近的 restart_index_< current_ < (restart_index_ + 1)
- while (restart_index_ + < num_restarts_ &&
- GetRestartPoint(restart_index_ + ) < current_) {
- ++restart_index_;
- }
- return true;
- }
- }
- };
参考:
https://www.cnblogs.com/itdef/p/9789620.html
leveldb 学习记录(六)SSTable:Block操作的更多相关文章
- leveldb 学习记录(五)SSTable格式介绍
本节主要记录SSTable的结构 为下一步代码阅读打好基础,考虑到已经有大量优秀博客解析透彻 就不再编写了 这里推荐 https://blog.csdn.net/tankles/article/det ...
- leveldb 学习记录(七) SSTable构造
使用TableBuilder构造一个Table struct TableBuilder::Rep { // TableBuilder内部使用的结构,记录当前的一些状态等 Options options ...
- leveldb 学习记录(四)Log文件
前文记录 leveldb 学习记录(一) skiplistleveldb 学习记录(二) Sliceleveldb 学习记录(三) MemTable 与 Immutable Memtablelevel ...
- leveldb 学习记录(四) skiplist补与变长数字
在leveldb 学习记录(一) skiplist 已经将skiplist的插入 查找等操作流程用图示说明 这里在介绍 下skiplist的代码 里面有几个模块 template<typenam ...
- leveldb 学习记录(三) MemTable 与 Immutable Memtable
前文: leveldb 学习记录(一) skiplist leveldb 学习记录(二) Slice 存储格式: leveldb数据在内存中以 Memtable存储(核心结构是skiplist 已介绍 ...
- MyBatis学习 之 六、insert操作返回主键
数据库操作怎能少了INSERT操作呢?下面记录MyBatis关于INSERT操作的笔记,以便日后查阅. 二. insert元素 属性详解 其属性如下: parameterType ,入参的全 ...
- 实验楼Python学习记录_挑战字符串操作
自我学习记录 Python3 挑战实验 -- 字符串操作 目标 在/home/shiyanlou/Code创建一个 名为 FindDigits.py 的Python 脚本,请读取一串字符串并且把其中所 ...
- leveldb 学习记录(八) compact
随着运行时间的增加,memtable会慢慢 转化成 sstable. sstable会越来越多 我们就需要进行整合 compact 代码会在写入查询key值 db写入时等多出位置调用MaybeSche ...
- ElasticSearch 学习记录之ES如何操作Lucene段
近实时搜索 提交(Commiting)一个新的段到磁盘需要一个 fsync 来确保段被物理性地写入磁盘,这样在断电的时候就不会丢失数据.但是每次提交的一个新的段都fsync 这样操作代价过大.可以使用 ...
随机推荐
- Kubernetes Kubelet安全认证连接Apiserver
Kubelet使用安全认证连接Apiserver,可以用Token或证书连接.配置步骤如下. 1,生成Token命令 head -c /dev/urandom | od -An -t x | tr - ...
- KPPW2.5 漏洞利用--CSRF
kppw2.5 CSRF漏洞复现 漏洞说明 http://192.168.50.157/kppw25/index.php?do=user&view=message&op=send 收件 ...
- CodeSmith和Powerdesigner的搭建和实例化操作 转载自黄聪同学
好了,废话少说,开始我们的CodeSmith旅程吧,我先讲讲这个系列教程要完成的目标吧,众所周知,CodeSmith其中一个强大的功能就是依照模板生成批量代码,这也是吸引着众多编程人士使用它的原因,它 ...
- ORM对象关系映射
ORM 总结: ORM:对象关系映射 作用: 1.将定义数据库模型类--> 数据库表 2.将定义数据库模型类中的属性--->数据库表字段 3.将模型对象的操作(add,delete,com ...
- python3基础: 元组tuple、 列表list、 字典dict、集合set。 迭代器、生成器
一.元组: tuple Python 的元组与列表类似,不同之处在于元组的元素不能修改. 元组中的元素值是不允许删除的,但我们可以使用del语句来删除整个元组 tup2 = (111, 22, 33, ...
- Halcon旋转图片的研究
在Halcon中有两个用于图像旋转的函数: 1,rotate_image *Image和ImageRotate分别是输入和输出图像 *Phi是输入的旋转度数 *interpolation是内插方式,默 ...
- SpringCloud系列一:SpringCloud的简介和架构
一.SpringCloud简介 SpringCloud就是一套分布式服务治理的框架,既然它是一套服务治理的框架,那么它本身不会提供具体功能性的操作,更专注于服务之间的通讯.熔断.监控等.因此就需要很多 ...
- 第二篇*1、Python基本数据类型
数据类型: 变量可以处理不同类型的值,基本的类型是数和字符串.使用变量时只需要给它们赋一个值.不需要声明或定义数据类型.Python3 中有六个标准的数据类型:Number(数字),String(字符 ...
- MySQL统计信息以及执行计划预估方式初探
数据库中的统计信息在不同(精确)程度上描述了表中数据的分布情况,执行计划通过统计信息获取符合查询条件的数据大小(行数),来指导执行计划的生成.在以Oracle和SQLServer为代表的商业数据库,和 ...
- linux下redis4.0.2集群部署(利用原生命令)
一.部署架构如下 每台服务器准备2个节点,一主一从,主节点为另外两台其中一台的主,从节点为另外两台其中一台的从. 二.准备6个节点配置文件 在172.28.18.75上操作 cd /etc/redis ...