LevelDB 反向迭代怎么用:SeekToLast 配合 Prev 遍历并检查迭代状态
【免费下载链接】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 把数据按键的排序顺序存储,除了正向扫描,还支持反向(backward)迭代。本文的任务是:在 C++ 程序中使用Iterator::SeekToLast()配合Iterator::Prev(),把数据库中所有的 key/value 对按排序顺序的逆序(从最大的 key 到最小的 key)遍历一遍,并在循环结束后检查迭代状态、确认扫描过程没有出错。适用前提是你在一个已链接 LevelDB 库的 C++ 工程中,数据库是本地文件系统上的一个目录。
前置条件:构建与打开数据库
README 给出的 POSIX 构建方式是 CMake 两行命令,在源码根目录执行:
mkdir -p build && cd build cmake -DCMAKE_BUILD_TYPE=Release .. && cmake --build .按 doc/index.md 的示例打开数据库,数据库名对应一个文件系统目录,缺失时会自动创建:
#include <cassert> #include "leveldb/db.h" leveldb::DB* db; leveldb::Options options; options.create_if_missing = true; leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db); assert(status.ok());两个可选开关,文档均有说明:
options.create_if_missing = true:数据库目录不存在时创建;options.error_if_exists = true:数据库已存在时报错,在leveldb::DB::Open调用之前设置。
默认比较器按键的字节字典序排序,反向遍历的"逆序"即这个顺序的倒序;如果打开时指定了自定义 comparator,顺序按你定义的比较规则。
获取迭代器
leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());include/leveldb/db.h 中NewIterator的注释规定了三点,直接影响后面的用法:
- 返回的迭代器初始状态是无效的,使用前必须先调用某个 Seek 方法(本任务用
SeekToLast); - 迭代器是堆分配的,用完必须
delete it; - 迭代器应比
db先被删除。
可选分支:如果你做的是大批量读取,doc/index.md 的 Performance 一节建议在ReadOptions中设置fill_cache = false,让批量读到的数据不去挤占 block cache:
leveldb::ReadOptions options; options.fill_cache = false; leveldb::Iterator* it = db->NewIterator(options);仅当你的目标是大批量扫描且在意缓存污染时才用;普通遍历用默认的ReadOptions()即可。
反向遍历循环
反向迭代的主循环就是 doc/index.md Iteration 一节给出的形式:
for (it->SeekToLast(); it->Valid(); it->Prev()) { ... }对照 include/leveldb/iterator.h 的注释,循环三个部分各自的语义是:
SeekToLast():定位到源中的最后一个 key。调用后迭代器Valid()为 true,当且仅当源非空。所以空数据库下循环体一次都不会执行,这是正常的,不是错误。Valid():为 true 表示迭代器当前停在某个 key/value 对上,可以调用key()/value()。Prev():移动到前一个 entry。调用后Valid()为 true,当且仅当移动前迭代器不在第一个 entry 上。它带有REQUIRES: Valid()约束,只在迭代器有效时才能调用。
在循环体内取当前 entry:
it->key().ToString() it->value().ToString()key()/value()返回leveldb::Slice,头文件注明其底层存储只在下一次修改迭代器之前有效,且要求Valid()。因此如果要在循环外保存这些值,用ToString()拷贝成std::string,不要直接保存 Slice 本身——这是 doc/index.md Slice 一节强调的调用者责任。
完整可运行示例
下面把上述片段拼成一个完整程序。"/tmp/testdb"来自文档示例,可替换为你自己的目录;如果数据库已有数据,Put一行可以跳过:
#include <cassert> #include <iostream> #include "leveldb/db.h" #include "leveldb/iterator.h" int main() { leveldb::DB* db; leveldb::Options options; options.create_if_missing = true; leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db); assert(status.ok()); // 准备一条数据。值取自 doc/index.md 的 Slice 示例 status = db->Put(leveldb::WriteOptions(), "hello", "world"); assert(status.ok()); leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions()); for (it->SeekToLast(); it->Valid(); it->Prev()) { std::cout << it->key().ToString() << ": " << it->value().ToString() << std::endl; } assert(it->status().ok()); // Check for any errors found during the scan delete it; delete db; return 0; }程序的行为:从当前最大的 key 开始,每次输出一对 key/value,一直遍历到最小的 key 为止;迭代器先于db删除。
如何检查迭代状态
扫描结束后的状态检查就是 doc/index.md 中紧跟正向遍历示例的这行(反向循环同样适用):
assert(it->status().ok()); // Check for any errors found during the scan对应 include/leveldb/iterator.h 中status()的定义:"If an error has occurred, return it. Else return an ok status.",即扫描过程中如果发生过错误,这里会拿到该错误。生产代码中通常不用assert,而是按文档 Status 一节的写法输出错误信息:
leveldb::Status s = it->status(); if (!s.ok()) cerr << s.ToString() << endl;判断迭代是否"走完"则看Valid():Prev()之后Valid()为 false,表示已经离开了第一个 entry、反向遍历结束。文档没有为反向遍历提供其他终止标志,Valid()是唯一依据。
边界与限制
- 性能:doc/index.md 明确提示 "Caveat: reverse iteration may be somewhat slower than forward iteration."。README 的性能报告(来自随库的 db_bench 程序,工作集在内存中的场景,文档自述结果有噪声,仅为文档示例)中,
readreverse为 0.724 micros/op / 152.9 MB/s,readseq为 0.476 micros/op / 232.3 MB/s,反向确实慢于正向。 - 线程:
leveldb::DB对象本身可被多线程共享,但 doc/index.md Concurrency 一节指出 Iterator 这类对象被多线程共享时必须由你自己加锁做外部同步。 - 生命周期:再次强调
delete it必须发生在delete db之前,这是 include/leveldb/db.h 的明确要求。
做完上述步骤,成功的标准是:循环按 key 的降序输出了数据库中的全部条目(空库则一次不输出),it->status()返回 ok。若status()非 ok,用ToString()打印的字符串就是扫描中遇到的错误信息。
【免费下载链接】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),仅供参考