并发/迭代/快照

并发 - Concurrency

一个数据库在同一时间内只能由一个进程打开,leveldb通过从操作系统中获取锁的方式防止误用。在单个进程中,同一个leveldb::DB对象可以安全的由多个并发线程共享使用。即,不同的线程可以同时写入或获取迭代器,或在没有任何外部同步的情况在同一数据库上调用Getleveldb的实现过程中将自动自行所需的同步)。但是其他对象(如IteratorWriteBatch)可能需要外部同步。如果两个线程共享这样的对象,它们必须使用自己的协议锁来保护自己的访问。更多详细的细节在公共的头文件中描述。

迭代 - Iteration

下面的例子演示了如何从数据库中成对的打印键值:

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可能是non-NULL,表示读取操作在特定的DB版本状态上进行的。如果ReadOptions::snapshotNULL,则读取操作将在当前状态上进行隐式的快照操作。

快照是通过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接口释放它。这样既可以让底层实现丢弃那些为支持该快照的读取操作而进行维护的一些状态数据。