classIter; constchar* data_; size_t size_; uint32_t restart_offset_; // Offset in data_ of restart array bool owned_; // Block owns data_[]
其中Iter 是Block的迭代器,我们来看看Iter 是如何实现的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classBlock::Iter : public Iterator { private: const Comparator* const comparator_; constchar* const data_; // underlying block contents, block的内容 uint32_tconst restarts_; // Offset of restart array (list of fixed32) uint32_tconst num_restarts_; // Number of uint32_t entries in restart array
uint32_t current_; // current_ is offset in data_ of current entry. >= restarts_ if !Valid uint32_t restart_index_; // Index of restart block in which current_ falls std::string key_; Slice value_; Status status_; .... ....
boolParseNextKey() { current_ = NextEntryOffset(); constchar* p = data_ + current_; constchar* limit = data_ + restarts_; // Restarts come right after data if (p >= limit) { // No more entries to return. Mark as invalid. current_ = restarts_; restart_index_ = num_restarts_; returnfalse; }
voidPrev() override { assert(Valid()); // Scan backwards to a restart point before current_ constuint32_t original = current_; while (GetRestartPoint(restart_index_) >= original) { if (restart_index_ == 0) { // No more entries current_ = restarts_; restart_index_ = num_restarts_; return; } restart_index_--; }
SeekToRestartPoint(restart_index_); do { // Loop until end of current entry hits the start of original entry } while (ParseNextKey() && NextEntryOffset() < original); }
voidSeek(const Slice& target) override { // Binary search in restart array to find the last restart point // with a key < target uint32_t left = 0; uint32_t right = num_restarts_ - 1; int current_key_compare = 0;
if (Valid()) { // If we're already scanning, use the current position as a starting // point. This is beneficial if the key we're seeking to is ahead of the // current position. current_key_compare = Compare(key_, target); if (current_key_compare < 0) { // key_ is smaller than target left = restart_index_; } elseif (current_key_compare > 0) { right = restart_index_; } else { // We're seeking to the key we're already at. return; } }
while (left < right) { uint32_t mid = (left + right + 1) / 2; uint32_t region_offset = GetRestartPoint(mid); uint32_t shared, non_shared, value_length; constchar* key_ptr = DecodeEntry(data_ + region_offset, data_ + restarts_, &shared, &non_shared, &value_length); if (key_ptr == nullptr || (shared != 0)) { CorruptionError(); return; } Slice mid_key(key_ptr, non_shared); if (Compare(mid_key, target) < 0) { // Key at "mid" is smaller than "target". Therefore all // blocks before "mid" are uninteresting. left = mid; } else { // Key at "mid" is >= "target". Therefore all blocks at or // after "mid" are uninteresting. right = mid - 1; } }
// We might be able to use our current position within the restart block. // This is true if we determined the key we desire is in the current block // and is after than the current key. assert(current_key_compare == 0 || Valid()); bool skip_seek = left == restart_index_ && current_key_compare < 0; if (!skip_seek) { SeekToRestartPoint(left); } // Linear search (within restart block) for first key >= target while (true) { if (!ParseNextKey()) { return; } if (Compare(key_, target) >= 0) { return; } } }