LevelDb-用户接口
优缺点
- This is not a SQL database. It does not have a relational data model, it does not support SQL queries, and it has no support for indexes.
- Only a single process (possibly multi-threaded) can access a particular database at a time.
- There is no client-server support builtin to the library. An application that needs such support will have to wrap their own server around the library.
TODO:回头再来理解
用户接口
基本读写
打开关闭数据库
#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());
...
delete db;
读写
std::string value;
leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value);
if (s.ok()) s = db->Put(leveldb::WriteOptions(), key2, value);
if (s.ok()) s = db->Delete(leveldb::WriteOptions(), key1);
原子更新
#include "leveldb/write_batch.h"
...
std::string value;
leveldb::Status s = db->Get(leveldb::ReadOptions(), key1, &value);
if (s.ok()) {
leveldb::WriteBatch batch;
batch.Delete(key1);
batch.Put(key2, value);
s = db->Write(leveldb::WriteOptions(), &batch);
}
delete key1和put key2在一个原子请求中,要么都不执行,要么都执行。
同步/异步写
leveldb::WriteOptions write_options;
write_options.sync = true;
db->Put(write_options, ...);
默认写是异步的,可以设置上述参数实现同步写。异步写速度快。
并发
一个数据库同时只能被一个进程使用。
一个进程中的DB对象是线程安全的,但是Iterator和WriteBatch这些对象不是。
迭代器
leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
for (it->SeekToFirst(); it->Valid(); it->Next()) {
cout << it->key().ToString() << ": " << it->value().ToString() << endl;
}
assert(it->status().ok()); // Check for any errors found during the scan
delete it;
遍历所有的数据。
for (it->Seek(start);
it->Valid() && it->key().ToString() < limit;
it->Next()) {
...
}
遍历[start, limit)区间的数据。
for (it->SeekToLast(); it->Valid(); it->Prev()) {
...
}
倒序遍历,效率不如正序遍历。
快照
leveldb::ReadOptions read_options;
read_options.snapshot = db->GetSnapshot();
assert(status.ok());
status = db->Put(leveldb::WriteOptions(), "key1", "value2");
leveldb::Iterator* it = db->NewIterator(read_options);
for (it->SeekToFirst(); it->Valid(); it->Next()) {
std::cout << it->key().ToString() << ": " << it->value().ToString() << std::endl;
}
创建一个数据状态的可读快照。
如上所示,Put key1,value2之前,数据库里key1对应的是value1,在Put之前创建了快照对象,Put之后,用快照的key1的值依然是value1。
Slice
it->key() and it->value()返回的都是Slice实例,能和string互转。
leveldb::Slice s1 = "hello";
std::string str("world");
leveldb::Slice s2 = str;
自定义key比较器
默认的是按key的字典序进行排序。
class TwoPartComparator : public leveldb::Comparator {
public:
// Three-way comparison function:
// if a < b: negative result
// if a > b: positive result
// else: zero result
int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const {
int a1, a2, b1, b2;
ParseKey(a, &a1, &a2);
ParseKey(b, &b1, &b2);
if (a1 < b1) return -1;
if (a1 > b1) return +1;
if (a2 < b2) return -1;
if (a2 > b2) return +1;
return 0;
}
// Ignore the following methods for now:
const char* Name() const { return "TwoPartComparator"; }
void FindShortestSeparator(std::string*, const leveldb::Slice&) const {}
void FindShortSuccessor(std::string*) const {}
};
TwoPartComparator cmp;
leveldb::DB* db;
leveldb::Options options;
options.create_if_missing = true;
options.comparator = &cmp;
leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
...
性能相关
压缩
leveldb::Options options;
options.compression = leveldb::kNoCompression;
... leveldb::DB::Open(options, name, ...) ....
默认开启压缩,可用如上代码关闭。
缓存
#include "leveldb/cache.h"
leveldb::Options options;
options.block_cache = leveldb::NewLRUCache(100 * 1048576); // 100MB cache
leveldb::DB* db;
leveldb::DB::Open(options, name, &db);
... use the db ...
delete db
delete options.block_cache;
设置缓存。
leveldb::ReadOptions options;
options.fill_cache = false;
leveldb::Iterator* it = db->NewIterator(options);
for (it->SeekToFirst(); it->Valid(); it->Next()) {
...
}
大量读请求的场景下,可以关闭文件缓存,防止在内存中缓存大量数据。
key设计
leveldb中连续的key会存在一起,根据这个特性,经常一起访问的数据key最好相似。
filename -> permission-bits, length, list of file_block_ids
file_block_id -> data
比如有这两类数据,filename最好以"/"开始,file_block_id最好以数据开始,这样查找filename对应的元信息时,不会扫描到file_block_id对应的数据。
布隆过滤
leveldb::Options options;
options.filter_policy = NewBloomFilterPolicy(10);
leveldb::DB* db;
leveldb::DB::Open(options, "/tmp/testdb", &db);
... use the database ...
delete db;
delete options.filter_policy;
设置布隆过滤器,取key的特征,判定key存在的概率,从而减少不必要读。
获取范围数据大小近似值
leveldb::Range ranges[2];
ranges[0] = leveldb::Range("a", "c");
ranges[1] = leveldb::Range("x", "z");
uint64_t sizes[2];
db->GetApproximateSizes(ranges, 2, sizes);
参考资料:
levedb doc