02. log WriteBatch 的结构和编码

news/2025/3/18 7:00:19/文章来源:https://www.cnblogs.com/lang77/p/18778131

在这样的情况之下,我就想来捋一下,这个代码的逻辑

首先从不同的模块说起吧

  • include/leveldb : 这里面存储了要暴露给外部的API,这里面的结构,从使用者来说会比较熟悉,就是通过这里面的结构,实现它的功能,对不同的组件会有一个直观的定义
  • db : 这里面是对应的实现的类,不仅实现了include/leveldb内部,并且还有很多大量相关的部分,但是没有被暴露的部分,从include入手有一个直观印象再慢慢深入db中相关的实现
  • util : 这个是相关的工具包,更通用,对以上的支持功能

然后我希望的是一种从上到下的解释吧

Include 接口

option.h 是对需要进行的操作,比如说 put或者delete 操作的的定义,在这里,我就只有一个 bool sync 指定这个操作是否是需要同步刷入磁盘中

slice.h 这个就是数据视图,就只有对应数据的指针和size

  • 为什么不直接用String?
    • 因为使用String进行传播,会出现多次的复制,降低性能
  • 减少复制为什么不使用&引用传递?
    • 因为引用传递并不能只指向String的一部分,而slice可以使用char* data_指向不同的地址和size_就可以灵活的指向数据的一部分
  • 因此slice因为其灵活性广泛被使用,尤其在需要被不同组件传递的数据中
Slice() : data_(""), size_(0) {}private:const char* data_;size_t size_;

status.h 是一个非常常见的返回状态的类,返回状态不要只是使用bool值表示,使用包装类可以保存更多信息

---以上我觉得是比较灵活的接口小的设计,为了更好的使用,下面这两个部分,就涉及到了程序的核心组件---

db.h 数据库的基类,主要使用name命名数据库,定义Put, Delet, Write, Get方法

write_batch.h 是一个非常非常重要的类,里面保存了用户要做的增删操作,它的编码很重要,日志中也会保存

WAL 实现

在这里面就是具体的实现部分,然后每个组件和每个组件之间的联系,内部的成员变量,然后这里的话,我并不想再赘述什么操作的实现逻辑,机制什么的,可以参考 leveldb handbook 写的很好,也很简洁,是我非常喜欢的风格。

然后我主要是想捋一下 db, log, file 这部分的逻辑

sequenceDiagramDB->>log_Writer : AddRecord()log_Writer->>WritableFile : Append()log_Writer->>WritableFile : Flush()
  • 这里就是DB中会有一个log::Writer对象,DB会将对应要写入的WriteBatch通过AddRecord()方法传入
  • log::Writer 主要负责得到了对应要写的操作,然后编码成为log的结构,然后把对应的数据传递给WritableFile对象
  • Writeable对象就是对应的file的管理,它就是对文件读写的封装,实现的就是被对应的内容调用write()系统调用写进文件

然后我的理解就是

  • DB: 接受用户的操作信息
  • log::Writer: 得到用户操作信息然后将其保证编码成为一个log的结构
  • WritableFile: 就是单纯的write()系统调用的包装,有对应应用层的缓存

tips:log::Writer不太理解,就是它的int block_offset_不知道是如何用的,应该是在read部分会有帮助吧?

WriteBatch和log的结构

日志结构

fixed64,fiex32的编码

除了在日志中varint的编码,在编码上,对于数字,也有特别的注意,因为它是以小端存储,在encode的时候也要以小端的方式,但是对应char部分是不用的,只是对于数字是需要额外编码的,因为char是没有歧义的,每个字节每个自己的存的,但是数组不是只一个字节,还需要关注字节之间的顺序,主要是在coding.h

在这里比较容易纠结的就是左移还是右移,一个比较好的理解方法是把左移看成是数据的值权重变大,而右移是数据的权重变小,然后小端就是将小的部分放在buf[0]前端慢慢往后.

