|
@ -58,7 +58,7 @@ std::string IntSetToString(const std::set& s) { |
|
|
Version::~Version() { |
|
|
Version::~Version() { |
|
|
assert(refs_ == 0); |
|
|
assert(refs_ == 0); |
|
|
for (int level = 0; level < config::kNumLevels; level++) { |
|
|
for (int level = 0; level < config::kNumLevels; level++) { |
|
|
for (size_t i = 0; i < files_[level].size(); i++) { |
|
|
|
|
|
|
|
|
for (int i = 0; i < files_[level].size(); i++) { |
|
|
FileMetaData* f = files_[level][i]; |
|
|
FileMetaData* f = files_[level][i]; |
|
|
assert(f->refs >= 0); |
|
|
assert(f->refs >= 0); |
|
|
f->refs--; |
|
|
f->refs--; |
|
@ -134,7 +134,7 @@ class Version::LevelFileNumIterator : public Iterator { |
|
|
private: |
|
|
private: |
|
|
const InternalKeyComparator icmp_; |
|
|
const InternalKeyComparator icmp_; |
|
|
const std::vector<FileMetaData*>* const flist_; |
|
|
const std::vector<FileMetaData*>* const flist_; |
|
|
uint32_t index_; |
|
|
|
|
|
|
|
|
int index_; |
|
|
|
|
|
|
|
|
// Backing store for value(). Holds the file number and size.
|
|
|
// Backing store for value(). Holds the file number and size.
|
|
|
mutable char value_buf_[16]; |
|
|
mutable char value_buf_[16]; |
|
@ -164,7 +164,7 @@ Iterator* Version::NewConcatenatingIterator(const ReadOptions& options, |
|
|
void Version::AddIterators(const ReadOptions& options, |
|
|
void Version::AddIterators(const ReadOptions& options, |
|
|
std::vector<Iterator*>* iters) { |
|
|
std::vector<Iterator*>* iters) { |
|
|
// Merge all level zero files together since they may overlap
|
|
|
// Merge all level zero files together since they may overlap
|
|
|
for (size_t i = 0; i < files_[0].size(); i++) { |
|
|
|
|
|
|
|
|
for (int i = 0; i < files_[0].size(); i++) { |
|
|
iters->push_back( |
|
|
iters->push_back( |
|
|
vset_->table_cache_->NewIterator( |
|
|
vset_->table_cache_->NewIterator( |
|
|
options, files_[0][i]->number, files_[0][i]->file_size)); |
|
|
options, files_[0][i]->number, files_[0][i]->file_size)); |
|
@ -201,7 +201,7 @@ std::string Version::DebugString() const { |
|
|
AppendNumberTo(&r, level); |
|
|
AppendNumberTo(&r, level); |
|
|
r.push_back(':'); |
|
|
r.push_back(':'); |
|
|
const std::vector<FileMetaData*>& files = files_[level]; |
|
|
const std::vector<FileMetaData*>& files = files_[level]; |
|
|
for (size_t i = 0; i < files.size(); i++) { |
|
|
|
|
|
|
|
|
for (int i = 0; i < files.size(); i++) { |
|
|
r.push_back(' '); |
|
|
r.push_back(' '); |
|
|
AppendNumberTo(&r, files[i]->number); |
|
|
AppendNumberTo(&r, files[i]->number); |
|
|
r.push_back(':'); |
|
|
r.push_back(':'); |
|
@ -232,7 +232,7 @@ class VersionSet::Builder { |
|
|
: vset_(vset) { |
|
|
: vset_(vset) { |
|
|
for (int level = 0; level < config::kNumLevels; level++) { |
|
|
for (int level = 0; level < config::kNumLevels; level++) { |
|
|
const std::vector<FileMetaData*>& files = base->files_[level]; |
|
|
const std::vector<FileMetaData*>& files = base->files_[level]; |
|
|
for (size_t i = 0; i < files.size(); i++) { |
|
|
|
|
|
|
|
|
for (int i = 0; i < files.size(); i++) { |
|
|
FileMetaData* f = files[i]; |
|
|
FileMetaData* f = files[i]; |
|
|
f->refs++; |
|
|
f->refs++; |
|
|
files_[level].insert(std::make_pair(f->number, f)); |
|
|
files_[level].insert(std::make_pair(f->number, f)); |
|
@ -258,7 +258,7 @@ class VersionSet::Builder { |
|
|
// Apply all of the edits in *edit to the current state.
|
|
|
// Apply all of the edits in *edit to the current state.
|
|
|
void Apply(VersionEdit* edit) { |
|
|
void Apply(VersionEdit* edit) { |
|
|
// Update compaction pointers
|
|
|
// Update compaction pointers
|
|
|
for (size_t i = 0; i < edit->compact_pointers_.size(); i++) { |
|
|
|
|
|
|
|
|
for (int i = 0; i < edit->compact_pointers_.size(); i++) { |
|
|
const int level = edit->compact_pointers_[i].first; |
|
|
const int level = edit->compact_pointers_[i].first; |
|
|
vset_->compact_pointer_[level] = |
|
|
vset_->compact_pointer_[level] = |
|
|
edit->compact_pointers_[i].second.Encode().ToString(); |
|
|
edit->compact_pointers_[i].second.Encode().ToString(); |
|
@ -284,13 +284,19 @@ class VersionSet::Builder { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Add new files
|
|
|
// Add new files
|
|
|
for (size_t i = 0; i < edit->new_files_.size(); i++) { |
|
|
|
|
|
|
|
|
for (int i = 0; i < edit->new_files_.size(); i++) { |
|
|
const int level = edit->new_files_[i].first; |
|
|
const int level = edit->new_files_[i].first; |
|
|
FileMetaData* f = new FileMetaData(edit->new_files_[i].second); |
|
|
FileMetaData* f = new FileMetaData(edit->new_files_[i].second); |
|
|
f->refs = 1; |
|
|
f->refs = 1; |
|
|
assert(files_[level].count(f->number) == 0); |
|
|
assert(files_[level].count(f->number) == 0); |
|
|
files_[level].insert(std::make_pair(f->number, f)); |
|
|
files_[level].insert(std::make_pair(f->number, f)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Add large value refs
|
|
|
|
|
|
for (int i = 0; i < edit->large_refs_added_.size(); i++) { |
|
|
|
|
|
const VersionEdit::Large& l = edit->large_refs_added_[i]; |
|
|
|
|
|
vset_->RegisterLargeValueRef(l.large_ref, l.fnum, l.internal_key); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// Save the current state in *v.
|
|
|
// Save the current state in *v.
|
|
@ -539,7 +545,7 @@ Status VersionSet::Recover() { |
|
|
|
|
|
|
|
|
static int64_t TotalFileSize(const std::vector<FileMetaData*>& files) { |
|
|
static int64_t TotalFileSize(const std::vector<FileMetaData*>& files) { |
|
|
int64_t sum = 0; |
|
|
int64_t sum = 0; |
|
|
for (size_t i = 0; i < files.size(); i++) { |
|
|
|
|
|
|
|
|
for (int i = 0; i < files.size(); i++) { |
|
|
sum += files[i]->file_size; |
|
|
sum += files[i]->file_size; |
|
|
} |
|
|
} |
|
|
return sum; |
|
|
return sum; |
|
@ -604,12 +610,25 @@ Status VersionSet::WriteSnapshot(log::Writer* log) { |
|
|
// Save files
|
|
|
// Save files
|
|
|
for (int level = 0; level < config::kNumLevels; level++) { |
|
|
for (int level = 0; level < config::kNumLevels; level++) { |
|
|
const std::vector<FileMetaData*>& files = current_->files_[level]; |
|
|
const std::vector<FileMetaData*>& files = current_->files_[level]; |
|
|
for (size_t i = 0; i < files.size(); i++) { |
|
|
|
|
|
|
|
|
for (int i = 0; i < files.size(); i++) { |
|
|
const FileMetaData* f = files[i]; |
|
|
const FileMetaData* f = files[i]; |
|
|
edit.AddFile(level, f->number, f->file_size, f->smallest, f->largest); |
|
|
edit.AddFile(level, f->number, f->file_size, f->smallest, f->largest); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Save large value refs
|
|
|
|
|
|
for (LargeValueMap::const_iterator it = large_value_refs_.begin(); |
|
|
|
|
|
it != large_value_refs_.end(); |
|
|
|
|
|
++it) { |
|
|
|
|
|
const LargeValueRef& ref = it->first; |
|
|
|
|
|
const LargeReferencesSet& pointers = it->second; |
|
|
|
|
|
for (LargeReferencesSet::const_iterator j = pointers.begin(); |
|
|
|
|
|
j != pointers.end(); |
|
|
|
|
|
++j) { |
|
|
|
|
|
edit.AddLargeValueRef(ref, j->first, j->second); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
std::string record; |
|
|
std::string record; |
|
|
edit.EncodeTo(&record); |
|
|
edit.EncodeTo(&record); |
|
|
return log->AddRecord(record); |
|
|
return log->AddRecord(record); |
|
@ -632,7 +651,7 @@ Status VersionSet::SortLevel(Version* v, uint64_t level) { |
|
|
|
|
|
|
|
|
if (result.ok() && level > 0) { |
|
|
if (result.ok() && level > 0) { |
|
|
// There should be no overlap
|
|
|
// There should be no overlap
|
|
|
for (size_t i = 1; i < v->files_[level].size(); i++) { |
|
|
|
|
|
|
|
|
for (int i = 1; i < v->files_[level].size(); i++) { |
|
|
const InternalKey& prev_end = v->files_[level][i-1]->largest; |
|
|
const InternalKey& prev_end = v->files_[level][i-1]->largest; |
|
|
const InternalKey& this_begin = v->files_[level][i]->smallest; |
|
|
const InternalKey& this_begin = v->files_[level][i]->smallest; |
|
|
if (icmp_.Compare(prev_end, this_begin) >= 0) { |
|
|
if (icmp_.Compare(prev_end, this_begin) >= 0) { |
|
@ -657,7 +676,7 @@ uint64_t VersionSet::ApproximateOffsetOf(Version* v, const InternalKey& ikey) { |
|
|
uint64_t result = 0; |
|
|
uint64_t result = 0; |
|
|
for (int level = 0; level < config::kNumLevels; level++) { |
|
|
for (int level = 0; level < config::kNumLevels; level++) { |
|
|
const std::vector<FileMetaData*>& files = v->files_[level]; |
|
|
const std::vector<FileMetaData*>& files = v->files_[level]; |
|
|
for (size_t i = 0; i < files.size(); i++) { |
|
|
|
|
|
|
|
|
for (int i = 0; i < files.size(); i++) { |
|
|
if (icmp_.Compare(files[i]->largest, ikey) <= 0) { |
|
|
if (icmp_.Compare(files[i]->largest, ikey) <= 0) { |
|
|
// Entire file is before "ikey", so just add the file size
|
|
|
// Entire file is before "ikey", so just add the file size
|
|
|
result += files[i]->file_size; |
|
|
result += files[i]->file_size; |
|
@ -682,9 +701,83 @@ uint64_t VersionSet::ApproximateOffsetOf(Version* v, const InternalKey& ikey) { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Add in large value files which are references from internal keys
|
|
|
|
|
|
// stored in the table files
|
|
|
|
|
|
//
|
|
|
|
|
|
// TODO(opt): this is O(# large values in db). If this becomes too slow,
|
|
|
|
|
|
// we could store an auxiliary data structure indexed by internal key
|
|
|
|
|
|
for (LargeValueMap::const_iterator it = large_value_refs_.begin(); |
|
|
|
|
|
it != large_value_refs_.end(); |
|
|
|
|
|
++it) { |
|
|
|
|
|
const LargeValueRef& lref = it->first; |
|
|
|
|
|
for (LargeReferencesSet::const_iterator it2 = it->second.begin(); |
|
|
|
|
|
it2 != it->second.end(); |
|
|
|
|
|
++it2) { |
|
|
|
|
|
if (icmp_.Compare(it2->second, ikey.Encode()) <= 0) { |
|
|
|
|
|
// Internal key for large value is before our key of interest
|
|
|
|
|
|
result += lref.ValueSize(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool VersionSet::RegisterLargeValueRef(const LargeValueRef& large_ref, |
|
|
|
|
|
uint64_t fnum, |
|
|
|
|
|
const InternalKey& internal_key) { |
|
|
|
|
|
LargeReferencesSet* refs = &large_value_refs_[large_ref]; |
|
|
|
|
|
bool is_first = refs->empty(); |
|
|
|
|
|
refs->insert(make_pair(fnum, internal_key.Encode().ToString())); |
|
|
|
|
|
return is_first; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void VersionSet::CleanupLargeValueRefs(const std::set<uint64_t>& live_tables) { |
|
|
|
|
|
for (LargeValueMap::iterator it = large_value_refs_.begin(); |
|
|
|
|
|
it != large_value_refs_.end(); |
|
|
|
|
|
) { |
|
|
|
|
|
LargeReferencesSet* refs = &it->second; |
|
|
|
|
|
for (LargeReferencesSet::iterator ref_it = refs->begin(); |
|
|
|
|
|
ref_it != refs->end(); |
|
|
|
|
|
) { |
|
|
|
|
|
if (ref_it->first != log_number_ && // Not in log file
|
|
|
|
|
|
ref_it->first != prev_log_number_ && // Not in prev log
|
|
|
|
|
|
live_tables.count(ref_it->first) == 0) { // Not in a live table
|
|
|
|
|
|
// No longer live: erase
|
|
|
|
|
|
LargeReferencesSet::iterator to_erase = ref_it; |
|
|
|
|
|
++ref_it; |
|
|
|
|
|
refs->erase(to_erase); |
|
|
|
|
|
} else { |
|
|
|
|
|
// Still live: leave this reference alone
|
|
|
|
|
|
++ref_it; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if (refs->empty()) { |
|
|
|
|
|
// No longer any live references to this large value: remove from
|
|
|
|
|
|
// large_value_refs
|
|
|
|
|
|
Log(env_, options_->info_log, "large value is dead: '%s'", |
|
|
|
|
|
LargeValueRefToFilenameString(it->first).c_str()); |
|
|
|
|
|
LargeValueMap::iterator to_erase = it; |
|
|
|
|
|
++it; |
|
|
|
|
|
large_value_refs_.erase(to_erase); |
|
|
|
|
|
} else { |
|
|
|
|
|
++it; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool VersionSet::LargeValueIsLive(const LargeValueRef& large_ref) { |
|
|
|
|
|
LargeValueMap::iterator it = large_value_refs_.find(large_ref); |
|
|
|
|
|
if (it == large_value_refs_.end()) { |
|
|
|
|
|
return false; |
|
|
|
|
|
} else { |
|
|
|
|
|
assert(!it->second.empty()); |
|
|
|
|
|
return true; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
void VersionSet::MaybeDeleteOldVersions() { |
|
|
void VersionSet::MaybeDeleteOldVersions() { |
|
|
// Note: it is important to delete versions in order since a newer
|
|
|
// Note: it is important to delete versions in order since a newer
|
|
|
// version with zero refs may be holding a pointer to a memtable
|
|
|
// version with zero refs may be holding a pointer to a memtable
|
|
@ -700,7 +793,7 @@ void VersionSet::AddLiveFiles(std::set* live) { |
|
|
for (Version* v = oldest_; v != NULL; v = v->next_) { |
|
|
for (Version* v = oldest_; v != NULL; v = v->next_) { |
|
|
for (int level = 0; level < config::kNumLevels; level++) { |
|
|
for (int level = 0; level < config::kNumLevels; level++) { |
|
|
const std::vector<FileMetaData*>& files = v->files_[level]; |
|
|
const std::vector<FileMetaData*>& files = v->files_[level]; |
|
|
for (size_t i = 0; i < files.size(); i++) { |
|
|
|
|
|
|
|
|
for (int i = 0; i < files.size(); i++) { |
|
|
live->insert(files[i]->number); |
|
|
live->insert(files[i]->number); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -717,7 +810,7 @@ int64_t VersionSet::MaxNextLevelOverlappingBytes() { |
|
|
int64_t result = 0; |
|
|
int64_t result = 0; |
|
|
std::vector<FileMetaData*> overlaps; |
|
|
std::vector<FileMetaData*> overlaps; |
|
|
for (int level = 0; level < config::kNumLevels - 1; level++) { |
|
|
for (int level = 0; level < config::kNumLevels - 1; level++) { |
|
|
for (size_t i = 0; i < current_->files_[level].size(); i++) { |
|
|
|
|
|
|
|
|
for (int i = 0; i < current_->files_[level].size(); i++) { |
|
|
const FileMetaData* f = current_->files_[level][i]; |
|
|
const FileMetaData* f = current_->files_[level][i]; |
|
|
GetOverlappingInputs(level+1, f->smallest, f->largest, &overlaps); |
|
|
GetOverlappingInputs(level+1, f->smallest, f->largest, &overlaps); |
|
|
const int64_t sum = TotalFileSize(overlaps); |
|
|
const int64_t sum = TotalFileSize(overlaps); |
|
@ -739,7 +832,7 @@ void VersionSet::GetOverlappingInputs( |
|
|
Slice user_begin = begin.user_key(); |
|
|
Slice user_begin = begin.user_key(); |
|
|
Slice user_end = end.user_key(); |
|
|
Slice user_end = end.user_key(); |
|
|
const Comparator* user_cmp = icmp_.user_comparator(); |
|
|
const Comparator* user_cmp = icmp_.user_comparator(); |
|
|
for (size_t i = 0; i < current_->files_[level].size(); i++) { |
|
|
|
|
|
|
|
|
for (int i = 0; i < current_->files_[level].size(); i++) { |
|
|
FileMetaData* f = current_->files_[level][i]; |
|
|
FileMetaData* f = current_->files_[level][i]; |
|
|
if (user_cmp->Compare(f->largest.user_key(), user_begin) < 0 || |
|
|
if (user_cmp->Compare(f->largest.user_key(), user_begin) < 0 || |
|
|
user_cmp->Compare(f->smallest.user_key(), user_end) > 0) { |
|
|
user_cmp->Compare(f->smallest.user_key(), user_end) > 0) { |
|
@ -759,7 +852,7 @@ void VersionSet::GetRange(const std::vector& inputs, |
|
|
assert(!inputs.empty()); |
|
|
assert(!inputs.empty()); |
|
|
smallest->Clear(); |
|
|
smallest->Clear(); |
|
|
largest->Clear(); |
|
|
largest->Clear(); |
|
|
for (size_t i = 0; i < inputs.size(); i++) { |
|
|
|
|
|
|
|
|
for (int i = 0; i < inputs.size(); i++) { |
|
|
FileMetaData* f = inputs[i]; |
|
|
FileMetaData* f = inputs[i]; |
|
|
if (i == 0) { |
|
|
if (i == 0) { |
|
|
*smallest = f->smallest; |
|
|
*smallest = f->smallest; |
|
@ -802,7 +895,7 @@ Iterator* VersionSet::MakeInputIterator(Compaction* c) { |
|
|
if (!c->inputs_[which].empty()) { |
|
|
if (!c->inputs_[which].empty()) { |
|
|
if (c->level() + which == 0) { |
|
|
if (c->level() + which == 0) { |
|
|
const std::vector<FileMetaData*>& files = c->inputs_[which]; |
|
|
const std::vector<FileMetaData*>& files = c->inputs_[which]; |
|
|
for (size_t i = 0; i < files.size(); i++) { |
|
|
|
|
|
|
|
|
for (int i = 0; i < files.size(); i++) { |
|
|
list[num++] = table_cache_->NewIterator( |
|
|
list[num++] = table_cache_->NewIterator( |
|
|
options, files[i]->number, files[i]->file_size); |
|
|
options, files[i]->number, files[i]->file_size); |
|
|
} |
|
|
} |
|
@ -834,7 +927,7 @@ Compaction* VersionSet::PickCompaction() { |
|
|
c->input_version_->Ref(); |
|
|
c->input_version_->Ref(); |
|
|
|
|
|
|
|
|
// Pick the first file that comes after compact_pointer_[level]
|
|
|
// Pick the first file that comes after compact_pointer_[level]
|
|
|
for (size_t i = 0; i < current_->files_[level].size(); i++) { |
|
|
|
|
|
|
|
|
for (int i = 0; i < current_->files_[level].size(); i++) { |
|
|
FileMetaData* f = current_->files_[level][i]; |
|
|
FileMetaData* f = current_->files_[level][i]; |
|
|
if (compact_pointer_[level].empty() || |
|
|
if (compact_pointer_[level].empty() || |
|
|
icmp_.Compare(f->largest.Encode(), compact_pointer_[level]) > 0) { |
|
|
icmp_.Compare(f->largest.Encode(), compact_pointer_[level]) > 0) { |
|
@ -969,7 +1062,7 @@ bool Compaction::IsTrivialMove() const { |
|
|
|
|
|
|
|
|
void Compaction::AddInputDeletions(VersionEdit* edit) { |
|
|
void Compaction::AddInputDeletions(VersionEdit* edit) { |
|
|
for (int which = 0; which < 2; which++) { |
|
|
for (int which = 0; which < 2; which++) { |
|
|
for (size_t i = 0; i < inputs_[which].size(); i++) { |
|
|
|
|
|
|
|
|
for (int i = 0; i < inputs_[which].size(); i++) { |
|
|
edit->DeleteFile(level_ + which, inputs_[which][i]->number); |
|
|
edit->DeleteFile(level_ + which, inputs_[which][i]->number); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |