Fixed bug with seek compactions on Level 0

Summary: Due to how the code handled compactions in Level 0 in `PickCompaction()` it could be the case that two compactions on level 0 ran that produced tables in level 1 that overlap. However, this case seems like it would only occur on a seek compaction which is unlikely on level 0. Furthermore, level 0 and level 1 had to have a certain arrangement of files.

Test Plan:
make check

Reviewers: dhruba, vamsi

Reviewed By: dhruba

CC: leveldb, sheki

Differential Revision: https://reviews.facebook.net/D7923
main
Kosie van der Merwe 12 years ago
parent 8ce418cd79
commit 28fe86c48a
  1. 22
      db/version_set.cc
  2. 2
      db/version_set.h

@ -1936,9 +1936,13 @@ Compaction* VersionSet::PickCompaction() {
// Find compactions needed by seeks // Find compactions needed by seeks
if (c == NULL && (current_->file_to_compact_ != NULL)) { if (c == NULL && (current_->file_to_compact_ != NULL)) {
level = current_->file_to_compact_level_; level = current_->file_to_compact_level_;
c = new Compaction(level, MaxFileSizeForLevel(level),
MaxGrandParentOverlapBytes(level), NumberLevels(), true); // Only allow one level 0 compaction at a time.
c->inputs_[0].push_back(current_->file_to_compact_); if (level != 0 || compactions_in_progress_[0].empty()) {
c = new Compaction(level, MaxFileSizeForLevel(level),
MaxGrandParentOverlapBytes(level), NumberLevels(), true);
c->inputs_[0].push_back(current_->file_to_compact_);
}
} }
if (c == NULL) { if (c == NULL) {
@ -1949,26 +1953,22 @@ Compaction* VersionSet::PickCompaction() {
c->input_version_->Ref(); c->input_version_->Ref();
// Files in level 0 may overlap each other, so pick up all overlapping ones // Files in level 0 may overlap each other, so pick up all overlapping ones
// Two level 0 compaction won't run at the same time, so don't need to worry
// about files on level 0 being compacted.
if (level == 0) { if (level == 0) {
assert(compactions_in_progress_[0].empty());
InternalKey smallest, largest; InternalKey smallest, largest;
GetRange(c->inputs_[0], &smallest, &largest); GetRange(c->inputs_[0], &smallest, &largest);
// Note that the next call will discard the file we placed in // Note that the next call will discard the file we placed in
// c->inputs_[0] earlier and replace it with an overlapping set // c->inputs_[0] earlier and replace it with an overlapping set
// which will include the picked file. // which will include the picked file.
c->inputs_[0].clear(); c->inputs_[0].clear();
std::vector<FileMetaData*> more; current_->GetOverlappingInputs(0, &smallest, &largest, &c->inputs_[0]);
current_->GetOverlappingInputs(0, &smallest, &largest, &more);
if (ParentRangeInCompaction(&smallest, &largest, if (ParentRangeInCompaction(&smallest, &largest,
level, &c->parent_index_)) { level, &c->parent_index_)) {
delete c; delete c;
return NULL; return NULL;
} }
for (unsigned int i = 0; i < more.size(); i++) {
FileMetaData* f = more[i];
if (!f->being_compacted) {
c->inputs_[0].push_back(f);
}
}
assert(!c->inputs_[0].empty()); assert(!c->inputs_[0].empty());
} }

@ -345,6 +345,8 @@ class VersionSet {
// For the specfied level, pick a compaction. // For the specfied level, pick a compaction.
// Returns NULL if there is no compaction to be done. // Returns NULL if there is no compaction to be done.
// If level is 0 and there is already a compaction on that level, this
// function will return NULL.
Compaction* PickCompactionBySize(int level, double score); Compaction* PickCompactionBySize(int level, double score);
// Free up the files that were participated in a compaction // Free up the files that were participated in a compaction

Loading…
Cancel
Save