打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
LevelDB源码剖析之snapshot原理 | 赖明星
userphoto

2014.03.25

关注

注意:本文转载自小和尚的藏经阁,无任何修改。

Snapshot(快照)关于指定数据集合的一个完全可用拷贝,该拷贝包括相应数据在某个时间点(拷贝开始的时间点)的映像。快照可以是其所表示的数据的一个副本,也可以是数据的一个复制品。

快照的作用主要是能够进行在线数据备份与恢复1

leveldb也提供了快照。对于整个key-value存储状态,Snapshot提供了一致性只读视图。ReadOptions::snapshot不为NULL时表示读取数据库的某一个特定版本。如果Snapshot为NULL,则读取数据库的当前版本。

通常Snapshots通过方法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);

注意,当snapshot不再使用时,需要用DB::RealeaseSnapshot释放。这样底层就可以释放支持Snapshot的资源。

写操作也可以返回一个应用了一系列更新之后的Snapshot:

leveldb::Snapshot* snapshot;leveldb::WriteOptions write_options;write_options.post_write_snapshot = &snapshot;leveldb::Status status = db->Write(write_options, ...);... perform other mutations to db ...leveldb::ReadOptions read_options;read_options.snapshot = snapshot;leveldb::Iterator* iter =db->NewIterator(read_options);... read as of the state just after the Write call returned ...delete iter;db->ReleaseSnapshot(snapshot);

leveldb中的Snapshot是如何实现的呢?

我们知道leveldb是只增加的数据库,在一定的时间范围内leveldb并不删除数据,它记录了所有的操作。比如:

  table["liming"] = 18  del table["liming"]  table["wangdong"] = 85  table["wangdong"] = 30

转换成leveldb内部操作为:

  liming 1 kTypeValue     : 18  liming 2 kTypeDeletion  wandong 3 ktypeValue    : 85  wandong 4 kTypeValue    : 30

内部按照key非递减,sequence非递增,kTypeValue非递增排序(保证kTypeDeletion在前面)进行排序(存储在SkipList中),那么在这些数据在skiplist中为:

  //userkey sequence type : value  liming 2 kTypeDeletion  liming 1 kTypeValue     : 18  wandong 4 kTypeValue    : 30  wandong 3 ktypeValue    : 85

这时我们获得了快照号4(最后更新的sequence号),我们只读取seqence <= 4的元素,如果查找table["wandong"], 那么找到wandong 4 kTypeValue : 30,可以获得table["wandong"]为 30,我们只取sequence最大的值作为数据的最新状态(自动忽略wandong 3 ktypeValue : 85), 如果查找table["liming"],找到liming的最新数据liming 2 kTypeDeletion,表示已经删掉了liming,则数据库中没有liming'.

如果之后又有更新比如:

  table["liming"] = 19  table["wandong"]= 21  table["jim"] = 30

这时skiplist中的内容变为:

  liming 5 kTypeValue     : 19  liming 2 kTypeDeletion  liming 1 kTypeValue     : 18  jim    7 kTypeValue     : 30  wandong 6 kTypeValue    : 21  wandong 4 kTypeValue    : 30  wandong 3 ktypeValue    : 85

这时我们查找table["liming"], 由于我们指读取sequence <= 4的数据所以我们会自动忽略新插入的元素liming 5 kTypeValue : 19', jim 7 kTypeValue : 30,wandong 6 kTypeValue : 21, 所以我们snapshot为4时,数据库中仍没有liming, table["wandong"] 为 30.

另外LevelDb中的SkipList中的指针为AtomicPointer,对它的读写操作是原子的。多线程写需要在外部加锁,因此最多只有一个线程写SkipList,

但是多个线程可以不用加锁并发的读取SkipList,Snapshot不关心新插入的key-value(因为他们的sequence>snapshot的sequence编号)。线程写SkipList的时候,仍然可以多线程读SkipList,并不会有问题。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
LevelDB设计与实现
详解LSM Tree
(玩命snapshot)甘正噶黑絲,你扯左未?
考研英语作文应用文对策
如何让SELECT 查询结果额外增加自动递增序号
【技术综述】深度学习新手如何开始合适的“调参”任务
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服