Implement NextAndGetResult() in memtable and level iterator (#7179)

Summary:
NextAndGetResult() is not implemented in memtable and is very simply implemented in level iterator. The result is that for a normal leveled iterator, performance regression will be observed for calling PrepareValue() for most iterator Next(). Mitigate the problem by implementing the function for both iterators. In level iterator, the implementation cannot be perfect as when calling file iterator's SeekToFirst() we don't have information about whether the value is prepared. Fortunately, the first key should not cause a big portion of the CPu.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/7179

Test Plan: Run normal crash test for a while.

Reviewed By: anand1976

Differential Revision: D22783840

fbshipit-source-id: c19f45cdf21b756190adef97a3b66ccde3936e05
main
sdong 4 years ago committed by Facebook GitHub Bot
parent d9d190742c
commit 692f6a3138
  1. 10
      db/memtable.cc
  2. 32
      db/version_set.cc
  3. 7
      table/iterator_wrapper.h

@ -377,6 +377,16 @@ class MemTableIterator : public InternalIterator {
iter_->Next();
valid_ = iter_->Valid();
}
bool NextAndGetResult(IterateResult* result) override {
Next();
bool is_valid = valid_;
if (is_valid) {
result->key = key();
result->may_be_out_of_upper_bound = true;
result->value_prepared = true;
}
return is_valid;
}
void Prev() override {
PERF_COUNTER_ADD(prev_on_memtable_count, 1);
assert(Valid());

@ -970,13 +970,6 @@ class LevelIterator final : public InternalIterator {
void SetFileIterator(InternalIterator* iter);
void InitFileIterator(size_t new_file_index);
// Called by both of Next() and NextAndGetResult(). Force inline.
void NextImpl() {
assert(Valid());
file_iter_.Next();
SkipEmptyFileForward();
}
const Slice& file_smallest_key(size_t file_index) {
assert(file_index < flevel_->num_files);
return flevel_->files[file_index].smallest_key;
@ -1140,15 +1133,26 @@ void LevelIterator::SeekToLast() {
CheckMayBeOutOfLowerBound();
}
void LevelIterator::Next() { NextImpl(); }
void LevelIterator::Next() {
assert(Valid());
file_iter_.Next();
SkipEmptyFileForward();
}
bool LevelIterator::NextAndGetResult(IterateResult* result) {
NextImpl();
bool is_valid = Valid();
if (is_valid) {
result->key = key();
result->may_be_out_of_upper_bound = MayBeOutOfUpperBound();
result->value_prepared = !allow_unprepared_value_;
assert(Valid());
bool is_valid = file_iter_.NextAndGetResult(result);
if (!is_valid) {
SkipEmptyFileForward();
is_valid = Valid();
if (is_valid) {
result->key = key();
result->may_be_out_of_upper_bound = MayBeOutOfUpperBound();
// Ideally, we should return the real file_iter_.value_prepared but the
// information is not here. It would casue an extra PrepareValue()
// for the first key of a file.
result->value_prepared = !allow_unprepared_value_;
}
}
return is_valid;
}

@ -89,6 +89,13 @@ class IteratorWrapperBase {
valid_ = iter_->NextAndGetResult(&result_);
assert(!valid_ || iter_->status().ok());
}
bool NextAndGetResult(IterateResult* result) {
assert(iter_);
valid_ = iter_->NextAndGetResult(&result_);
*result = result_;
assert(!valid_ || iter_->status().ok());
return valid_;
}
void Prev() {
assert(iter_);
iter_->Prev();

Loading…
Cancel
Save