LevelDB 选项与使用示例
详解 LevelDB 的常用选项(Options/ReadOptions/WriteOptions)与核心 API 使用示例:Put/Get/Delete/WriteBatch 批量写、Iterator 迭代器与排序遍历、Compaction 与实现机制,附 db_bench 基准说明与真实运行输出。基于 LevelDB 1.23 实测。
LevelDB 选项与使用示例
目标:掌握 LevelDB 作为嵌入 KV 库的选项配置与 C++ 核心 API 用法。LevelDB 是 ordered key-value store(有序键值),核心由
leveldb::DB::Open打开库,用Put/Get/Delete/WriteBatch读写,用Iterator有序遍历。本文示例编译运行于 LevelDB 1.23(链接libleveldb.a+-lsnappy)。
一、核心概念
- 排序:键按字典序(byte-wise)排序保存。
- LSM 结构:写先入内存 memtable(再固化 immutable memtable → SST),通过 Compaction(多级合并)维持读效率。
- 无服务进程:LevelDB 是库,由宿主进程以单进程或多进程(需锁)方式使用。
二、选项(Options)
leveldb::Options 在 DB::Open 时配置库级行为:
| 字段 | 说明 | 常见值 |
|---|---|---|
create_if_missing | 库不存在时自动创建 | true |
error_if_exists | 库已存在时报错(排障用) | false |
write_buffer_size | 内存写缓冲(memtable)大小 | 默认 4MB(4<<20) |
max_open_files | 可打开的文件句柄上限 | 默认 1000 |
block_cache | 读缓存(NewLRUCache) | 默认空 |
block_size | SST 数据块大小 | 默认 4KB |
compression | 压缩方式 | kSnappyCompression/kNoCompression |
filter_policy | Bloom 过滤器,加速查不存在 key | NewBloomFilterPolicy(10) |
comparator | 键比较器(自定义排序) | 默认字节序比较 |
典型配置:
leveldb::Options opts;
opts.create_if_missing = true;
opts.write_buffer_size = 8 << 20; // 8 MB
opts.block_cache = leveldb::NewLRUCache(64 << 20); // 64 MB 读缓存
opts.filter_policy = leveldb::NewBloomFilterPolicy(10);
opts.compression = leveldb::kSnappyCompression;
leveldb::DB::Open(opts, "/data/ldb", &db);
三、ReadOptions / WriteOptions
ReadOptions(读):
| 字段 | 说明 |
|---|---|
verify_checksums | 读时校验数据校验和(默认 false) |
fill_cache | 读入的数据是否填充块缓存(默认 true) |
WriteOptions(写):
| 字段 | 说明 |
|---|---|
sync | 写入是否等落盘再返回(默认 false,更快) |
// 每次写同步落盘(更安全但更慢)
leveldb::WriteOptions wo;
wo.sync = true;
db->Put(wo, "k", "v");
四、核心 API 使用示例
完整可编译 demo(g++ -std=c++11 demo.cc -lleveldb -lsnappy -lpthread):
4.1 Put / Get / Delete
#include <cassert>
#include <iostream>
#include "leveldb/db.h"
leveldb::DB* db;
leveldb::Options options;
options.create_if_missing = true;
leveldb::Status s = leveldb::DB::Open(options, "/tmp/ldb", &db);
s = db->Put(leveldb::WriteOptions(), "key1", "value1"); // 写
assert(s.ok());
std::string v;
s = db->Get(leveldb::ReadOptions(), "key1", &v); // 读
if (s.ok()) std::cout << "Get key1=" << v << std::endl;
std::string miss;
s = db->Get(leveldb::ReadOptions(), "nokey", &miss); // 读不存在的 key
std::cout << "Get nokey=" << s.ToString() << std::endl; // NotFound
s = db->Delete(leveldb::WriteOptions(), "key1"); // 删
assert(s.ok());
实测输出:
Get: key1 = value1
Get: nokey -> NotFound:
Delete key1 ok
4.2 WriteBatch 批量写(原子)
WriteBatch 把多条写合并为一次原子提交,减少 RTT 并保证原子性:
#include "leveldb/write_batch.h"
leveldb::WriteBatch batch;
batch.Put("a", "1");
batch.Put("b", "2");
// batch.Delete("a"); // 支持混合删除
db->Write(leveldb::WriteOptions(), &batch);
实测输出:Batch written。
4.3 Iterator 有序遍历
leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
for (it->SeekToFirst(); it->Valid(); it->Next())
std::cout << " " << it->key().ToString() << " -> "
<< it->value().ToString() << std::endl;
delete it;
实测输出(插入 a、b、key1 后遍历,按字典序):
Iterate all keys:
a -> 1
b -> 2
key1 -> value1
常用迭代操作:
| 方法 | 作用 |
|---|---|
SeekToFirst() / SeekToLast() | 跳到第一个 / 最后一个 |
Seek(target) | 跳到 >= target 的第一个键 |
Valid() / Next() / Prev() | 判断有效 / 前进 / 后退 |
key() / value() | 读当前键 / 值 |
五、db_bench 基准(可选)
启用 LEVELDB_BUILD_BENCHMARKS=ON 时编译出 db_bench,可测读写吞吐:
cd build && cmake --build . --target db_bench
./db_bench
输出包含 fillseq、readrandom 等阶段与每秒操作数(ops/sec)。
六、常见问题(FAQ)
1. 多进程能同时打开同一个库吗?
LevelDB 用文件锁实现单写者;多进程并发写同一目录会因锁失败。多进程场景需先做持久化 DB 锁管理,或改用 RocksDB 的并发模式(见《RocksDB 配置与选项详解》)。
2. 写很慢?
WriteOptions.sync 默认为 false 已非同步;仍需更快的批量写用 WriteBatch 合并。
3. 数据库目录里有哪些文件?
CURRENT、MANIFEST-*、*.log(WAL/memtable 日志)、*.ldb(SST 数据)、LOCK、*.dbtmp 等。别单独复制 logs 已迁移,用官方同步备份机制。
4. 如何确认读到的最新值?
LevelDB 默认返回最新可见值(含未 Compact 的内存与 SST 叠加)。
七、小结
LevelDB 的选项集中在 Options(写缓冲/缓存/压缩/过滤器)与 ReadOptions/WriteOptions(同步/校验)。核心 API 即 Open + Put/Get/Delete + WriteBatch + Iterator,配合 Bloom 过滤与缓存即可用于本地有序 KV 存储。想要更丰富的配置、Blob 与并发写入,可参考姐妹库 RocksDB 的《RocksDB 配置与选项详解》。