news 2026/9/1 13:27:20

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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-000012,hexdump 只有一串看不懂的字节,连"哪些 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 传入的 key
  • 42:序列号,越大表示写入越晚
  • val/del:记录类型,值写入或墓碑删除标记
  • => '...':实际存储的值,del 记录为空

这一行的每个字段都不是直接从文件里解出来的,而是内部键拆分后拼装的结果,机制在下一节。

文件类型靠文件名识别

LevelDB 数据目录里可能有几十种文件,但 dumpfile 只处理其中三类,判断完全由文件名完成。DumpFile是调度中心:先用GuessType从文件名识别类型,再按类型路由到DumpLogDumpTableDumpDescriptor。真正干活的是 db/filename.cc 的ParseFileName,匹配规则非常严格:

  1. CURRENTLOCKLOG等固定名 → 各自对应一种固定文件类型
  2. MANIFEST-<数字>→ 描述符文件 kDescriptorFile
  3. <数字>.log→ 日志文件;<数字>.ldb.sst→ SSTable
  4. 其余 → 识别失败,返回 "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 的DumpTableTable::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:9f2c'
  • offset 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:1199
  • RemoveFile: L N:从第 L 层移除编号 N 的文件
  • LastSeq:本次变更时的序列号水位线

按 offset 顺序读 MANIFEST,就得到数据库层级结构的完整演化时间线,是追查"某个大文件是哪次 compaction 产物"的第一站。

从损坏日志提取有效记录

回到开头场景:WAL 损坏、数据库打不开。关键在于 dumpfile 遇到损坏不会停——log::Reader 检测到校验和失败时交给注册的 reporter,db/dumpfile.cc 里的CorruptionReporter只把一行 "corruption: N bytes; <原因>" 写进输出流,随后继续读取后面的记录:

./leveldbutil dump mydb/000013.log > recovered.txt grep "put '" recovered.txt # 筛出有效 put 行

损坏段被压缩成一行 corruption 报错,其前后完整的 WriteBatch 照常 dump 出来,据此可以把真正生效的操作重建为修复脚本。三种文件格式本身在 doc/table_format.md(SSTable 块布局)和 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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/1 13:20:16

微信、QQ消息被撤回了?RevokeMsgPatcher 防撤回补丁打补丁指南

微信、QQ消息被撤回了&#xff1f;RevokeMsgPatcher 防撤回补丁打补丁指南 【免费下载链接】RevokeMsgPatcher :trollface: A hex editor for WeChat/QQ/TIM - PC版微信/QQ/TIM防撤回补丁&#xff08;我已经看到了&#xff0c;撤回也没用了&#xff09; 项目地址: https://gi…

作者头像 李华
网站建设 2026/9/1 13:19:26

awesome-gpt-image-2 Agent Skill完整教程:把风格库装进Claude Code

awesome-gpt-image-2 Agent Skill完整教程&#xff1a;把风格库装进Claude Code 【免费下载链接】awesome-gpt-image-2 Prompt as Code | GPT-Image2 工业级提示词引擎与模板库&#xff0c;530 个案例逆向工程&#xff0c;20 套工业级模板&#xff0c;并提炼出Skills&#xff0…

作者头像 李华
网站建设 2026/9/1 13:19:13

C语言枚举(enum)完全指南:从基础语法到底层原理与实战应用

在C语言的学习道路上&#xff0c;我们常常会遇到一些需要表示一组固定、有限选项的场景&#xff0c;比如一周的七天、一年的四季、订单的状态&#xff08;待支付、已支付、已发货&#xff09;。如果使用简单的整数常量&#xff08;如 #define MON 1 &#xff09;&#xff0c;…

作者头像 李华
网站建设 2026/9/1 13:18:12

机器视觉13-2

案例1&#xff1a;蓝色工件破损检测 并且标绘出缺陷轮廓1.颜色提取工具 目的&#xff1a;获取输出一个灰度图像 用于blob检测1.提取多的特征颜色 目的: 是灰度图的特征更明显1.提取效果图1.blob工具#region namespace imports using System; using System.Collections; usi…

作者头像 李华
网站建设 2026/9/1 13:17:31

ZYNQ7020嵌入式平台LVGL 9.5.0移植与优化实战指南

在 ZYNQ7020 这颗经典的 FPGAARM 双核芯片上跑 LVGL 9.5.0&#xff0c;核心要解决的是 如何在资源受限的嵌入式平台上&#xff0c;流畅运行一个现代化的图形界面库 。这不仅仅是“能不能跑起来”的问题&#xff0c;更是关于如何平衡性能、内存和开发效率。如果你手头有 ZYNQ7…

作者头像 李华