leveldb:DBIter

来源:互联网 发布:项目管理就业前景知乎 编辑:程序博客网 时间:2024/06/09 23:11

DBIter的作用

Leveldb数据库的MemTable和sstable文件的存储格式都是InternalKey(userkey, seq, type) => uservalue。
DBIter把同一个userkey在DB中的多条记录合并为一条,综合考虑了userkey的序号、删除标记、和写覆盖等等因素。DBIter只会把userkey最新(seq最大的就是最新的,相同userkey的老记录(seq较小的)不会让上层看到)的一条记录展现给用户,另外如果这条最新的记录是删除类型,则会跳过该记录,否则,遍历时会把已删除的key列举出来。

DBIter的实现原理

class DBIter: public Iterator {  enum Direction {    kForward,    kReverse  };private:  DBImpl* db_;  const Comparator* const user_comparator_;//比较iter间userkey  Iterator* const iter_;//是一个MergingIterator  SequenceNumber const sequence_;//DBIter只能访问到比sequence_小的kv对  //这就方便了老版本(快照)数据库的遍历  Status status_;  std::string saved_key_;     //用于方向遍历 direction_==kReverse时才有效  std::string saved_value_;   //用于反向遍历 direction_==kReverse时才有效  Direction direction_;  bool valid_;  Random rnd_;  ssize_t bytes_counter_;}

iter_是DBImpl::NewInternalIterator创建的结果

  std::vector<Iterator*> list;  list.push_back(mem_->NewIterator());//加入memtbale的迭代器  list.push_back(imm_->NewIterator());//加入immemtbale的迭代器  versions_->current()->AddIterators(options, &list);//可以简单理解为加入所以sst文件的迭代器  Iterator* internal_iter =      NewMergingIterator(&internal_comparator_, &list[0], list.size());

iter_是由NewInternalIterator创建的一个MergingIterator,通过MergingIterator可以实现多个有序数据集合的归并操作。其中包含多个child iterator组成的集合。对MergingIterator的遍历会有序的遍历其child iterator中的每个元素。
因为iter_遍历的是数据库的每一条记录。它是以InternalKey(userkey, seq, type)为遍历粒度的,只要InternalKey中任意一个组成元素不同,MergingIterator就认为他们是不同的kv对。
DBIter是以userkey为遍历粒度的,只要记录的userkey相同,那么DBIter就认为他们是一条记录(不同版本),sqe越大代表该记录越新。每次迭代将跳到下一个不同userkey的记录。
这里写图片描述
假设当前DBIter的sequence_为2,那么DBIter只会处理seq小于2的记录,这也是访问快照数据的原理。
图中每个框框表示对应记录的InternalKey(userkey, seq, type),key1 < key2 < key3 < key4,seq越大代表记录越新,所以相同userkey的seq越大的顺序越靠前(小)。

DBIter next的实现

假设iter_现在在key2:2:1的位置,DBIter也在这个位置,此时iter_的next会是key2:1:1。而DBIter的next将会是key4:2:1(因为key3:3:1seq不符,key3:2:0是一条删除记录,因此跳过key3:2:0和key3:1:1,key4:2:1seq不符)。

DBIter prev的实现

假设当前iter在key4:2:1上,direction为kForward。此时调用Prev(),此图显示了Prev操作执行的5个步骤。
这里写图片描述

S1 首先因为direction为kForward,先调整iter到key3:1:1上。此图也说明了调整的理由,key4:2:1前面还有key4:3:1。然后进入FindPrevUserEntry函数,执行S2到S4。
S2 跳到key3:2:0上时,这是一个删除标记,清空saved key(其中保存的是key3:1:1)。
S3 循环继续,跳到key2:1:1上,此时key2:1:1 > saved key,设置saved key为key2:1:1,并继续循环。
S4 循环继续,跳到key2:2:1上,此时key2:2:1 > saved key,设置saved key为key2:2:1,并继续循环。
S5 跳到Key1:1:1上,因为key1:1:1 < saved key,跳出循环。
最终状态iter_位置在key1:1:1上,而saved key保存的则是key2:2:1上,这也就是Prev应该定位到的值。也就是说在Prev操作下,iter_的位置并不是真正的key位置。这就是Get函数中,在direction为kReverse时,返回saved key/value的原因。
同理,在Next时,如果direction是kReverse,根据上面的Prev可以发现,此时iter刚好是saved key的前一个entry。执行iter->Next()就跳到了saved key的dentry范围的sequence最大的那个entry。在前面的例子中,在Prev后执行Next,那么iter首先跳转到key2:3:1上,然后再调用FindNextUserEntry循环,使iter定位在key2:2:1上。

prev的小结

prev就是要向前找到第一个符合条件的kv记录,该记录的userkey必须小于当前iter的userkey,并且该记录是最新的而且不能是删除类型的记录。如何判断出该记录是不是最新的呢,先将该记录保存在save(saved key/value)里,iter_继续向前遍历,如果遇到userkey和刚才save的记录userkey不相等的,则说明刚才save的就是最新的记录,此时iter_的位置并不是真正的key位置,saved key才是真正key的位置,因此需要用Direction来区分。

Direction

1) kForward,正向遍历(向后移动),代码保证此时DBIter的内部迭代器刚好定位在this->key(),this->value()这条记录上;此时iter_一定是在一条最新的记录上(seq最大的记录上(当然seq得小于sequence_))
2) kReverse,反向遍历(向前移动),代码保证此时DBIter的内部迭代器刚好定位在所有key=this->key()的entry之前。此时iter_一定是在一条最老的记录上。
其成员变量savedkey和saved value保存的是KReverse方向移动完成后的k/v对,每次seek系调用之后,其值都会跟随iter_而改变。

