前面的例子使用了按照字典序的默认排序函数对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) 保持 comparator
的name
不变,(b) 给新的key
增加版本号,(c) 改变比较器函数,使得它可以通过key
里的版本号来决定如何解释它们。