LevelDb是google的工程师Jeff Dean和Sanjay Ghemawat这两位大神级别的工程师发起的开源项目,这两位是Google重量级的工程师,为数甚少的Google Fellow之二。Jeff Dean其人是Google大规模分布式平台Bigtable和MapReduce主要设计和实现者,Sanjay Ghemawat是Google大规模分布式平台GFS,Bigtable和MapReduce主要设计和实现工程师。Google大数据的三驾马车论文参考:GFS论文阅读、Mapreduce论文阅读、BigTable论文阅读。
LevelDb是能够处理十亿级别规模Key-Value型数据持久性存储的嵌入式数据库,内部没有设计成C/S网络结构,必须和服务部署在同一台服务器。levelDB其实也是一个C++程序库,是可以可以被编译和链接到我们自己的程序中的库,而不是像Redis那样是一个数据库服务器。LevelDb本质上是一个存储引擎,即一套存储系统以及在这套存储系统上提供的一些操作接口。LevelDb有如下一些特点:
git clone --recurse-submodules https://github.com/google/leveldb.git
mkdir -p build
cd build
cmake -DCMAKE_BUILD_TYPE=Release .. && cmake --build .
编译好之后,在build目录会生成libleveldb.a静态库文件,在使用时,我们只需要把源码中的头文件目录leveldb/加入到我们工程的include目录,并且把编译好的静态库文件加入到我们工程的lib目录即可,这里我使用cmake来编译工程,具体的工程配置和编译参考GoogleTest入门,在编译过程中注意需要链接pthread线程库。
接下来我们来分析一下leveldb的hello world程序。
#include <iostream>
#include <cassert>
#include "leveldb/db.h"
#include "leveldb/write_batch.h"
int main()
{
// Open a database.
leveldb::DB* db;
leveldb::Options opts;
opts.create_if_missing = true;
leveldb::Status status = leveldb::DB::Open(opts, "./testdb", &db);
assert(status.ok());
// Write data.
status = db->Put(leveldb::WriteOptions(), "name", "jinhelin");
assert(status.ok());
// Read data.
std::string val;
status = db->Get(leveldb::ReadOptions(), "name", &val);
assert(status.ok());
std::cout << val << std::endl;
// Batch atomic write.
leveldb::WriteBatch batch;
batch.Delete("name");
batch.Put("name0", "jinhelin0");
batch.Put("name1", "jinhelin1");
batch.Put("name2", "jinhelin2");
batch.Put("name3", "jinhelin3");
batch.Put("name4", "jinhelin4");
batch.Put("name5", "jinhelin5");
batch.Put("name6", "jinhelin6");
batch.Put("name7", "jinhelin7");
batch.Put("name8", "jinhelin8");
batch.Put("name9", "jinhelin9");
status = db->Write(leveldb::WriteOptions(), &batch);
assert(status.ok());
// Scan database.
leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
for (it->SeekToFirst(); it->Valid(); it->Next()) {
std::cout << it->key().ToString() << ": " <<
it->value().ToString() << std::endl;
}
assert(it->status().ok());
// Range scan, example: [name3, name8)
for (it->Seek("name3");
it->Valid() && it->key().ToString() < "name8";
it->Next()) {
std::cout << it->key().ToString() << ": " <<
it->value().ToString() << std::endl;
}
// Close a database.
delete db;
}
这个例子简单介绍了 LevelDB 的基本用法,包括:
(1)打开数据库:
leveldb::DB* db;
leveldb::Options opts;
opts.create_if_missing = true;
leveldb::Status status = leveldb::DB::Open(opts, "./testdb", &db);
assert(status.ok());
leveldb::DB::Open()打开数据库需要三个参数:
(2)写入一条数据:
status = db->Put(leveldb::WriteOptions(), "name", "jinhelin");
assert(status.ok());
db->put 接口的三个参数:
(3)读取一条数据:
std::string val;
status = db->Get(leveldb::ReadOptions(), "name", &val);
assert(status.ok());
std::cout << val << std::endl;
Get 接口和 Put 接口比较像,除了 leveldb::ReadOptions 参数是用来控制读操作的.
(4)批量原子操作:
leveldb::WriteBatch batch;
batch.Delete("name");
batch.Put("name0", "jinhelin0");
batch.Put("name1", "jinhelin1");
batch.Put("name2", "jinhelin2");
batch.Put("name3", "jinhelin3");
batch.Put("name4", "jinhelin4");
batch.Put("name5", "jinhelin5");
batch.Put("name6", "jinhelin6");
batch.Put("name7", "jinhelin7");
batch.Put("name8", "jinhelin8");
batch.Put("name9", "jinhelin9");
status = db->Write(leveldb::WriteOptions(), &batch);
assert(status.ok());
LevelDB 的 Write 接口支持原子地修改多条数据,主要参数是 leveldb::WriteBatch 。
(5)数据库的遍历和范围查找:
leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
for (it->SeekToFirst(); it->Valid(); it->Next()) {
std::cout << it->key().ToString() << ": " <<
it->value().ToString() << std::endl;
}
assert(it->status().ok());
// Range scan, example: [name3, name8)
for (it->Seek("name3");
it->Valid() && it->key().ToString() < "name8";
it->Next()) {
std::cout << it->key().ToString() << ": " <<
it->value().ToString() << std::endl;
}
LevelDB 通过提供 leveldb::Iterator 来实现范围查找。
(6)关闭数据库:
delete db;
关闭数据库时需要删除掉创建的数据库实例,让其调用析构函数处理一些收尾工作。