比较器 - Comparators

前面的例子使用了按照字典序的默认排序函数对key进行排序。然而,你也可以在打开一个数据库时为其提供一个自定义的比较器。例如,假设数据库的每个key由两个数字著称,我们应该先按照第一个数字排序,如果相等再按照第二个数字进行排序。首先,定义一个满足如下规则的leveldb::Conmparator的子类:

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

向后兼容性 - Backwards compatibility

比较器的Name方法的返回值将会在数据库创建时与之绑定,并且在以后每次打开数据库的时候进行检查。如果name发生变化,那么leveldb::DB::Open将会调用失败。因此,只有在新的key格式及比较函数和现在的数据库不兼容时才需要修改name,同时所有现有的数据库数据将会被丢弃。

当然,你也可以通过预先的计划来逐步改变你的key格式。例如,你可以在每个key的末尾存储一个版本号(一个字节的应该可以满足大多数用途)。当希望使用一种新的key格式时(比如,给TwoPartComparator增加一个可选的第三块内容),(a) 保持 comparatorname不变,(b) 给新的key增加版本号,(c) 改变比较器函数,使得它可以通过key里的版本号来决定如何解释它们。