mirror of
https://github.com/google/leveldb.git
synced 2024-12-28 04:00:09 +08:00
Merge pull request #698 from neal-zhu:master
PiperOrigin-RevId: 266001777
This commit is contained in:
commit
21304d41f7
@ -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;
|
||||
state->last_file_read = f;
|
||||
state->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->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;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return Status::NotFound(Slice()); // Use an empty error message for speed
|
||||
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 state.found ? state.s : Status::NotFound(Slice());
|
||||
}
|
||||
|
||||
bool Version::UpdateStats(const GetStats& stats) {
|
||||
|
Loading…
Reference in New Issue
Block a user