inline void EncodeFixed32(char* dst, uint32_t value) {uint8_t* const buffer = reinterpret_cast<uint8_t*>(dst);buffer[0] = static_cast<uint8_t>(value);        // 存储最低字节 0x78buffer[1] = static_cast<uint8_t>(value >> 8);   // 存储次低字节 0x56buffer[2] = static_cast<uint8_t>(value >> 16);  // 存储次高字节 0x34buffer[3] = static_cast<uint8_t>(value >> 24);  // 存储最高字节 0x12
}inline uint32_t DecodeFixed32(const char* ptr) {const uint8_t* const buffer = reinterpret_cast<const uint8_t*>(ptr);return (static_cast<uint32_t>(buffer[0])) |(static_cast<uint32_t>(buffer[1]) << 8) |(static_cast<uint32_t>(buffer[2]) << 16) |(static_cast<uint32_t>(buffer[3]) << 24); 
}inline uint64_t DecodeFixed64(const char* ptr) {const uint8_t* const buffer = reinterpret_cast<const uint8_t*>(ptr);return (static_cast<uint64_t>(buffer[0])) |(static_cast<uint64_t>(buffer[1]) << 8) |(static_cast<uint64_t>(buffer[2]) << 16) |(static_cast<uint64_t>(buffer[3]) << 24) |(static_cast<uint64_t>(buffer[4]) << 32) |(static_cast<uint64_t>(buffer[5]) << 40) |(static_cast<uint64_t>(buffer[6]) << 48) |(static_cast<uint64_t>(buffer[7]) << 56);
}inline void EncodeFixed64(char* dst, uint64_t value) {uint8_t* const buffer = reinterpret_cast<uint8_t*>(dst);buffer[0] = static_cast<uint8_t>(value);        buffer[1] = static_cast<uint8_t>(value >> 8);   buffer[2] = static_cast<uint8_t>(value >> 16);  buffer[3] = static_cast<uint8_t>(value >> 24);  buffer[4] = static_cast<uint8_t>(value >> 32);  buffer[5] = static_cast<uint8_t>(value >> 40);  buffer[6] = static_cast<uint8_t>(value >> 48);  buffer[7] = static_cast<uint8_t>(value >> 56);  
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/900749.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

01. 非阻塞的Skiplist

首先学习LevelDB当中比较独立的一部分,当然的,读源码的话,一个很好的入门的感觉就是先从一个独立的组件模块开始,一个比较容易的开始,SkipList 然后跳表的基本概念什么的我不太想要去过多的赘述,就像二叉树那样希望能得到log(N)的性能,而又利用概率算法更好实现,可以看…

ROCm技术小结与回顾(下)

示例3–V_MFMA_F64_4x4x4F64 考虑V_MFMA_F64_4x4x4F64指令,它计算大小为44的四个独立矩阵块的MFMA。执行的操作是 ,其中 , , 和 都是大小为44元素的矩阵,N=0,1,2,3。下面的两张图显示了 1)输入参数A和B的四个分量的大小和形状,如图4-18所示。 2)分量映射到波阵面所拥有…

ROCm技术小结与回顾(上)

ROCm技术小结与回顾 在这一部分中,首先检查了Kernel 5在各种AMD GPU和问题大小上的性能,并注意到当网格超过一定大小阈值时,性能似乎会急剧下降。通过实验确定,LLC的大小是大型xy平面问题性能的限制因素。提出了两种不同的解决方法来规避缓存大小的问题,这两种方法都只需要…

有限差分法——拉普拉斯第4部分

有限差分法——拉普拉斯第4部分 提出了拉普拉斯算子有限差分法的HIP实现,并应用了四种不同的优化。在这些代码修改过程中,观察到由于全局内存的总取数减少,性能得到了逐步提高。然后,应用了进一步的优化,以在512512512上达到预期的性能目标MI250X GPU的单个GCD上的512个点…

推荐几本书1《AI芯片开发核心技术详解》、2《智能汽车传感器:原理设计应用》、3《TVM编译器原理与实践》、4《LLVM编译器原理与实践》,谢谢

4本书推荐《AI芯片开发核心技术详解》、《智能汽车传感器:原理设计应用》、《TVM编译器原理与实践》、《LLVM编译器原理与实践》由清华大学出版社资深编辑赵佳霓老师策划编辑的新书《AI芯片开发核心技术详解》已经出版,京东、淘宝天猫、当当等网上,相应陆陆续续可以购买。该…

WebKit Inside: CSS 的匹配原理

WebKit Inside: CSS 的匹配原理相关文章WebKit Inside: CSS 样式表的解析 WebKit Inside: CSS 样式表的匹配时机 WebKit Inside: Acitvie 样式表 当WebView解析完所有外部与内联样式表,就要进入到CSS样式表的匹配阶段。 1 相关类图 WebKit中参与CSS样式表匹配的主要类如下图所…

助记词-公私钥-子私钥派生-钱包地址原理及实现

0x01.简介 现在各种DEX、钱包插件中的钱包导入及创建,大部分是通过助记词来备份的; 助记词是明文私钥的一种表现形式,最早由BIP39提出,为了帮助用户记住复杂的私钥; 一组助记词可以生成各个链上的公私钥,进而可以算出钱包地址;掌握了助记词,就代表掌握了该组助记词上的…

AI 代理的未来是事件驱动的

AI 代理即将彻底改变企业运营,它们具备自主解决问题的能力、适应性工作流以及可扩展性。但真正的挑战并不是构建更好的模型。 代理需要访问数据、工具,并且能够在不同系统之间共享信息,其输出还需要能被多个服务(包括其他代理)使用。这不是一个 AI 问题,而是一个基础设施…

树莓派 3B + Bookworm:mjpg-streamer 正确安装全流程(原创)

在树莓派 OS Bookworm 版本上安装 mjpg-streamer 并非像旧版本一样简单,许多网上的教程已经过时,甚至存在错误。我在尝试过程中遇到了多个问题,例如依赖库缺失、编译失败等,但最终成功解决并搭建了 远程视频流监控系统。本教程基于 树莓派 3B,整理了一套 完整、可复现 的 …

1.匀速圆周运动

1.平面中的匀速圆周运动 例子:一个物体在半径为r的圆形路径中以恒定大小的速度s移动。 建立一个二维坐标系,物体位于平面上,圆心在原点上。物体的瞬时速度v(t)总是与其运动轨迹相切,所以物体任意时刻的速度与轨迹圆相切,并且速度的大小:$|v(t)|=s$ 下图右侧的两个三角形,…

Fiddler如何抓取HTTPS请求

如果发现fiddler只能抓取http请求,但是抓取不到HTTPS请求,看查看是不是没有勾选解密https流量入口:Tools——>Options——>HTTPS,勾选以下选框设置完成过后可以正常抓取HTTPS的请求了