ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

LevelDB dumpfile:读懂数据库内部三种文件的完整方法

2026/9/1 13:27:25 拓冰建站 浏览量
LevelDB dumpfile:读懂数据库内部三种文件的完整方法 LevelDB dumpfile读懂数据库内部三种文件的完整方法【免费下载链接】leveldbLevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values.项目地址: https://gitcode.com/GitHub_Trending/leveldb4/leveldb凌晨应用报无法打开 LevelDB 数据库错误信息只指向一个 WAL 文件。打开数据目录里面是若干带六位数字前缀的二进制文件000007.ldb、000013.log、MANIFEST-000012hexdump 只有一串看不懂的字节连哪些 key 还活着都无法确认。LevelDB 自带的 dumpfile 模块就是为这种处境准备的它把这些存储文件变成可逐行阅读的文字。先 dump 一个 SSTable 试试命令行入口是 db/leveldbutil.cc它只注册了一个dump子命令行为是调用 include/leveldb/dumpfile.h 声明的DumpFile把结果写到 stdout。编译运行路径git clone https://gitcode.com/GitHub_Trending/leveldb4/leveldb cd leveldb mkdir build cd build cmake .. make leveldbutil ./leveldbutil dump ../mydb/000007.ldb一个小 .ldb 文件的输出大致长这样user:1001 42 : val {name:alice,role:ops} user:1002 47 : del session:9f2c 53 : val {token:s_8a3d,expire:1756915200}user:1001用户键即应用 Put/Get 传入的 key42序列号越大表示写入越晚val/del记录类型值写入或墓碑删除标记 ...实际存储的值del 记录为空这一行的每个字段都不是直接从文件里解出来的而是内部键拆分后拼装的结果机制在下一节。文件类型靠文件名识别LevelDB 数据目录里可能有几十种文件但 dumpfile 只处理其中三类判断完全由文件名完成。DumpFile是调度中心先用GuessType从文件名识别类型再按类型路由到DumpLog、DumpTable、DumpDescriptor。真正干活的是 db/filename.cc 的ParseFileName匹配规则非常严格CURRENT、LOCK、LOG等固定名 → 各自对应一种固定文件类型MANIFEST-数字→ 描述符文件 kDescriptorFile数字.log→ 日志文件数字.ldb或.sst→ SSTable其余 → 识别失败返回 unknown file type文件名就是类型声明只有上表三类有解析处理器能识别但没有解析器的文件如 CURRENT、LOCK会返回 not a dump-able file type。键值输出逐字段拆解内部键用户键加两个字段SSTable 里 dump 出的 key 并不是你在代码里写的那个。db/dbformat.h 中ParsedInternalKey由 user_key、sequence、type 三部分构成磁盘上把序列号和操作类型占低 8 位与用户键打包成一个内部键因此同一个业务 key 可以在同一张表里留下多条不同序列号的记录。db/dumpfile.cc 的DumpTable先Table::Open打开整张表再从SeekToFirst遍历到末尾逐条用ParseInternalKey拆出内部键才拼出key seq : val/del value这一行。解析不了的记录会输出为badkey行而不是中断迭代出错则追加一行iterator error——这是它对损坏表的容错设计。还原日志文件里的写入历史.log 文件WAL预写日志存的是 WriteBatch 记录每条对应一次应用写入。DumpLog用 log::Reader 逐条读取记录每条记录经WriteBatchPrinter展开--- offset 32; sequence 101 put user:1001 {name:alice,role:ops} del session:9f2coffset 32这条 WriteBatch 在日志文件中起始的字节偏移sequence 101本批起始序列号批内操作依次取 101、102……put/del批内操作键和值转义后输出与 SSTable 输出的差别在于视角SSTable 回答每个 key 最终存了哪个版本日志回答写入按什么顺序进来。排查某次写入到底落盘没有时以日志的 offset 与 sequence 为锚点。从 MANIFEST 追溯版本轨迹MANIFEST 是 LevelDB 分层结构的持久化记录每次 compaction 增删文件都先写入它。DumpDescriptor把每条记录解码成 VersionEdit再用DebugString格式定义见 db/version_edit.cc输出--- offset 41; VersionEdit { LogNumber: 12 NextFile: 21 LastSeq: 104 AddFile: 2 20 4096 user:1000 .. user:1199 }AddFile: 2 20 4096 ...向第 2 层加入编号 20 的文件大小 4096键范围 user:1000 到 user:1199RemoveFile: L N从第 L 层移除编号 N 的文件LastSeq本次变更时的序列号水位线按 offset 顺序读 MANIFEST就得到数据库层级结构的完整演化时间线是追查某个大文件是哪次 compaction 产物的第一站。从损坏日志提取有效记录回到开头场景WAL 损坏、数据库打不开。关键在于 dumpfile 遇到损坏不会停——log::Reader 检测到校验和失败时交给注册的 reporterdb/dumpfile.cc 里的CorruptionReporter只把一行 corruption: N bytes; 原因 写进输出流随后继续读取后面的记录./leveldbutil dump mydb/000013.log recovered.txt grep put recovered.txt # 筛出有效 put 行损坏段被压缩成一行 corruption 报错其前后完整的 WriteBatch 照常 dump 出来据此可以把真正生效的操作重建为修复脚本。三种文件格式本身在 doc/table_format.mdSSTable 块布局和 doc/log_format.md日志记录分帧与校验和里有完整说明想弄清 dumpfile 凭什么能读出这些文件先读这两份文档再回看 db/dumpfile.cc 会顺畅很多。【免费下载链接】leveldbLevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values.项目地址: https://gitcode.com/GitHub_Trending/leveldb4/leveldb创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考