|
@ -20,21 +20,29 @@ |
|
|
|
|
|
|
|
|
namespace leveldb { |
|
|
namespace leveldb { |
|
|
|
|
|
|
|
|
static const int kTargetFileSize = 2 * 1048576; |
|
|
|
|
|
|
|
|
static int TargetFileSize(const Options* options) { |
|
|
|
|
|
return options->max_file_size; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// Maximum bytes of overlaps in grandparent (i.e., level+2) before we
|
|
|
// Maximum bytes of overlaps in grandparent (i.e., level+2) before we
|
|
|
// stop building a single file in a level->level+1 compaction.
|
|
|
// stop building a single file in a level->level+1 compaction.
|
|
|
static const int64_t kMaxGrandParentOverlapBytes = 10 * kTargetFileSize; |
|
|
|
|
|
|
|
|
static int64_t MaxGrandParentOverlapBytes(const Options* options) { |
|
|
|
|
|
return 10 * TargetFileSize(options); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// Maximum number of bytes in all compacted files. We avoid expanding
|
|
|
// Maximum number of bytes in all compacted files. We avoid expanding
|
|
|
// the lower level file set of a compaction if it would make the
|
|
|
// the lower level file set of a compaction if it would make the
|
|
|
// total compaction cover more than this many bytes.
|
|
|
// total compaction cover more than this many bytes.
|
|
|
static const int64_t kExpandedCompactionByteSizeLimit = 25 * kTargetFileSize; |
|
|
|
|
|
|
|
|
static int64_t ExpandedCompactionByteSizeLimit(const Options* options) { |
|
|
|
|
|
return 25 * TargetFileSize(options); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
static double MaxBytesForLevel(int level) { |
|
|
|
|
|
|
|
|
static double MaxBytesForLevel(const Options* options, int level) { |
|
|
// Note: the result for level zero is not really used since we set
|
|
|
// Note: the result for level zero is not really used since we set
|
|
|
// the level-0 compaction threshold based on number of files.
|
|
|
// the level-0 compaction threshold based on number of files.
|
|
|
double result = 10 * 1048576.0; // Result for both level-0 and level-1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Result for both level-0 and level-1
|
|
|
|
|
|
double result = 10. * 1048576.0; |
|
|
while (level > 1) { |
|
|
while (level > 1) { |
|
|
result *= 10; |
|
|
result *= 10; |
|
|
level--; |
|
|
level--; |
|
@ -42,8 +50,9 @@ static double MaxBytesForLevel(int level) { |
|
|
return result; |
|
|
return result; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static uint64_t MaxFileSizeForLevel(int level) { |
|
|
|
|
|
return kTargetFileSize; // We could vary per level to reduce number of files?
|
|
|
|
|
|
|
|
|
static uint64_t MaxFileSizeForLevel(const Options* options, int level) { |
|
|
|
|
|
// We could vary per level to reduce number of files?
|
|
|
|
|
|
return TargetFileSize(options); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static int64_t TotalFileSize(const std::vector<FileMetaData*>& files) { |
|
|
static int64_t TotalFileSize(const std::vector<FileMetaData*>& files) { |
|
@ -508,7 +517,7 @@ int Version::PickLevelForMemTableOutput( |
|
|
// Check that file does not overlap too many grandparent bytes.
|
|
|
// Check that file does not overlap too many grandparent bytes.
|
|
|
GetOverlappingInputs(level + 2, &start, &limit, &overlaps); |
|
|
GetOverlappingInputs(level + 2, &start, &limit, &overlaps); |
|
|
const int64_t sum = TotalFileSize(overlaps); |
|
|
const int64_t sum = TotalFileSize(overlaps); |
|
|
if (sum > kMaxGrandParentOverlapBytes) { |
|
|
|
|
|
|
|
|
if (sum > MaxGrandParentOverlapBytes(vset_->options_)) { |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -1027,7 +1036,7 @@ bool VersionSet::ReuseManifest(const std::string& dscname, |
|
|
manifest_type != kDescriptorFile || |
|
|
manifest_type != kDescriptorFile || |
|
|
!env_->GetFileSize(dscname, &manifest_size).ok() || |
|
|
!env_->GetFileSize(dscname, &manifest_size).ok() || |
|
|
// Make new compacted MANIFEST if old one is too big
|
|
|
// Make new compacted MANIFEST if old one is too big
|
|
|
manifest_size >= kTargetFileSize) { |
|
|
|
|
|
|
|
|
manifest_size >= TargetFileSize(options_)) { |
|
|
return false; |
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -1076,7 +1085,8 @@ void VersionSet::Finalize(Version* v) { |
|
|
} else { |
|
|
} else { |
|
|
// Compute the ratio of current size to size limit.
|
|
|
// Compute the ratio of current size to size limit.
|
|
|
const uint64_t level_bytes = TotalFileSize(v->files_[level]); |
|
|
const uint64_t level_bytes = TotalFileSize(v->files_[level]); |
|
|
score = static_cast<double>(level_bytes) / MaxBytesForLevel(level); |
|
|
|
|
|
|
|
|
score = |
|
|
|
|
|
static_cast<double>(level_bytes) / MaxBytesForLevel(options_, level); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (score > best_score) { |
|
|
if (score > best_score) { |
|
@ -1290,7 +1300,7 @@ Compaction* VersionSet::PickCompaction() { |
|
|
level = current_->compaction_level_; |
|
|
level = current_->compaction_level_; |
|
|
assert(level >= 0); |
|
|
assert(level >= 0); |
|
|
assert(level+1 < config::kNumLevels); |
|
|
assert(level+1 < config::kNumLevels); |
|
|
c = new Compaction(level); |
|
|
|
|
|
|
|
|
c = new Compaction(options_, level); |
|
|
|
|
|
|
|
|
// 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 (size_t i = 0; i < current_->files_[level].size(); i++) { |
|
@ -1307,7 +1317,7 @@ Compaction* VersionSet::PickCompaction() { |
|
|
} |
|
|
} |
|
|
} else if (seek_compaction) { |
|
|
} else if (seek_compaction) { |
|
|
level = current_->file_to_compact_level_; |
|
|
level = current_->file_to_compact_level_; |
|
|
c = new Compaction(level); |
|
|
|
|
|
|
|
|
c = new Compaction(options_, level); |
|
|
c->inputs_[0].push_back(current_->file_to_compact_); |
|
|
c->inputs_[0].push_back(current_->file_to_compact_); |
|
|
} else { |
|
|
} else { |
|
|
return NULL; |
|
|
return NULL; |
|
@ -1352,7 +1362,8 @@ void VersionSet::SetupOtherInputs(Compaction* c) { |
|
|
const int64_t inputs1_size = TotalFileSize(c->inputs_[1]); |
|
|
const int64_t inputs1_size = TotalFileSize(c->inputs_[1]); |
|
|
const int64_t expanded0_size = TotalFileSize(expanded0); |
|
|
const int64_t expanded0_size = TotalFileSize(expanded0); |
|
|
if (expanded0.size() > c->inputs_[0].size() && |
|
|
if (expanded0.size() > c->inputs_[0].size() && |
|
|
inputs1_size + expanded0_size < kExpandedCompactionByteSizeLimit) { |
|
|
|
|
|
|
|
|
inputs1_size + expanded0_size < |
|
|
|
|
|
ExpandedCompactionByteSizeLimit(options_)) { |
|
|
InternalKey new_start, new_limit; |
|
|
InternalKey new_start, new_limit; |
|
|
GetRange(expanded0, &new_start, &new_limit); |
|
|
GetRange(expanded0, &new_start, &new_limit); |
|
|
std::vector<FileMetaData*> expanded1; |
|
|
std::vector<FileMetaData*> expanded1; |
|
@ -1414,7 +1425,7 @@ Compaction* VersionSet::CompactRange( |
|
|
// and we must not pick one file and drop another older file if the
|
|
|
// and we must not pick one file and drop another older file if the
|
|
|
// two files overlap.
|
|
|
// two files overlap.
|
|
|
if (level > 0) { |
|
|
if (level > 0) { |
|
|
const uint64_t limit = MaxFileSizeForLevel(level); |
|
|
|
|
|
|
|
|
const uint64_t limit = MaxFileSizeForLevel(options_, level); |
|
|
uint64_t total = 0; |
|
|
uint64_t total = 0; |
|
|
for (size_t i = 0; i < inputs.size(); i++) { |
|
|
for (size_t i = 0; i < inputs.size(); i++) { |
|
|
uint64_t s = inputs[i]->file_size; |
|
|
uint64_t s = inputs[i]->file_size; |
|
@ -1426,7 +1437,7 @@ Compaction* VersionSet::CompactRange( |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Compaction* c = new Compaction(level); |
|
|
|
|
|
|
|
|
Compaction* c = new Compaction(options_, level); |
|
|
c->input_version_ = current_; |
|
|
c->input_version_ = current_; |
|
|
c->input_version_->Ref(); |
|
|
c->input_version_->Ref(); |
|
|
c->inputs_[0] = inputs; |
|
|
c->inputs_[0] = inputs; |
|
@ -1434,9 +1445,9 @@ Compaction* VersionSet::CompactRange( |
|
|
return c; |
|
|
return c; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Compaction::Compaction(int level) |
|
|
|
|
|
|
|
|
Compaction::Compaction(const Options* options, int level) |
|
|
: level_(level), |
|
|
: level_(level), |
|
|
max_output_file_size_(MaxFileSizeForLevel(level)), |
|
|
|
|
|
|
|
|
max_output_file_size_(MaxFileSizeForLevel(options, level)), |
|
|
input_version_(NULL), |
|
|
input_version_(NULL), |
|
|
grandparent_index_(0), |
|
|
grandparent_index_(0), |
|
|
seen_key_(false), |
|
|
seen_key_(false), |
|
@ -1453,12 +1464,13 @@ Compaction::~Compaction() { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
bool Compaction::IsTrivialMove() const { |
|
|
bool Compaction::IsTrivialMove() const { |
|
|
|
|
|
const VersionSet* vset = input_version_->vset_; |
|
|
// Avoid a move if there is lots of overlapping grandparent data.
|
|
|
// Avoid a move if there is lots of overlapping grandparent data.
|
|
|
// Otherwise, the move could create a parent file that will require
|
|
|
// Otherwise, the move could create a parent file that will require
|
|
|
// a very expensive merge later on.
|
|
|
// a very expensive merge later on.
|
|
|
return (num_input_files(0) == 1 && |
|
|
|
|
|
num_input_files(1) == 0 && |
|
|
|
|
|
TotalFileSize(grandparents_) <= kMaxGrandParentOverlapBytes); |
|
|
|
|
|
|
|
|
return (num_input_files(0) == 1 && num_input_files(1) == 0 && |
|
|
|
|
|
TotalFileSize(grandparents_) <= |
|
|
|
|
|
MaxGrandParentOverlapBytes(vset->options_)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void Compaction::AddInputDeletions(VersionEdit* edit) { |
|
|
void Compaction::AddInputDeletions(VersionEdit* edit) { |
|
@ -1491,8 +1503,9 @@ bool Compaction::IsBaseLevelForKey(const Slice& user_key) { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
bool Compaction::ShouldStopBefore(const Slice& internal_key) { |
|
|
bool Compaction::ShouldStopBefore(const Slice& internal_key) { |
|
|
|
|
|
const VersionSet* vset = input_version_->vset_; |
|
|
// Scan to find earliest grandparent file that contains key.
|
|
|
// Scan to find earliest grandparent file that contains key.
|
|
|
const InternalKeyComparator* icmp = &input_version_->vset_->icmp_; |
|
|
|
|
|
|
|
|
const InternalKeyComparator* icmp = &vset->icmp_; |
|
|
while (grandparent_index_ < grandparents_.size() && |
|
|
while (grandparent_index_ < grandparents_.size() && |
|
|
icmp->Compare(internal_key, |
|
|
icmp->Compare(internal_key, |
|
|
grandparents_[grandparent_index_]->largest.Encode()) > 0) { |
|
|
grandparents_[grandparent_index_]->largest.Encode()) > 0) { |
|
@ -1503,7 +1516,7 @@ bool Compaction::ShouldStopBefore(const Slice& internal_key) { |
|
|
} |
|
|
} |
|
|
seen_key_ = true; |
|
|
seen_key_ = true; |
|
|
|
|
|
|
|
|
if (overlapped_bytes_ > kMaxGrandParentOverlapBytes) { |
|
|
|
|
|
|
|
|
if (overlapped_bytes_ > MaxGrandParentOverlapBytes(vset->options_)) { |
|
|
// Too much overlap for current output; start new output
|
|
|
// Too much overlap for current output; start new output
|
|
|
overlapped_bytes_ = 0; |
|
|
overlapped_bytes_ = 0; |
|
|
return true; |
|
|
return true; |
|
|