LevelDB 介绍

GitHub
https://github.com/google/leveldb
https://rawgit.com/google/leveldb/master/doc/index.html

关于BigTable:
http://blog.csdn.net/opennaive/article/details/7532589
http://jimbojw.com/wiki/index.php?title=Understanding_Hbase_and_BigTable

关于Bloom过滤:
https://en.wikipedia.org/wiki/Bloom_filter
http://iluoxuan.iteye.com/blog/1718254 (推荐)

分析
http://www.cnblogs.com/haippy/archive/2011/12/04/2276064.html
http://www.samecity.com/blog/Index.asp?SortID=12 (推荐)

介绍

LevelDB是Google开发的一个持久化的键值对儿数据库。Google Chrome等产品使用了它。它支持使用任意的字节数组作为key和value,可以使用用户自定义的比较函数对key进行排序。不仅允许单次执行get、put和delete操作,也允许批量的put和delete,双向迭代器,使用非常快速的Snappy算法进行压缩。

编译使用

$ git clone https://github.com/google/leveldb.git
$ cd leveldb
$ make

编译完成后,生成了leveldb/out-static/libleveldb.a,这是一个静态链接库。而在leveldb/out-shared中是共享库。

测试程序:

#include <iostream>
#include <cassert>
#include "leveldb/db.h"

int main()
{
    // open a db
    leveldb::DB* db;
    leveldb::Options options;
    options.create_if_missing = true;
    leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
    assert(status.ok());

    // read write
    std::string key1("name");
    std::string value1("hongjin"), valueReadBack;
    leveldb::Status s = db->Put(leveldb::WriteOptions(), key1, value1);
    if (s.ok()) 
    {
        s = db->Get(leveldb::ReadOptions(), key1, &valueReadBack);
        std::cout << valueReadBack << std::endl;
    }

    // close db
    delete db;
    return 0;
}

编译方法:

$ g++ -Wall testleveldb.cpp -I leveldb/include/ leveldb/out-static/libleveldb.a -lpthread 

Slice

上面的it->key() 和 it->value()的返回值类型是leveldb::Slice。Slice包含的数据成员只有两个:一个指向数据的指针和一个表示数据长度的整形变量。并没有使用std::string作为返回值,文档给出的理由是使用Slice可以避免数据的复制。

但是注意,在使用Slice时,Slice指向的数据必须由调用者保证数据的有效性,像下面这样的代码是有bug的:


   leveldb::Slice slice;
   if (...) {
     std::string str = ...;
     slice = str;
   }
   Use(slice); // bug

slice中的指针指向了str的数据,但是str被析构后,slice的指针就不能再使用了。

Comparators

用于排序的默认Comparators是按照字典序进行排序(lexicographically)。用户可以自定义比较器。

下面这个自定义的比较器将key/value解析成数字进行排序:

  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);
  ...

Block size

leveldb将相邻的key放到同一个block中,而block是读写到持续存储介质的基本单位。block的默认大小是4096字节(未压缩)。

经常对数据库进行大块数据操作的程序可能会希望增加block size;但是对于每次仅仅读取一小块数据的程序来说,通常希望减小block size。

Compression

每个block在被写到存储介质上之前要被压缩。压缩是默认开启的,因为默认的压缩方法很快(>_<)。同时不会对不可压缩数据进行压缩。除非禁止压缩后bench的结果有提升,否则不要完全禁止压缩。

禁止压缩:

  leveldb::Options options;
  options.compression = leveldb::kNoCompression;
  ... leveldb::DB::Open(options, name, ...) ....

Cache

数据库的数据被存储在文件系统中的一组文件中,而每个文件存储了一系列的经过压缩的block。

可以设置options.cache,来缓存(cache)经常被使用的block(缓存的是未压缩的数据)

  #include "leveldb/cache.h"

  leveldb::Options options;
  options.cache = leveldb::NewLRUCache(100 * 1048576);  // 100MB cache
  leveldb::DB* db;
  leveldb::DB::Open(options, name, &db);
  ... use the db ...
  delete db
  delete options.cache;

当读取一大块数据时,可以使用options.fill_cache = false来禁止缓存被覆盖。

  leveldb::ReadOptions options;
  options.fill_cache = false;
  leveldb::Iterator* it = db->NewIterator(options);
  for (it->SeekToFirst(); it->Valid(); it->Next()) {
    ...
  }

Filters

leveldb中的相邻key被存在一个block中,而多个block被存储在磁盘上的文件里面。这种组织形式会导致Get()操作会执行多次磁盘读操作。可以使用FilterPolicy(过滤器策略)来减少对磁盘的读操作。

   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;

Bloom Filter

关于Bloom过滤,请参考下面的文章

https://en.wikipedia.org/wiki/Bloom_filter
http://iluoxuan.iteye.com/blog/1718254 (推荐)

此外,如果你自定义了比较器,请保证你使用的过滤策略与比较器是兼容的。

Checksums

leveldb存储在磁盘上的数据都有一个校验和。

  • ReadOptions::verify_checksums 设置为true来开启从文件系统读数据时进行校验,默认是关闭的。
  • Options::paranoid_checks 打开数据库之前,将此项设置为true,会让leveldb检测到一个 internal corruption时raise an error。默认是关闭的,这样做可是在一部分存储出错时让数据库仍然可用。

Approximate Sizes

GetApproximateSizes 方法可以用来得到key range在所文件系统中占用的空间大小。

   leveldb::Range ranges[2];
   ranges[0] = leveldb::Range("a", "c");
   ranges[1] = leveldb::Range("x", "z");
   uint64_t sizes[2];
   leveldb::Status s = db->GetApproximateSizes(ranges, 2, sizes);

sizes[0] 是 key range [a..c) 所占用的大小。
sizes[1] 是 key range [x..z) 所占用的大小。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值