leveldb

原文地址http://leveldb.googlecode.com/svn/trunk/doc/index.html

特征:

1. 高效的kv持久化存储系统,key为任意字节的数组,顺序读写的qps可达几百K;

2. 数据按key 有序存储, 支持自定义比较函数;

3. 支持数据压缩,默认为snappy 压缩;

4. 支持前向后向迭代器


打开一个数据库:

      一个leveldb数据库有一个对应存储目录的名字,所有数据都存储在这个目录下。下面的例子展示了如何打开一个数据库,如果目录不存在就创建它:

  #include <assert>
  #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());
  ...
如果你想在目录存在的情况下报错,如何设置options:
   options.error_if_exists = true;
Status:
   绝大多数function 会返回类型为leveldb::Status的值,你可以检查返回值判断函数是否出错,还可以打印出错信息:
   leveldb::Status s = ...;
       if (!s.ok()) cerr << s.ToString() << endl;
关闭一个数据库
     完成对数据库的操作后,调用一下操作关闭一个数据库:   
    delete db;
读写操作
   数据库提供了Put,Delete和Get方法来修改和查询数据库。下面的例子把key1的值移动到key2下.
  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);
原子更新
注意,上面的操作如果在Put key2后挂掉,相同的值就会存储在多个key中。这种问题可以通过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);
  }
WriteBatch 包含一系列操作,这些操作会按顺序执行。注意我们先调用Delete,在调用Put,这可以避免在key1==key2时,value被错误地删掉。
除了原子性外,WriteBatch 也可以通过把多个单个的操作组成批量操作来加快速度。
同步写机制
   默认情况,leveldb是异步写:操作提交给操作系统后返回。由操作系统内存写入底层持久化存储异步进行。可以打开sync标签,可以是写操作写入持久化存储后返回。(在Posix系统上,通过调用fsync() or fdatasync() or msync()实现)
  leveldb::WriteOptions write_options;
  write_options.sync = true;
  db->Put(write_options, ...);
异步写会比同步写快1000倍。异步写的负面是当机器crash是会丢失最近的几个操作。注意如果是进程crash不会造成任何数据丢失,数据已经由进程内存写入操作系统内存。
异步写通常是安全的。例如当load大量数据到数据时,你可以通过重启批量load来解决crash时的更新丢失问题。一种混合的方案也是可行的,每n次执行一次同步写,当crash时,从最后一次同步写后执行批量load重启,同步写会更新一个标记,用来描述crash是的重启位置。
批量写是另一种代替异步写的机制。多次更新可以通过一个批量操作完成,使用同步写。同步写的额外消耗被分摊到多次写上。
并发
一个数据库同一时间只能被一个进程打开。leveldb会从系统中请求一个锁,防止数据库被滥用。在一个进程中,相同的DB对象可以被多个并发线程安全共享。不同的线程可以写入或者获得迭代器或者调用Get在同一个数据库上,而不需要同步(leveldb会自动进行同步)。但是其他对象,比如Iterator和writeBatch需要额外的同步。如果两个线程共享这样的对象,他们必须用自己的加锁协议来保护对他们的访问。
Iteration
   下面展示如何遍历数据库中的kv对:
   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;
下面展示如何访问 [start,limit)间的内容:

  for (it->Seek(start);
       it->Valid() && it->key().ToString() < limit;
       it->Next()) {
    ...
  }
你也可以逆序遍历数据库中的内容

  for (it->SeekToLast(); it->Valid(); it->Prev()) {
    ...
  }
Snapshots:
 快照提供了一致性只读视图。Readoptions::snapshot 不为空表示读操作在DB的某个状体进行。如果为空读操作默认为DB的当前状态。
通过DB::GetSnapshot()创建快照:
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);
如果一个快照不需要了,可以通过DB::ReleaseSnapshot 释放。
Slice:
it-key() 和 it->value()的返回值是leveldb::Slice 类型。 Slice是一个包含一个指向字节数据的指针和字节数据长度的简单结构体。返回一个Slice是返回string的廉价替代,避免了复制大的keys和values。另外,leveldb 的方法不返回null结尾的C-style 字符串,因为leveldb允许键和值包含'\0'。

C++ 字符串和C-style 字符串都可以简单的转换为Slice:

   leveldb::Slice s1 = "hello";

   std::string str("world");
   leveldb::Slice s2 = str;
Slice 转换为C++ string:
   std::string str = s1.ToString();
   assert(str == std::string("hello"));
应该确保在使用Slice时,Slice指向的字节数据仍然有效.下面的使用方法是错误的:

   leveldb::Slice slice;
   if (...) {
     std::string str = ...;
     slice = str;
   }
   Use(slice);
当if语句结束时,str会被析构,slice指向的内存也会失效。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值