google的leveldb是久闻大名的数据存储库,可以说是开源爱好者的必推项目了,最近准备在自己的程序中使用一下leveldb,并读源码,因此想记录一下学习的过程。
leveldb的安装,请参考:http://blog.csdn.net/koko2015c/article/details/68066761,其实也就是make一下然后拷贝动态链接库常规的操作,不过最新的leveldb版本好像已经改用cmake编译了,看来cmake还是有必要掌握一下的吧。
leveldb是单机的K/V数据存储系统,用到了 LSM Tree的设计思想,使用对日志的操作代替对磁盘的随机存取,这种顺序操作避免了随机写所带来的时间负担,不过同时也抛弃了随机查询的速度优势,即:使用顺序读写代替随机读写,虽然顺序写比随即写的速度快,但顺序读比随机读的速度慢!
较新的数据都被append到log中然后放到称为memtable的顺序缓存上,当memtable的体积足够大了以后将变为immemtable,数据移到外存,加入SSTable,这是一个有序的层次结构,用于存放所有的“旧数据”(相对于memtable中的新数据),每个层次存放的key没有重复,以便于新来的数据快速合并(compaction)到SSTable中。
SSTable的层次结构应该就是系统被成为“leveldb”的原因了!
conpaction是SSTable操作的核心操作,因为是对SSTable的内容扩充,所以最坏情况可能会导致对SSTable的数据整体重新写一遍!对SSTable分层以后,leveldb选择将新来的数据做的处理是:所有的操作都是延时的操作。
Code:db/memtable.cc(82-106)
void MemTable::Add(SequenceNumber s, ValueType type,
const Slice& key,
const Slice& value) {
// Format of an entry is concatenation of:
// key_size : varint32 of internal_key.size()
// key bytes : char[internal_key.size()]
// value_size : varint32 of value.size()
// value bytes : char[value.size()]
size_t key_size = key.size();
size_t val_size = value.size();
size_t internal_key_size = key_size + 8;
const size_t encoded_len =
VarintLength(internal_key_size) + internal_key_size +
VarintLength(val_size) + val_size;
char* buf = arena_.Allocate(encoded_len);
char* p = EncodeVarint32(buf, internal_key_size);
memcpy(p, key.data(), key_size);
p += key_size;
EncodeFixed64(p, (s << 8) | type);
p += 8;
p = EncodeVarint32(p, val_size);
memcpy(p, value.data(), val_size);
assert(p + val_size == buf + encoded_len);
table_.Insert(buf);
}
memtable的添加/删除操作,当type为kTypeDeletion的时候表示删除操作,value没有值。leveldb没有单独的删除操作,删除表现为特别的添加!
实例:Demo
demo.cpp作为leveldb的一个简单应用,创建数据库并读/写数据库
#include "leveldb/db.h"
#include <cassert>
#include <iostream>
using namespace std;
using namespace leveldb;
int main()
{
leveldb::DB *db;
leveldb::Options options;
options.create_if_missing = true;
leveldb::Status status = leveldb::DB::Open(options, "testdb", &db);
assert(status.ok());
status = db->Put(WriteOptions(), "abc", "levelDB here!");
assert(status.ok());
string res;
status = db->Get(ReadOptions(), "abc", &res);
assert(status.ok());
cout << res << endl;
delete db;
return 0;
}
最后是使用文档: https://github.com/google/leveldb/blob/master/doc/index.md