summaryrefslogtreecommitdiff
path: root/db
diff options
context:
space:
mode:
authorVictor Costan <pwnall@chromium.org>2019-08-28 15:05:07 -0700
committerVictor Costan <pwnall@chromium.org>2019-08-28 15:05:07 -0700
commit21304d41f77990b8edabbdab33b222bd5ceb5f18 (patch)
tree2cbe8825d02e30d48dea0dc74d3ce1307ef908ad /db
parent53e280b56866ac4c90a9f5fcfe02ebdfd4a19832 (diff)
parent5e921896eedf87b0fb06bc8a1fd0991b9ac64131 (diff)
downloadleveldb-21304d41f77990b8edabbdab33b222bd5ceb5f18.tar.gz
Merge pull request #698 from neal-zhu:master
PiperOrigin-RevId: 266001777
Diffstat (limited to 'db')
-rw-r--r--db/version_set.cc130
1 files changed, 53 insertions, 77 deletions
diff --git a/db/version_set.cc b/db/version_set.cc
index b62a2d0..fd5e3ab 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.
@@ -325,99 +324,76 @@ 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();
- Status s;
-
stats->seek_file = nullptr;
stats->seek_file_level = -1;
- FileMetaData* last_file_read = nullptr;
- int last_file_read_level = -1;
- // 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<FileMetaData*> tmp;
- FileMetaData* tmp2;
- for (int level = 0; level < config::kNumLevels; level++) {
- size_t num_files = files_[level].size();
- if (num_files == 0) continue;
+ struct State {
+ Saver saver;
+ GetStats* stats;
+ const ReadOptions* options;
+ Slice ikey;
+ FileMetaData* last_file_read;
+ int last_file_read_level;
- // 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;
+ VersionSet* vset;
+ Status s;
+ bool found;
- 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;
- }
- }
- }
+ static bool Match(void* arg, int level, FileMetaData* f) {
+ State* state = reinterpret_cast<State*>(arg);
- for (uint32_t i = 0; i < num_files; ++i) {
- if (last_file_read != nullptr && 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.
- stats->seek_file = last_file_read;
- stats->seek_file_level = last_file_read_level;
+ state->stats->seek_file = state->last_file_read;
+ state->stats->seek_file_level = state->last_file_read_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);
- if (!s.ok()) {
- return s;
+ state->last_file_read = f;
+ state->last_file_read_level = level;
+
+ state->s = state->vset->table_cache_->Get(*state->options, f->number,
+ f->file_size, state->ikey,
+ &state->saver, SaveValue);
+ if (!state->s.ok()) {
+ state->found = true;
+ return false;
}
- switch (saver.state) {
+ switch (state->saver.state) {
case kNotFound:
- break; // Keep searching in other files
+ return true; // Keep searching in other files
case kFound:
- return s;
+ state->found = true;
+ 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->saver.user_key);
+ state->found = true;
+ return false;
}
}
- }
+ };
+
+ State state;
+ state.found = false;
+ state.stats = stats;
+ state.last_file_read = nullptr;
+ state.last_file_read_level = -1;
+
+ state.options = &options;
+ state.ikey = k.internal_key();
+ state.vset = vset_;
+
+ state.saver.state = kNotFound;
+ state.saver.ucmp = vset_->icmp_.user_comparator();
+ state.saver.user_key = k.user_key();
+ state.saver.value = value;
+
+ ForEachOverlapping(state.saver.user_key, state.ikey, &state, &State::Match);
- return Status::NotFound(Slice()); // Use an empty error message for speed
+ return state.found ? state.s : Status::NotFound(Slice());
}
bool Version::UpdateStats(const GetStats& stats) {