比较器 - Comparators

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

  1. class TwoPartComparator : public leveldb::Comparator {
  2. public:
  3. // Three-way comparison function:
  4. // if a < b: negative result
  5. // if a > b: positive result
  6. // else: zero result
  7. int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const {
  8. int a1, a2, b1, b2;
  9. ParseKey(a, &a1, &a2);
  10. ParseKey(b, &b1, &b2);
  11. if (a1 < b1) return -1;
  12. if (a1 > b1) return +1;
  13. if (a2 < b2) return -1;
  14. if (a2 > b2) return +1;
  15. return 0;
  16. }
  17. // Ignore the following methods for now:
  18. const char* Name() const { return "TwoPartComparator"; }
  19. void FindShortestSeparator(std::string*, const leveldb::Slice&) const { }
  20. void FindShortSuccessor(std::string*) const { }
  21. };

现在使用这个自定义的比较器创建数据库:

  1. TwoPartComparator cmp;
  2. leveldb::DB* db;
  3. leveldb::Options options;
  4. options.create_if_missing = true;
  5. options.comparator = &cmp;
  6. leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
  7. ...

向后兼容性 - Backwards compatibility

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

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