02-leveldb入门—从0开始编译和使用leveldb
Posted anda0109
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了02-leveldb入门—从0开始编译和使用leveldb相关的知识,希望对你有一定的参考价值。
01-leveldb编译和使用
在github下载开源代码:git clone --recurse-submodules https://github.com/google/leveldb.git
进入项目根目录,执行以下命令:
mkdir -p build && cd build
cmake -DCMAKE_BUILD_TYPE=Release … && cmake --build .
以上命令运行之后会编译全部代码包括测试程序,windows下编译生成文件在leveldb/build/Release下。同时在leveldb/build目录下可以打开leveldb.sln工程文件,在visual studio中查看工程代码。
一个简单的应用leveldb实现数据写入、查询的例子,依照国际惯例,还是从“hello world”开始:
#include <cassert>
#include "leveldb/db.h"
int main()
//open database
leveldb::DB* db;
leveldb::Options options;
options.create_if_missing = true;
leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
if (!status.ok())
std::cout << "open db failed" << std::endl;
return -1;
std::string key = "first_key";
std::string value = "hello world";
leveldb::Status s = db->Put(leveldb::WriteOptions(), key, value);
value.clear();
if (s.ok())
s = db->Get(leveldb::ReadOptions(), key, &value);
if(s.ok())
std::out << value << std::endl;
//close database
delete db;
return 0;
运行结果:Hello world
02-leveldb的基本操作
1-打开数据库
打开leveldb数据库需要指定一个文件系统目录,数据库的所有文件都存放在该目录下。
#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());
...
2-读写数据
leveldb提供了Get、Put、Delete方法来进行数据的查询、写入和删除操作。没有提供更新接口,直接使用Put接口写入一个新的value即会覆盖之前的值。
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);
3-原子更新
如果某个业务的处理需要连续写入多个数据,这些数据会依次写入。如果中途宕机则可能导致部分写入成功,部分失败,从而影响业务的完整性。使用WriteBatch批处理功能,则会保证一个WriteBatch的所有操作要么全部成功,要么全部失败,即保证原子性。
#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);
4-同步写
leveldb提供了同步写方式,即每次写入数据后强制刷盘。这种方式能保证机器宕机情况下数据的落盘安全,但会极大地降低数据库写入性能。在实际使用中我们往往不会采用同步写的方式,即允许极端情况下的一些数据丢失,而保证其使用的性能。
leveldb::WriteOptions write_options;
write_options.sync = true;
db->Put(write_options, ...);
5-迭代
以下代码用于迭代数据库的所有数据。
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;
以下代码用于迭代指定范围内的数据。
leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
for (it->Seek(start);
it->Valid() && it->key().ToString() < limit;
it->Next())
...
assert(it->status().ok()); // Check for any errors found during the scan
delete it;
以下代码用于倒序迭代所有的数据。
for (it->SeekToLast(); it->Valid(); it->Prev())
...
5-快照
快照提供了整个存储数据状态的一致性只读视图。ReadOptions::snapshot如果不为空,则会在指定的数据库状态版本上进行读取。如果ReadOptions::snapshot为空,则会在当前状态隐式地创建一个快照,即在当前快照上进行读取。
leveldb::ReadOptions options;
options.snapshot = db->GetSnapshot();
... apply some updates to db ...
leveldb::Iterator* iter = db->NewIterator(options);
... read using iter to view the state when the snapshot was created ...
delete iter;
db->ReleaseSnapshot(options.snapshot);
需要注意当快照不再使用时,需要调用ReleaseSnapshot释放快照,以免需要维护其状态而占用资源。
6-缓存
当block_cache不为空时,最常使用的数据块会进行缓存,这些块是未进行压缩的。使用缓存有利用优化查询性能,尤其是对于频繁查询相同数据的场景。
#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;
7-布隆过滤器
leveldb的查询可能要进行多次磁io,为了减少磁盘IO,提升查询性能,可以开户布隆过滤器。
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;
03-leveldb参数介绍
leveldb的主要参数通过Options设置,其在options.h文件中定义。下面就介绍下其主要参数及含义:
- const Comparator* comparator;比较函数,主要用于key的大小比较。如果传入NULL则使用默认字节序进行比较。
- bool create_if_missing = false;如果数据库不存在,则创建。
- bool error_if_exists = false;如果数据库存在,返回错误。
- bool paranoid_checks = false;如果开启,则在读取数据时进行严格的检查,若发现数据损坏,则立即结束。
- Env* env;用户定义环境,用于文件读写、后台线程等,默认Env::Default()。
- Logger* info_log;日志对象指针,如果传入为空,则使用默认定义的日志对象。
- size_t write_buffer_size = 4 * 1024 * 1024;写缓冲区的大小,对应于memtable的空间大小,会影响并发写入性能,原理部分会进行详细说明。
- int max_open_files = 1000;最大打开文件数,也会关系到tablecache的大小.
- Cache* block_cache = nullptr;data block缓存,如果为nullptr则数据块不进行缓存。
- size_t block_size = 4 * 1024;数据块的大小,默认为4k,一般不需修改。
- int block_restart_interval = 16;重启点的间隔,即每16个key进行前缀压缩。
- size_t max_file_size = 2 * 1024 * 1024;文件最大大小,根据存储数据大小进行调整。
- CompressionType compression = kSnappyCompression;是否对数进行压缩。
- const FilterPolicy* filter_policy = nullptr;布隆过滤器,使用布隆过滤器有利于提高查询效率。
以上只是对参数做简单介绍,对于初学者,如果只是运行个demo,则不用太多理解即可使用。若是在实际项目中使用,则需要根据情况进行设置,以保证其性能等需求。
如果希望对参数充分理解,则需要对leveldb的原理进行深入了解,甚至阅读和分析源码。这对于想要充分利用和改造leveldb是必需的。下一章将会详细讲解leveldb的原理,随着对leveldb原理的深入,这些参数的具体含义也都会迎刃而解。
以上是关于02-leveldb入门—从0开始编译和使用leveldb的主要内容,如果未能解决你的问题,请参考以下文章