代码分析

FindNextUserEntry和FindPrevUserEntry

FindNextUserEntry和FindPrevUserEntry的功能就是循环跳过下一个/前一个delete的记录,直到遇到kValueType的记录。
void DBIter::FindNextUserEntry(bool skipping, std::string* skip)
参数@skipping表明是否要跳过userkey和skip相等的记录;
参数@skip临时存储空间,保存seek时要跳过的key;
在进入FindNextUserEntry时,iter_刚好定位在this->key(), this->value()这条记录上。

//skipping等于true的时候表示要找到向后找到第一个和skip不相等的userkey才行void DBIter::FindNextUserEntry(bool skipping, std::string* skip) {  // Loop until we hit an acceptable entry to yield  assert(iter_->Valid());  assert(direction_ == kForward);  do {    ParsedInternalKey ikey;    if (ParseKey(&ikey) && ikey.sequence <= sequence_) {//跳过不符合sequence_要求的kv对      switch (ikey.type) {        case kTypeDeletion://如果遇到iter userkey的删除操作,则说明后面该userkey都是无效的,因此需要跳过          // Arrange to skip all upcoming entries for this key since          // they are hidden by this deletion.          SaveKey(ikey.user_key, skip);          skipping = true;          break;        case kTypeValue:          if (skipping &&              user_comparator_->Compare(ikey.user_key, *skip) <= 0) {//如果当前key与要跳过的key相等就继续向后            // Entry hidden          } else {            valid_ = true;//如果skipping为true的话,此处iter为第一个不等于save的userkey,而且不是删除类型            saved_key_.clear();            return;          }          break;      }    }    iter_->Next();  } while (iter_->Valid());  saved_key_.clear();  valid_ = false;}

FindNextUserKey移动方向是kForward,DBIter在向kForward移动时,借用了saved key作为临时缓存。FindNextUserKey确保定位到的entry的sequence不会大于指定的sequence,并跳过被删除标记覆盖的旧记录。

void DBIter::FindPrevUserEntry(),在进入FindPrevUserEntry时,iter_刚好位于saved key对应的所有记录之前*FindPrevUserKey根据指定的sequence,依次检查前一个entry,直到遇到user key小于saved key,并且类型不是Delete的entry。*
如果entry的类型是Delete,就清空saved key和saved value,这样在依次遍历前一个entry的循环中,只要类型不是Delete,就是要找的entry。这就是Prev的语义。

void DBIter::FindPrevUserEntry() {  assert(direction_ == kReverse);  ValueType value_type = kTypeDeletion;//这个很关键,后面的循环至少执行一次Prev操作   if (iter_->Valid()) {    do {      ParsedInternalKey ikey;      if (ParseKey(&ikey) && ikey.sequence <= sequence_) {        if ((value_type != kTypeDeletion) &&//第一次是不会进入该分支的,因为进入循环前先把value_type = kTypeDeletion;            user_comparator_->Compare(ikey.user_key, saved_key_) < 0) {          // We encountered a non-deleted value in entries for previous keys,          break;        }     //根据类型,如果是Deletion则清空saved key和saved value        //否则,把iter_的user key和value赋给saved key和saved value          value_type = ikey.type;        if (value_type == kTypeDeletion) {          saved_key_.clear();          ClearSavedValue();        } else {          Slice raw_value = iter_->value();          if (saved_value_.capacity() > raw_value.size() + 1048576) {            std::string empty;            swap(empty, saved_value_);          }//save一直在变,直到遇到iter和save的userkey不一样,说明save是最新的          SaveKey(ExtractUserKey(iter_->key()), &saved_key_);          saved_value_.assign(raw_value.data(), raw_value.size());        }      }      iter_->Prev();    } while (iter_->Valid());  }  if (value_type == kTypeDeletion) {    // End    valid_ = false;    saved_key_.clear();    ClearSavedValue();    direction_ = kForward;  } else {    valid_ = true;  }}

seek

void DBIter::Seek(const Slice& target) {    direction_ = kForward; // 向前seek    // 清空saved value和saved key,并根据target设置saved key    ClearSavedValue();    saved_key_.clear();    AppendInternalKey( // kValueTypeForSeek(1) > kDeleteType(0)        &saved_key_,ParsedInternalKey(target, sequence_, kValueTypeForSeek));    iter_->Seek(saved_key_); // iter seek到saved key    //可以定位到合法的iter,还需要跳过Delete的entry    if (iter_->Valid()) FindNextUserEntry(false,&saved_key_); //是false   else valid_ = false;  }                                                                                                                                         void DBIter::SeekToFirst() {    direction_ = kForward; // 向前seek    // 清空saved value,首先iter_->SeekToFirst,然后跳过Delete的entry    ClearSavedValue();    iter_->SeekToFirst();    if (iter_->Valid()) FindNextUserEntry(false,&saved_key_ /*临时存储*/);    else valid_ = false;  }  void DBIter::SeekToLast() { // 更简单    direction_ = kReverse;    ClearSavedValue();    iter_->SeekToLast();    FindPrevUserEntry();  }  

参考:http://blog.csdn.net/sparkliang/article/details/16968487

原创粉丝点击