From 6a90bb91ee72642241fdbeefa673f88370c7b245 Mon Sep 17 00:00:00 2001 From: neal-zhu <13126959424@163.com> Date: Tue, 11 Jun 2019 19:16:49 +0800 Subject: [PATCH 1/7] use ForEachOverlapping to impl Get --- db/version_set.cc | 115 ++++++++++++++++++---------------------------- 1 file changed, 45 insertions(+), 70 deletions(-) diff --git a/db/version_set.cc b/db/version_set.cc index b62a2d0..625598d 100644 --- a/db/version_set.cc +++ b/db/version_set.cc @@ -330,94 +330,69 @@ Status Version::Get(const ReadOptions& options, const LookupKey& k, const Comparator* ucmp = vset_->icmp_.user_comparator(); Status s; - stats->seek_file = nullptr; - stats->seek_file_level = -1; - FileMetaData* last_file_read = nullptr; - int last_file_read_level = -1; + struct State { + GetStats* stats; + const ReadOptions* options; + Slice ikey; + Slice user_key; + const Comparator* ucmp; + std::string* value; - // We can search level-by-level since entries never hop across - // levels. Therefore we are guaranteed that if we find data - // in a smaller level, later levels are irrelevant. - std::vector tmp; - FileMetaData* tmp2; - for (int level = 0; level < config::kNumLevels; level++) { - size_t num_files = files_[level].size(); - if (num_files == 0) continue; + VersionSet *vset; + Status s; - // Get the list of files to search in this level - FileMetaData* const* files = &files_[level][0]; - if (level == 0) { - // Level-0 files may overlap each other. Find all files that - // overlap user_key and process them in order from newest to oldest. - tmp.reserve(num_files); - for (uint32_t i = 0; i < num_files; i++) { - FileMetaData* f = files[i]; - if (ucmp->Compare(user_key, f->smallest.user_key()) >= 0 && - ucmp->Compare(user_key, f->largest.user_key()) <= 0) { - tmp.push_back(f); - } - } - if (tmp.empty()) continue; + static bool Match(void* arg, int level, FileMetaData* f) { + State* state = reinterpret_cast(arg); - std::sort(tmp.begin(), tmp.end(), NewestFirst); - files = &tmp[0]; - num_files = tmp.size(); - } else { - // Binary search to find earliest index whose largest key >= ikey. - uint32_t index = FindFile(vset_->icmp_, files_[level], ikey); - if (index >= num_files) { - files = nullptr; - num_files = 0; - } else { - tmp2 = files[index]; - if (ucmp->Compare(user_key, tmp2->smallest.user_key()) < 0) { - // All of "tmp2" is past any data for user_key - files = nullptr; - num_files = 0; - } else { - files = &tmp2; - num_files = 1; - } - } - } - - for (uint32_t i = 0; i < num_files; ++i) { - if (last_file_read != nullptr && stats->seek_file == nullptr) { + if (state->stats->seek_file == nullptr) { // We have had more than one seek for this read. Charge the 1st file. - stats->seek_file = last_file_read; - stats->seek_file_level = last_file_read_level; + state->stats->seek_file = f; + state->stats->seek_file_level = level; } - FileMetaData* f = files[i]; - last_file_read = f; - last_file_read_level = level; - Saver saver; saver.state = kNotFound; - saver.ucmp = ucmp; - saver.user_key = user_key; - saver.value = value; - s = vset_->table_cache_->Get(options, f->number, f->file_size, ikey, - &saver, SaveValue); + saver.ucmp = state->ucmp; + saver.user_key = state->user_key; + saver.value = state->value; + + Status s = state->vset->table_cache_->Get(*state->options, f->number, + f->file_size, state->ikey, + &saver, SaveValue); if (!s.ok()) { - return s; + state->s = s; + return false; } switch (saver.state) { case kNotFound: - break; // Keep searching in other files + return true; // Keep saerching in other files case kFound: - return s; + state->s = s; + return false; case kDeleted: - s = Status::NotFound(Slice()); // Use empty error message for speed - return s; + return false; case kCorrupt: - s = Status::Corruption("corrupted key for ", user_key); - return s; + state->s = Status::Corruption("corrupted key for ", state->user_key); + return false; } } - } + }; - return Status::NotFound(Slice()); // Use an empty error message for speed + stats->seek_file = nullptr; + stats->seek_file_level = -1; + + State state; + state.s = Status::NotFound(Slice()); + state.stats = stats; + state.ikey = ikey; + state.user_key = user_key; + state.ucmp = ucmp; + state.value = value; + state.vset = vset_; + + ForEachOverlapping(user_key, ikey, &state, &State::Match); + + return state.s; } bool Version::UpdateStats(const GetStats& stats) { From 8fa7a937ee8f38d8869357b0f27f120c5c58f4c9 Mon Sep 17 00:00:00 2001 From: neal-zhu <13126959424@163.com> Date: Tue, 11 Jun 2019 20:20:58 +0800 Subject: [PATCH 2/7] fix bug --- db/version_set.cc | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/db/version_set.cc b/db/version_set.cc index 625598d..1c2781e 100644 --- a/db/version_set.cc +++ b/db/version_set.cc @@ -328,7 +328,9 @@ Status Version::Get(const ReadOptions& options, const LookupKey& k, Slice ikey = k.internal_key(); Slice user_key = k.user_key(); const Comparator* ucmp = vset_->icmp_.user_comparator(); - Status s; + + stats->seek_file = nullptr; + stats->seek_file_level = -1; struct State { GetStats* stats; @@ -337,6 +339,8 @@ Status Version::Get(const ReadOptions& options, const LookupKey& k, Slice user_key; const Comparator* ucmp; std::string* value; + FileMetaData *last_file_read; + int last_file_level; VersionSet *vset; Status s; @@ -344,11 +348,13 @@ Status Version::Get(const ReadOptions& options, const LookupKey& k, static bool Match(void* arg, int level, FileMetaData* f) { State* state = reinterpret_cast(arg); - if (state->stats->seek_file == nullptr) { + if (state->last_file_read != nullptr && state->stats->seek_file == nullptr) { // We have had more than one seek for this read. Charge the 1st file. - state->stats->seek_file = f; - state->stats->seek_file_level = level; + state->stats->seek_file = state->last_file_read; + state->stats->seek_file_level = state->last_file_level; } + state->last_file_read = f; + state->last_file_level = level; Saver saver; saver.state = kNotFound; @@ -378,18 +384,18 @@ Status Version::Get(const ReadOptions& options, const LookupKey& k, } }; - stats->seek_file = nullptr; - stats->seek_file_level = -1; - State state; state.s = Status::NotFound(Slice()); state.stats = stats; + state.last_file_read = nullptr; + state.last_file_level = -1; + state.ikey = ikey; state.user_key = user_key; state.ucmp = ucmp; state.value = value; state.vset = vset_; - + ForEachOverlapping(user_key, ikey, &state, &State::Match); return state.s; From 177cd08629883c409f7a01f90f7084bc5518f1ef Mon Sep 17 00:00:00 2001 From: neal-zhu <13126959424@163.com> Date: Tue, 11 Jun 2019 20:30:54 +0800 Subject: [PATCH 3/7] format --- db/version_set.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/db/version_set.cc b/db/version_set.cc index 1c2781e..d10108a 100644 --- a/db/version_set.cc +++ b/db/version_set.cc @@ -328,7 +328,7 @@ Status Version::Get(const ReadOptions& options, const LookupKey& k, Slice ikey = k.internal_key(); Slice user_key = k.user_key(); const Comparator* ucmp = vset_->icmp_.user_comparator(); - + stats->seek_file = nullptr; stats->seek_file_level = -1; @@ -339,16 +339,17 @@ Status Version::Get(const ReadOptions& options, const LookupKey& k, Slice user_key; const Comparator* ucmp; std::string* value; - FileMetaData *last_file_read; + FileMetaData* last_file_read; int last_file_level; - VersionSet *vset; + VersionSet* vset; Status s; static bool Match(void* arg, int level, FileMetaData* f) { State* state = reinterpret_cast(arg); - if (state->last_file_read != nullptr && state->stats->seek_file == nullptr) { + if (state->last_file_read != nullptr && + state->stats->seek_file == nullptr) { // We have had more than one seek for this read. Charge the 1st file. state->stats->seek_file = state->last_file_read; state->stats->seek_file_level = state->last_file_level; @@ -371,7 +372,7 @@ Status Version::Get(const ReadOptions& options, const LookupKey& k, } switch (saver.state) { case kNotFound: - return true; // Keep saerching in other files + return true; // Keep saerching in other files case kFound: state->s = s; return false; @@ -395,7 +396,7 @@ Status Version::Get(const ReadOptions& options, const LookupKey& k, state.ucmp = ucmp; state.value = value; state.vset = vset_; - + ForEachOverlapping(user_key, ikey, &state, &State::Match); return state.s; From f668239bb262609146496b854e1ec3cea9cd1a83 Mon Sep 17 00:00:00 2001 From: neal-zhu <13126959424@163.com> Date: Tue, 11 Jun 2019 20:33:18 +0800 Subject: [PATCH 4/7] remove TODO in Version::ForEachOverlapping --- db/version_set.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/db/version_set.cc b/db/version_set.cc index d10108a..f63f461 100644 --- a/db/version_set.cc +++ b/db/version_set.cc @@ -281,7 +281,6 @@ static bool NewestFirst(FileMetaData* a, FileMetaData* b) { void Version::ForEachOverlapping(Slice user_key, Slice internal_key, void* arg, bool (*func)(void*, int, FileMetaData*)) { - // TODO(sanjay): Change Version::Get() to use this function. const Comparator* ucmp = vset_->icmp_.user_comparator(); // Search level-0 in order from newest to oldest. From 76ca1162768e5c89f1a49946a1f286c702ae27ae Mon Sep 17 00:00:00 2001 From: neal-zhu <13126959424@163.com> Date: Wed, 12 Jun 2019 05:58:00 +0800 Subject: [PATCH 5/7] fix bug(uninitialized options pointer in State) --- db/version_set.cc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/db/version_set.cc b/db/version_set.cc index f63f461..932b861 100644 --- a/db/version_set.cc +++ b/db/version_set.cc @@ -327,7 +327,6 @@ Status Version::Get(const ReadOptions& options, const LookupKey& k, Slice ikey = k.internal_key(); Slice user_key = k.user_key(); const Comparator* ucmp = vset_->icmp_.user_comparator(); - stats->seek_file = nullptr; stats->seek_file_level = -1; @@ -339,7 +338,7 @@ Status Version::Get(const ReadOptions& options, const LookupKey& k, const Comparator* ucmp; std::string* value; FileMetaData* last_file_read; - int last_file_level; + int last_file_read_level; VersionSet* vset; Status s; @@ -347,14 +346,15 @@ Status Version::Get(const ReadOptions& options, const LookupKey& k, static bool Match(void* arg, int level, FileMetaData* f) { State* state = reinterpret_cast(arg); - if (state->last_file_read != nullptr && - state->stats->seek_file == nullptr) { + if (state->stats->seek_file == nullptr && + state->last_file_read != nullptr) { // We have had more than one seek for this read. Charge the 1st file. state->stats->seek_file = state->last_file_read; - state->stats->seek_file_level = state->last_file_level; + state->stats->seek_file_level = state->last_file_read_level; } + state->last_file_read = f; - state->last_file_level = level; + state->last_file_read_level = level; Saver saver; saver.state = kNotFound; @@ -388,8 +388,9 @@ Status Version::Get(const ReadOptions& options, const LookupKey& k, state.s = Status::NotFound(Slice()); state.stats = stats; state.last_file_read = nullptr; - state.last_file_level = -1; + state.last_file_read_level = -1; + state.options = &options; state.ikey = ikey; state.user_key = user_key; state.ucmp = ucmp; From 107a75b62c19cce901ce10619b63c4b7acc9a0be Mon Sep 17 00:00:00 2001 From: neal-zhu <13126959424@163.com> Date: Wed, 12 Jun 2019 07:05:00 +0800 Subject: [PATCH 6/7] cache Saver in State object --- db/version_set.cc | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/db/version_set.cc b/db/version_set.cc index 932b861..3ddddf3 100644 --- a/db/version_set.cc +++ b/db/version_set.cc @@ -324,13 +324,11 @@ void Version::ForEachOverlapping(Slice user_key, Slice internal_key, void* arg, Status Version::Get(const ReadOptions& options, const LookupKey& k, std::string* value, GetStats* stats) { - Slice ikey = k.internal_key(); - Slice user_key = k.user_key(); - const Comparator* ucmp = vset_->icmp_.user_comparator(); stats->seek_file = nullptr; stats->seek_file_level = -1; struct State { + Saver saver; GetStats* stats; const ReadOptions* options; Slice ikey; @@ -342,6 +340,7 @@ Status Version::Get(const ReadOptions& options, const LookupKey& k, VersionSet* vset; Status s; + bool found; static bool Match(void* arg, int level, FileMetaData* f) { State* state = reinterpret_cast(arg); @@ -356,50 +355,50 @@ Status Version::Get(const ReadOptions& options, const LookupKey& k, state->last_file_read = f; state->last_file_read_level = level; - Saver saver; - saver.state = kNotFound; - saver.ucmp = state->ucmp; - saver.user_key = state->user_key; - saver.value = state->value; - - Status s = state->vset->table_cache_->Get(*state->options, f->number, + state->s = state->vset->table_cache_->Get(*state->options, f->number, f->file_size, state->ikey, - &saver, SaveValue); - if (!s.ok()) { - state->s = s; + &state->saver, SaveValue); + if (!state->s.ok()) { + state->found = true; return false; } - switch (saver.state) { + switch (state->saver.state) { case kNotFound: return true; // Keep saerching in other files case kFound: - state->s = s; + state->found = true; return false; case kDeleted: return false; case kCorrupt: state->s = Status::Corruption("corrupted key for ", state->user_key); + state->found = true; return false; } } }; State state; - state.s = Status::NotFound(Slice()); + state.found = false; state.stats = stats; state.last_file_read = nullptr; state.last_file_read_level = -1; state.options = &options; - state.ikey = ikey; - state.user_key = user_key; - state.ucmp = ucmp; + state.ikey = k.internal_key(); + state.user_key = k.user_key(); + state.ucmp = vset_->icmp_.user_comparator(); state.value = value; state.vset = vset_; - ForEachOverlapping(user_key, ikey, &state, &State::Match); + state.saver.state = kNotFound; + state.saver.ucmp = state.ucmp; + state.saver.user_key = state.user_key; + state.saver.value = state.value; - return state.s; + ForEachOverlapping(state.user_key, state.ikey, &state, &State::Match); + + return state.found ? state.s : Status::NotFound(Slice()); } bool Version::UpdateStats(const GetStats& stats) { From 5e921896eedf87b0fb06bc8a1fd0991b9ac64131 Mon Sep 17 00:00:00 2001 From: neal-zhu <13126959424@163.com> Date: Wed, 28 Aug 2019 23:43:34 +0800 Subject: [PATCH 7/7] drop fileds in State that are duplicates of fileds in Saver and fix typo --- db/version_set.cc | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/db/version_set.cc b/db/version_set.cc index 3ddddf3..fd5e3ab 100644 --- a/db/version_set.cc +++ b/db/version_set.cc @@ -332,9 +332,6 @@ Status Version::Get(const ReadOptions& options, const LookupKey& k, GetStats* stats; const ReadOptions* options; Slice ikey; - Slice user_key; - const Comparator* ucmp; - std::string* value; FileMetaData* last_file_read; int last_file_read_level; @@ -364,14 +361,15 @@ Status Version::Get(const ReadOptions& options, const LookupKey& k, } switch (state->saver.state) { case kNotFound: - return true; // Keep saerching in other files + return true; // Keep searching in other files case kFound: state->found = true; return false; case kDeleted: return false; case kCorrupt: - state->s = Status::Corruption("corrupted key for ", state->user_key); + state->s = + Status::Corruption("corrupted key for ", state->saver.user_key); state->found = true; return false; } @@ -386,17 +384,14 @@ Status Version::Get(const ReadOptions& options, const LookupKey& k, state.options = &options; state.ikey = k.internal_key(); - state.user_key = k.user_key(); - state.ucmp = vset_->icmp_.user_comparator(); - state.value = value; state.vset = vset_; state.saver.state = kNotFound; - state.saver.ucmp = state.ucmp; - state.saver.user_key = state.user_key; - state.saver.value = state.value; + state.saver.ucmp = vset_->icmp_.user_comparator(); + state.saver.user_key = k.user_key(); + state.saver.value = value; - ForEachOverlapping(state.user_key, state.ikey, &state, &State::Match); + ForEachOverlapping(state.saver.user_key, state.ikey, &state, &State::Match); return state.found ? state.s : Status::NotFound(Slice()); }