Summary:
The previous fix of reappearing of a deleted row 0ce258f9b3
missed a corner case, which can be reproduced using test CompactionPickerTest.OverlappingUserKeys7. Consider such an example:
input level file: 1[B E] 2[F H]
output level file: 3[A C] 4[D I] 5[I K]
First file 2 is picked, which overlaps to file 4. 4 expands to 5. Now the all range is [D K] with 2 output level files. When we try to expand that, [D K] overlaps with file 1 and 2 in the input level, and 1 and 2 overlaps with 3 and 4 in the output level. So we end up with picking 3 and 4 in the output level. Without expanding, it also has 2 files, so we determine the output level doesn't change, although they are the different two files.
The fix is to expand the output level files after we picked 3 and 4. In that case, there will be three output level files so we will abort the expanding.
I also added two unit tests related to marked_for_compaction and being_compacted. They have been passing though.
Test Plan: Run the new unit test, as well as all other tests.
Reviewers: andrewkr, IslamAbdelRahman
Reviewed By: IslamAbdelRahman
Subscribers: yoshinorim, leveldb, andrewkr, dhruba
Differential Revision: https://reviews.facebook.net/D65373
1186 lines
45 KiB
C++
1186 lines
45 KiB
C++
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
|
// This source code is licensed under the BSD-style license found in the
|
|
// LICENSE file in the root directory of this source tree. An additional grant
|
|
// of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
#include "db/compaction.h"
|
|
#include "db/compaction_picker.h"
|
|
#include <limits>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
#include "util/logging.h"
|
|
#include "util/string_util.h"
|
|
#include "util/testharness.h"
|
|
#include "util/testutil.h"
|
|
|
|
namespace rocksdb {
|
|
|
|
class CountingLogger : public Logger {
|
|
public:
|
|
using Logger::Logv;
|
|
virtual void Logv(const char* format, va_list ap) override { log_count++; }
|
|
size_t log_count;
|
|
};
|
|
|
|
class CompactionPickerTest : public testing::Test {
|
|
public:
|
|
const Comparator* ucmp_;
|
|
InternalKeyComparator icmp_;
|
|
Options options_;
|
|
ImmutableCFOptions ioptions_;
|
|
MutableCFOptions mutable_cf_options_;
|
|
LevelCompactionPicker level_compaction_picker;
|
|
std::string cf_name_;
|
|
CountingLogger logger_;
|
|
LogBuffer log_buffer_;
|
|
uint32_t file_num_;
|
|
CompactionOptionsFIFO fifo_options_;
|
|
std::unique_ptr<VersionStorageInfo> vstorage_;
|
|
std::vector<std::unique_ptr<FileMetaData>> files_;
|
|
// does not own FileMetaData
|
|
std::unordered_map<uint32_t, std::pair<FileMetaData*, int>> file_map_;
|
|
// input files to compaction process.
|
|
std::vector<CompactionInputFiles> input_files_;
|
|
int compaction_level_start_;
|
|
|
|
CompactionPickerTest()
|
|
: ucmp_(BytewiseComparator()),
|
|
icmp_(ucmp_),
|
|
ioptions_(options_),
|
|
mutable_cf_options_(options_),
|
|
level_compaction_picker(ioptions_, &icmp_),
|
|
cf_name_("dummy"),
|
|
log_buffer_(InfoLogLevel::INFO_LEVEL, &logger_),
|
|
file_num_(1),
|
|
vstorage_(nullptr) {
|
|
fifo_options_.max_table_files_size = 1;
|
|
mutable_cf_options_.RefreshDerivedOptions(ioptions_);
|
|
ioptions_.db_paths.emplace_back("dummy",
|
|
std::numeric_limits<uint64_t>::max());
|
|
}
|
|
|
|
~CompactionPickerTest() {
|
|
}
|
|
|
|
void NewVersionStorage(int num_levels, CompactionStyle style) {
|
|
DeleteVersionStorage();
|
|
options_.num_levels = num_levels;
|
|
vstorage_.reset(new VersionStorageInfo(&icmp_, ucmp_, options_.num_levels,
|
|
style, nullptr, false));
|
|
vstorage_->CalculateBaseBytes(ioptions_, mutable_cf_options_);
|
|
}
|
|
|
|
void DeleteVersionStorage() {
|
|
vstorage_.reset();
|
|
files_.clear();
|
|
file_map_.clear();
|
|
input_files_.clear();
|
|
}
|
|
|
|
void Add(int level, uint32_t file_number, const char* smallest,
|
|
const char* largest, uint64_t file_size = 1, uint32_t path_id = 0,
|
|
SequenceNumber smallest_seq = 100,
|
|
SequenceNumber largest_seq = 100) {
|
|
assert(level < vstorage_->num_levels());
|
|
FileMetaData* f = new FileMetaData;
|
|
f->fd = FileDescriptor(file_number, path_id, file_size);
|
|
f->smallest = InternalKey(smallest, smallest_seq, kTypeValue);
|
|
f->largest = InternalKey(largest, largest_seq, kTypeValue);
|
|
f->smallest_seqno = smallest_seq;
|
|
f->largest_seqno = largest_seq;
|
|
f->compensated_file_size = file_size;
|
|
f->refs = 0;
|
|
vstorage_->AddFile(level, f);
|
|
files_.emplace_back(f);
|
|
file_map_.insert({file_number, {f, level}});
|
|
}
|
|
|
|
void SetCompactionInputFilesLevels(int level_count, int start_level) {
|
|
input_files_.resize(level_count);
|
|
for (int i = 0; i < level_count; ++i) {
|
|
input_files_[i].level = start_level + i;
|
|
}
|
|
compaction_level_start_ = start_level;
|
|
}
|
|
|
|
void AddToCompactionFiles(uint32_t file_number) {
|
|
auto iter = file_map_.find(file_number);
|
|
assert(iter != file_map_.end());
|
|
int level = iter->second.second;
|
|
assert(level < vstorage_->num_levels());
|
|
input_files_[level - compaction_level_start_].files.emplace_back(
|
|
iter->second.first);
|
|
}
|
|
|
|
void UpdateVersionStorageInfo() {
|
|
vstorage_->CalculateBaseBytes(ioptions_, mutable_cf_options_);
|
|
vstorage_->UpdateFilesByCompactionPri(ioptions_.compaction_pri);
|
|
vstorage_->UpdateNumNonEmptyLevels();
|
|
vstorage_->GenerateFileIndexer();
|
|
vstorage_->GenerateLevelFilesBrief();
|
|
vstorage_->ComputeCompactionScore(ioptions_, mutable_cf_options_);
|
|
vstorage_->GenerateLevel0NonOverlapping();
|
|
vstorage_->ComputeFilesMarkedForCompaction();
|
|
vstorage_->SetFinalized();
|
|
}
|
|
};
|
|
|
|
TEST_F(CompactionPickerTest, Empty) {
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
UpdateVersionStorageInfo();
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() == nullptr);
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, Single) {
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
mutable_cf_options_.level0_file_num_compaction_trigger = 2;
|
|
Add(0, 1U, "p", "q");
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() == nullptr);
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, Level0Trigger) {
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
mutable_cf_options_.level0_file_num_compaction_trigger = 2;
|
|
Add(0, 1U, "150", "200");
|
|
Add(0, 2U, "200", "250");
|
|
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
ASSERT_EQ(2U, compaction->num_input_files(0));
|
|
ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber());
|
|
ASSERT_EQ(2U, compaction->input(0, 1)->fd.GetNumber());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, Level1Trigger) {
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
Add(1, 66U, "150", "200", 1000000000U);
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
ASSERT_EQ(1U, compaction->num_input_files(0));
|
|
ASSERT_EQ(66U, compaction->input(0, 0)->fd.GetNumber());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, Level1Trigger2) {
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
Add(1, 66U, "150", "200", 1000000001U);
|
|
Add(1, 88U, "201", "300", 1000000000U);
|
|
Add(2, 6U, "150", "179", 1000000000U);
|
|
Add(2, 7U, "180", "220", 1000000000U);
|
|
Add(2, 8U, "221", "300", 1000000000U);
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
ASSERT_EQ(1U, compaction->num_input_files(0));
|
|
ASSERT_EQ(2U, compaction->num_input_files(1));
|
|
ASSERT_EQ(66U, compaction->input(0, 0)->fd.GetNumber());
|
|
ASSERT_EQ(6U, compaction->input(1, 0)->fd.GetNumber());
|
|
ASSERT_EQ(7U, compaction->input(1, 1)->fd.GetNumber());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, LevelMaxScore) {
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
mutable_cf_options_.target_file_size_base = 10000000;
|
|
mutable_cf_options_.target_file_size_multiplier = 10;
|
|
mutable_cf_options_.max_bytes_for_level_base = 10 * 1024 * 1024;
|
|
Add(0, 1U, "150", "200", 1000000000U);
|
|
// Level 1 score 1.2
|
|
Add(1, 66U, "150", "200", 6000000U);
|
|
Add(1, 88U, "201", "300", 6000000U);
|
|
// Level 2 score 1.8. File 7 is the largest. Should be picked
|
|
Add(2, 6U, "150", "179", 60000000U);
|
|
Add(2, 7U, "180", "220", 60000001U);
|
|
Add(2, 8U, "221", "300", 60000000U);
|
|
// Level 3 score slightly larger than 1
|
|
Add(3, 26U, "150", "170", 260000000U);
|
|
Add(3, 27U, "171", "179", 260000000U);
|
|
Add(3, 28U, "191", "220", 260000000U);
|
|
Add(3, 29U, "221", "300", 260000000U);
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
ASSERT_EQ(1U, compaction->num_input_files(0));
|
|
ASSERT_EQ(7U, compaction->input(0, 0)->fd.GetNumber());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, NeedsCompactionLevel) {
|
|
const int kLevels = 6;
|
|
const int kFileCount = 20;
|
|
|
|
for (int level = 0; level < kLevels - 1; ++level) {
|
|
NewVersionStorage(kLevels, kCompactionStyleLevel);
|
|
uint64_t file_size = vstorage_->MaxBytesForLevel(level) * 2 / kFileCount;
|
|
for (int file_count = 1; file_count <= kFileCount; ++file_count) {
|
|
// start a brand new version in each test.
|
|
NewVersionStorage(kLevels, kCompactionStyleLevel);
|
|
for (int i = 0; i < file_count; ++i) {
|
|
Add(level, i, ToString((i + 100) * 1000).c_str(),
|
|
ToString((i + 100) * 1000 + 999).c_str(),
|
|
file_size, 0, i * 100, i * 100 + 99);
|
|
}
|
|
UpdateVersionStorageInfo();
|
|
ASSERT_EQ(vstorage_->CompactionScoreLevel(0), level);
|
|
ASSERT_EQ(level_compaction_picker.NeedsCompaction(vstorage_.get()),
|
|
vstorage_->CompactionScore(0) >= 1);
|
|
// release the version storage
|
|
DeleteVersionStorage();
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, Level0TriggerDynamic) {
|
|
int num_levels = ioptions_.num_levels;
|
|
ioptions_.level_compaction_dynamic_level_bytes = true;
|
|
mutable_cf_options_.level0_file_num_compaction_trigger = 2;
|
|
mutable_cf_options_.max_bytes_for_level_base = 200;
|
|
mutable_cf_options_.max_bytes_for_level_multiplier = 10;
|
|
NewVersionStorage(num_levels, kCompactionStyleLevel);
|
|
Add(0, 1U, "150", "200");
|
|
Add(0, 2U, "200", "250");
|
|
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
ASSERT_EQ(2U, compaction->num_input_files(0));
|
|
ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber());
|
|
ASSERT_EQ(2U, compaction->input(0, 1)->fd.GetNumber());
|
|
ASSERT_EQ(1, static_cast<int>(compaction->num_input_levels()));
|
|
ASSERT_EQ(num_levels - 1, compaction->output_level());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, Level0TriggerDynamic2) {
|
|
int num_levels = ioptions_.num_levels;
|
|
ioptions_.level_compaction_dynamic_level_bytes = true;
|
|
mutable_cf_options_.level0_file_num_compaction_trigger = 2;
|
|
mutable_cf_options_.max_bytes_for_level_base = 200;
|
|
mutable_cf_options_.max_bytes_for_level_multiplier = 10;
|
|
NewVersionStorage(num_levels, kCompactionStyleLevel);
|
|
Add(0, 1U, "150", "200");
|
|
Add(0, 2U, "200", "250");
|
|
Add(num_levels - 1, 3U, "200", "250", 300U);
|
|
|
|
UpdateVersionStorageInfo();
|
|
ASSERT_EQ(vstorage_->base_level(), num_levels - 2);
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
ASSERT_EQ(2U, compaction->num_input_files(0));
|
|
ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber());
|
|
ASSERT_EQ(2U, compaction->input(0, 1)->fd.GetNumber());
|
|
ASSERT_EQ(1, static_cast<int>(compaction->num_input_levels()));
|
|
ASSERT_EQ(num_levels - 2, compaction->output_level());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, Level0TriggerDynamic3) {
|
|
int num_levels = ioptions_.num_levels;
|
|
ioptions_.level_compaction_dynamic_level_bytes = true;
|
|
mutable_cf_options_.level0_file_num_compaction_trigger = 2;
|
|
mutable_cf_options_.max_bytes_for_level_base = 200;
|
|
mutable_cf_options_.max_bytes_for_level_multiplier = 10;
|
|
NewVersionStorage(num_levels, kCompactionStyleLevel);
|
|
Add(0, 1U, "150", "200");
|
|
Add(0, 2U, "200", "250");
|
|
Add(num_levels - 1, 3U, "200", "250", 300U);
|
|
Add(num_levels - 1, 4U, "300", "350", 3000U);
|
|
|
|
UpdateVersionStorageInfo();
|
|
ASSERT_EQ(vstorage_->base_level(), num_levels - 3);
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
ASSERT_EQ(2U, compaction->num_input_files(0));
|
|
ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber());
|
|
ASSERT_EQ(2U, compaction->input(0, 1)->fd.GetNumber());
|
|
ASSERT_EQ(1, static_cast<int>(compaction->num_input_levels()));
|
|
ASSERT_EQ(num_levels - 3, compaction->output_level());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, Level0TriggerDynamic4) {
|
|
int num_levels = ioptions_.num_levels;
|
|
ioptions_.level_compaction_dynamic_level_bytes = true;
|
|
mutable_cf_options_.level0_file_num_compaction_trigger = 2;
|
|
mutable_cf_options_.max_bytes_for_level_base = 200;
|
|
mutable_cf_options_.max_bytes_for_level_multiplier = 10;
|
|
|
|
NewVersionStorage(num_levels, kCompactionStyleLevel);
|
|
Add(0, 1U, "150", "200");
|
|
Add(0, 2U, "200", "250");
|
|
Add(num_levels - 1, 3U, "200", "250", 300U);
|
|
Add(num_levels - 1, 4U, "300", "350", 3000U);
|
|
Add(num_levels - 3, 5U, "150", "180", 3U);
|
|
Add(num_levels - 3, 6U, "181", "300", 3U);
|
|
Add(num_levels - 3, 7U, "400", "450", 3U);
|
|
|
|
UpdateVersionStorageInfo();
|
|
ASSERT_EQ(vstorage_->base_level(), num_levels - 3);
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
ASSERT_EQ(2U, compaction->num_input_files(0));
|
|
ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber());
|
|
ASSERT_EQ(2U, compaction->input(0, 1)->fd.GetNumber());
|
|
ASSERT_EQ(2U, compaction->num_input_files(1));
|
|
ASSERT_EQ(num_levels - 3, compaction->level(1));
|
|
ASSERT_EQ(5U, compaction->input(1, 0)->fd.GetNumber());
|
|
ASSERT_EQ(6U, compaction->input(1, 1)->fd.GetNumber());
|
|
ASSERT_EQ(2, static_cast<int>(compaction->num_input_levels()));
|
|
ASSERT_EQ(num_levels - 3, compaction->output_level());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, LevelTriggerDynamic4) {
|
|
int num_levels = ioptions_.num_levels;
|
|
ioptions_.level_compaction_dynamic_level_bytes = true;
|
|
ioptions_.compaction_pri = kMinOverlappingRatio;
|
|
mutable_cf_options_.level0_file_num_compaction_trigger = 2;
|
|
mutable_cf_options_.max_bytes_for_level_base = 200;
|
|
mutable_cf_options_.max_bytes_for_level_multiplier = 10;
|
|
NewVersionStorage(num_levels, kCompactionStyleLevel);
|
|
Add(0, 1U, "150", "200");
|
|
Add(num_levels - 1, 3U, "200", "250", 300U);
|
|
Add(num_levels - 1, 4U, "300", "350", 3000U);
|
|
Add(num_levels - 1, 4U, "400", "450", 3U);
|
|
Add(num_levels - 2, 5U, "150", "180", 300U);
|
|
Add(num_levels - 2, 6U, "181", "350", 500U);
|
|
Add(num_levels - 2, 7U, "400", "450", 200U);
|
|
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
ASSERT_EQ(1U, compaction->num_input_files(0));
|
|
ASSERT_EQ(5U, compaction->input(0, 0)->fd.GetNumber());
|
|
ASSERT_EQ(0, compaction->num_input_files(1));
|
|
ASSERT_EQ(1U, compaction->num_input_levels());
|
|
ASSERT_EQ(num_levels - 1, compaction->output_level());
|
|
}
|
|
|
|
// Universal and FIFO Compactions are not supported in ROCKSDB_LITE
|
|
#ifndef ROCKSDB_LITE
|
|
TEST_F(CompactionPickerTest, NeedsCompactionUniversal) {
|
|
NewVersionStorage(1, kCompactionStyleUniversal);
|
|
UniversalCompactionPicker universal_compaction_picker(
|
|
ioptions_, &icmp_);
|
|
// must return false when there's no files.
|
|
ASSERT_EQ(universal_compaction_picker.NeedsCompaction(vstorage_.get()),
|
|
false);
|
|
UpdateVersionStorageInfo();
|
|
|
|
// verify the trigger given different number of L0 files.
|
|
for (int i = 1;
|
|
i <= mutable_cf_options_.level0_file_num_compaction_trigger * 2; ++i) {
|
|
NewVersionStorage(1, kCompactionStyleUniversal);
|
|
Add(0, i, ToString((i + 100) * 1000).c_str(),
|
|
ToString((i + 100) * 1000 + 999).c_str(), 1000000, 0, i * 100,
|
|
i * 100 + 99);
|
|
UpdateVersionStorageInfo();
|
|
ASSERT_EQ(level_compaction_picker.NeedsCompaction(vstorage_.get()),
|
|
vstorage_->CompactionScore(0) >= 1);
|
|
}
|
|
}
|
|
// Tests if the files can be trivially moved in multi level
|
|
// universal compaction when allow_trivial_move option is set
|
|
// In this test as the input files overlaps, they cannot
|
|
// be trivially moved.
|
|
|
|
TEST_F(CompactionPickerTest, CannotTrivialMoveUniversal) {
|
|
const uint64_t kFileSize = 100000;
|
|
|
|
ioptions_.compaction_options_universal.allow_trivial_move = true;
|
|
NewVersionStorage(1, kCompactionStyleUniversal);
|
|
UniversalCompactionPicker universal_compaction_picker(ioptions_, &icmp_);
|
|
// must return false when there's no files.
|
|
ASSERT_EQ(universal_compaction_picker.NeedsCompaction(vstorage_.get()),
|
|
false);
|
|
|
|
NewVersionStorage(3, kCompactionStyleUniversal);
|
|
|
|
Add(0, 1U, "150", "200", kFileSize, 0, 500, 550);
|
|
Add(0, 2U, "201", "250", kFileSize, 0, 401, 450);
|
|
Add(0, 4U, "260", "300", kFileSize, 0, 260, 300);
|
|
Add(1, 5U, "100", "151", kFileSize, 0, 200, 251);
|
|
Add(1, 3U, "301", "350", kFileSize, 0, 101, 150);
|
|
Add(2, 6U, "120", "200", kFileSize, 0, 20, 100);
|
|
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(
|
|
universal_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
|
|
ASSERT_TRUE(!compaction->is_trivial_move());
|
|
}
|
|
// Tests if the files can be trivially moved in multi level
|
|
// universal compaction when allow_trivial_move option is set
|
|
// In this test as the input files doesn't overlaps, they should
|
|
// be trivially moved.
|
|
TEST_F(CompactionPickerTest, AllowsTrivialMoveUniversal) {
|
|
const uint64_t kFileSize = 100000;
|
|
|
|
ioptions_.compaction_options_universal.allow_trivial_move = true;
|
|
UniversalCompactionPicker universal_compaction_picker(ioptions_, &icmp_);
|
|
|
|
NewVersionStorage(3, kCompactionStyleUniversal);
|
|
|
|
Add(0, 1U, "150", "200", kFileSize, 0, 500, 550);
|
|
Add(0, 2U, "201", "250", kFileSize, 0, 401, 450);
|
|
Add(0, 4U, "260", "300", kFileSize, 0, 260, 300);
|
|
Add(1, 5U, "010", "080", kFileSize, 0, 200, 251);
|
|
Add(2, 3U, "301", "350", kFileSize, 0, 101, 150);
|
|
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(
|
|
universal_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
|
|
ASSERT_TRUE(compaction->is_trivial_move());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, NeedsCompactionFIFO) {
|
|
NewVersionStorage(1, kCompactionStyleFIFO);
|
|
const int kFileCount =
|
|
mutable_cf_options_.level0_file_num_compaction_trigger * 3;
|
|
const uint64_t kFileSize = 100000;
|
|
const uint64_t kMaxSize = kFileSize * kFileCount / 2;
|
|
|
|
fifo_options_.max_table_files_size = kMaxSize;
|
|
ioptions_.compaction_options_fifo = fifo_options_;
|
|
FIFOCompactionPicker fifo_compaction_picker(ioptions_, &icmp_);
|
|
UpdateVersionStorageInfo();
|
|
// must return false when there's no files.
|
|
ASSERT_EQ(fifo_compaction_picker.NeedsCompaction(vstorage_.get()), false);
|
|
|
|
// verify whether compaction is needed based on the current
|
|
// size of L0 files.
|
|
uint64_t current_size = 0;
|
|
for (int i = 1; i <= kFileCount; ++i) {
|
|
NewVersionStorage(1, kCompactionStyleFIFO);
|
|
Add(0, i, ToString((i + 100) * 1000).c_str(),
|
|
ToString((i + 100) * 1000 + 999).c_str(),
|
|
kFileSize, 0, i * 100, i * 100 + 99);
|
|
current_size += kFileSize;
|
|
UpdateVersionStorageInfo();
|
|
ASSERT_EQ(level_compaction_picker.NeedsCompaction(vstorage_.get()),
|
|
vstorage_->CompactionScore(0) >= 1);
|
|
}
|
|
}
|
|
#endif // ROCKSDB_LITE
|
|
|
|
TEST_F(CompactionPickerTest, CompactionPriMinOverlapping1) {
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
ioptions_.compaction_pri = kMinOverlappingRatio;
|
|
mutable_cf_options_.target_file_size_base = 10000000;
|
|
mutable_cf_options_.target_file_size_multiplier = 10;
|
|
mutable_cf_options_.max_bytes_for_level_base = 10 * 1024 * 1024;
|
|
|
|
Add(2, 6U, "150", "179", 50000000U);
|
|
Add(2, 7U, "180", "220", 50000000U);
|
|
Add(2, 8U, "321", "400", 50000000U); // File not overlapping
|
|
Add(2, 9U, "721", "800", 50000000U);
|
|
|
|
Add(3, 26U, "150", "170", 260000000U);
|
|
Add(3, 27U, "171", "179", 260000000U);
|
|
Add(3, 28U, "191", "220", 260000000U);
|
|
Add(3, 29U, "221", "300", 260000000U);
|
|
Add(3, 30U, "750", "900", 260000000U);
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
ASSERT_EQ(1U, compaction->num_input_files(0));
|
|
// Pick file 8 because it overlaps with 0 files on level 3.
|
|
ASSERT_EQ(8U, compaction->input(0, 0)->fd.GetNumber());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, CompactionPriMinOverlapping2) {
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
ioptions_.compaction_pri = kMinOverlappingRatio;
|
|
mutable_cf_options_.target_file_size_base = 10000000;
|
|
mutable_cf_options_.target_file_size_multiplier = 10;
|
|
mutable_cf_options_.max_bytes_for_level_base = 10 * 1024 * 1024;
|
|
|
|
Add(2, 6U, "150", "175",
|
|
60000000U); // Overlaps with file 26, 27, total size 521M
|
|
Add(2, 7U, "176", "200", 60000000U); // Overlaps with file 27, 28, total size
|
|
// 520M, the smalelst overlapping
|
|
Add(2, 8U, "201", "300",
|
|
60000000U); // Overlaps with file 28, 29, total size 521M
|
|
|
|
Add(3, 26U, "100", "110", 261000000U);
|
|
Add(3, 26U, "150", "170", 261000000U);
|
|
Add(3, 27U, "171", "179", 260000000U);
|
|
Add(3, 28U, "191", "220", 260000000U);
|
|
Add(3, 29U, "221", "300", 261000000U);
|
|
Add(3, 30U, "321", "400", 261000000U);
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
ASSERT_EQ(1U, compaction->num_input_files(0));
|
|
// Picking file 7 because overlapping ratio is the biggest.
|
|
ASSERT_EQ(7U, compaction->input(0, 0)->fd.GetNumber());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, CompactionPriMinOverlapping3) {
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
ioptions_.compaction_pri = kMinOverlappingRatio;
|
|
mutable_cf_options_.max_bytes_for_level_base = 10000000;
|
|
mutable_cf_options_.max_bytes_for_level_multiplier = 10;
|
|
|
|
// file 7 and 8 over lap with the same file, but file 8 is smaller so
|
|
// it will be picked.
|
|
Add(2, 6U, "150", "167", 60000000U); // Overlaps with file 26, 27
|
|
Add(2, 7U, "168", "169", 60000000U); // Overlaps with file 27
|
|
Add(2, 8U, "201", "300", 61000000U); // Overlaps with file 28, but the file
|
|
// itself is larger. Should be picked.
|
|
|
|
Add(3, 26U, "160", "165", 260000000U);
|
|
Add(3, 27U, "166", "170", 260000000U);
|
|
Add(3, 28U, "180", "400", 260000000U);
|
|
Add(3, 29U, "401", "500", 260000000U);
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
ASSERT_EQ(1U, compaction->num_input_files(0));
|
|
// Picking file 8 because overlapping ratio is the biggest.
|
|
ASSERT_EQ(8U, compaction->input(0, 0)->fd.GetNumber());
|
|
}
|
|
|
|
// This test exhibits the bug where we don't properly reset parent_index in
|
|
// PickCompaction()
|
|
TEST_F(CompactionPickerTest, ParentIndexResetBug) {
|
|
int num_levels = ioptions_.num_levels;
|
|
mutable_cf_options_.level0_file_num_compaction_trigger = 2;
|
|
mutable_cf_options_.max_bytes_for_level_base = 200;
|
|
NewVersionStorage(num_levels, kCompactionStyleLevel);
|
|
Add(0, 1U, "150", "200"); // <- marked for compaction
|
|
Add(1, 3U, "400", "500", 600); // <- this one needs compacting
|
|
Add(2, 4U, "150", "200");
|
|
Add(2, 5U, "201", "210");
|
|
Add(2, 6U, "300", "310");
|
|
Add(2, 7U, "400", "500"); // <- being compacted
|
|
|
|
vstorage_->LevelFiles(2)[3]->being_compacted = true;
|
|
vstorage_->LevelFiles(0)[0]->marked_for_compaction = true;
|
|
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
}
|
|
|
|
// This test checks ExpandWhileOverlapping() by having overlapping user keys
|
|
// ranges (with different sequence numbers) in the input files.
|
|
TEST_F(CompactionPickerTest, OverlappingUserKeys) {
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
ioptions_.compaction_pri = kByCompensatedSize;
|
|
|
|
Add(1, 1U, "100", "150", 1U);
|
|
// Overlapping user keys
|
|
Add(1, 2U, "200", "400", 1U);
|
|
Add(1, 3U, "400", "500", 1000000000U, 0, 0);
|
|
Add(2, 4U, "600", "700", 1U);
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
ASSERT_EQ(1U, compaction->num_input_levels());
|
|
ASSERT_EQ(2U, compaction->num_input_files(0));
|
|
ASSERT_EQ(2U, compaction->input(0, 0)->fd.GetNumber());
|
|
ASSERT_EQ(3U, compaction->input(0, 1)->fd.GetNumber());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, OverlappingUserKeys2) {
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
// Overlapping user keys on same level and output level
|
|
Add(1, 1U, "200", "400", 1000000000U);
|
|
Add(1, 2U, "400", "500", 1U, 0, 0);
|
|
Add(2, 3U, "000", "100", 1U);
|
|
Add(2, 4U, "100", "600", 1U, 0, 0);
|
|
Add(2, 5U, "600", "700", 1U, 0, 0);
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
ASSERT_EQ(2U, compaction->num_input_levels());
|
|
ASSERT_EQ(2U, compaction->num_input_files(0));
|
|
ASSERT_EQ(3U, compaction->num_input_files(1));
|
|
ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber());
|
|
ASSERT_EQ(2U, compaction->input(0, 1)->fd.GetNumber());
|
|
ASSERT_EQ(3U, compaction->input(1, 0)->fd.GetNumber());
|
|
ASSERT_EQ(4U, compaction->input(1, 1)->fd.GetNumber());
|
|
ASSERT_EQ(5U, compaction->input(1, 2)->fd.GetNumber());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, OverlappingUserKeys3) {
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
// Chain of overlapping user key ranges (forces ExpandWhileOverlapping() to
|
|
// expand multiple times)
|
|
Add(1, 1U, "100", "150", 1U);
|
|
Add(1, 2U, "150", "200", 1U, 0, 0);
|
|
Add(1, 3U, "200", "250", 1000000000U, 0, 0);
|
|
Add(1, 4U, "250", "300", 1U, 0, 0);
|
|
Add(1, 5U, "300", "350", 1U, 0, 0);
|
|
// Output level overlaps with the beginning and the end of the chain
|
|
Add(2, 6U, "050", "100", 1U);
|
|
Add(2, 7U, "350", "400", 1U);
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
ASSERT_EQ(2U, compaction->num_input_levels());
|
|
ASSERT_EQ(5U, compaction->num_input_files(0));
|
|
ASSERT_EQ(2U, compaction->num_input_files(1));
|
|
ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber());
|
|
ASSERT_EQ(2U, compaction->input(0, 1)->fd.GetNumber());
|
|
ASSERT_EQ(3U, compaction->input(0, 2)->fd.GetNumber());
|
|
ASSERT_EQ(4U, compaction->input(0, 3)->fd.GetNumber());
|
|
ASSERT_EQ(5U, compaction->input(0, 4)->fd.GetNumber());
|
|
ASSERT_EQ(6U, compaction->input(1, 0)->fd.GetNumber());
|
|
ASSERT_EQ(7U, compaction->input(1, 1)->fd.GetNumber());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, OverlappingUserKeys4) {
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
mutable_cf_options_.max_bytes_for_level_base = 1000000;
|
|
|
|
Add(1, 1U, "100", "150", 1U);
|
|
Add(1, 2U, "150", "199", 1U, 0, 0);
|
|
Add(1, 3U, "200", "250", 1100000U, 0, 0);
|
|
Add(1, 4U, "251", "300", 1U, 0, 0);
|
|
Add(1, 5U, "300", "350", 1U, 0, 0);
|
|
|
|
Add(2, 6U, "100", "115", 1U);
|
|
Add(2, 7U, "125", "325", 1U);
|
|
Add(2, 8U, "350", "400", 1U);
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
ASSERT_EQ(2U, compaction->num_input_levels());
|
|
ASSERT_EQ(1U, compaction->num_input_files(0));
|
|
ASSERT_EQ(1U, compaction->num_input_files(1));
|
|
ASSERT_EQ(3U, compaction->input(0, 0)->fd.GetNumber());
|
|
ASSERT_EQ(7U, compaction->input(1, 0)->fd.GetNumber());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, OverlappingUserKeys5) {
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
// Overlapping user keys on same level and output level
|
|
Add(1, 1U, "200", "400", 1000000000U);
|
|
Add(1, 2U, "400", "500", 1U, 0, 0);
|
|
Add(2, 3U, "000", "100", 1U);
|
|
Add(2, 4U, "100", "600", 1U, 0, 0);
|
|
Add(2, 5U, "600", "700", 1U, 0, 0);
|
|
|
|
vstorage_->LevelFiles(2)[2]->being_compacted = true;
|
|
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() == nullptr);
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, OverlappingUserKeys6) {
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
// Overlapping user keys on same level and output level
|
|
Add(1, 1U, "200", "400", 1U, 0, 0);
|
|
Add(1, 2U, "401", "500", 1U, 0, 0);
|
|
Add(2, 3U, "000", "100", 1U);
|
|
Add(2, 4U, "100", "300", 1U, 0, 0);
|
|
Add(2, 5U, "305", "450", 1U, 0, 0);
|
|
Add(2, 6U, "460", "600", 1U, 0, 0);
|
|
Add(2, 7U, "600", "700", 1U, 0, 0);
|
|
|
|
vstorage_->LevelFiles(1)[0]->marked_for_compaction = true;
|
|
vstorage_->LevelFiles(1)[1]->marked_for_compaction = true;
|
|
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
ASSERT_EQ(2U, compaction->num_input_levels());
|
|
ASSERT_EQ(1U, compaction->num_input_files(0));
|
|
ASSERT_EQ(3U, compaction->num_input_files(1));
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, OverlappingUserKeys7) {
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
mutable_cf_options_.max_compaction_bytes = 100000000000u;
|
|
// Overlapping user keys on same level and output level
|
|
Add(1, 1U, "200", "400", 1U, 0, 0);
|
|
Add(1, 2U, "401", "500", 1000000000U, 0, 0);
|
|
Add(2, 3U, "100", "250", 1U);
|
|
Add(2, 4U, "300", "600", 1U, 0, 0);
|
|
Add(2, 5U, "600", "800", 1U, 0, 0);
|
|
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
ASSERT_EQ(2U, compaction->num_input_levels());
|
|
ASSERT_GE(1U, compaction->num_input_files(0));
|
|
ASSERT_GE(2U, compaction->num_input_files(1));
|
|
// File 5 has to be included in the compaction
|
|
ASSERT_EQ(5U, compaction->inputs(1)->back()->fd.GetNumber());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, NotScheduleL1IfL0WithHigherPri1) {
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
mutable_cf_options_.level0_file_num_compaction_trigger = 2;
|
|
mutable_cf_options_.max_bytes_for_level_base = 900000000U;
|
|
|
|
// 6 L0 files, score 3.
|
|
Add(0, 1U, "000", "400", 1U);
|
|
Add(0, 2U, "001", "400", 1U, 0, 0);
|
|
Add(0, 3U, "001", "400", 1000000000U, 0, 0);
|
|
Add(0, 31U, "001", "400", 1000000000U, 0, 0);
|
|
Add(0, 32U, "001", "400", 1000000000U, 0, 0);
|
|
Add(0, 33U, "001", "400", 1000000000U, 0, 0);
|
|
|
|
// L1 total size 2GB, score 2.2. If one file being comapcted, score 1.1.
|
|
Add(1, 4U, "050", "300", 1000000000U, 0, 0);
|
|
file_map_[4u].first->being_compacted = true;
|
|
Add(1, 5U, "301", "350", 1000000000U, 0, 0);
|
|
|
|
// Output level overlaps with the beginning and the end of the chain
|
|
Add(2, 6U, "050", "100", 1U);
|
|
Add(2, 7U, "300", "400", 1U);
|
|
|
|
// No compaction should be scheduled, if L0 has higher priority than L1
|
|
// but L0->L1 compaction is blocked by a file in L1 being compacted.
|
|
UpdateVersionStorageInfo();
|
|
ASSERT_EQ(0, vstorage_->CompactionScoreLevel(0));
|
|
ASSERT_EQ(1, vstorage_->CompactionScoreLevel(1));
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() == nullptr);
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, NotScheduleL1IfL0WithHigherPri2) {
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
mutable_cf_options_.level0_file_num_compaction_trigger = 2;
|
|
mutable_cf_options_.max_bytes_for_level_base = 900000000U;
|
|
|
|
// 6 L0 files, score 3.
|
|
Add(0, 1U, "000", "400", 1U);
|
|
Add(0, 2U, "001", "400", 1U, 0, 0);
|
|
Add(0, 3U, "001", "400", 1000000000U, 0, 0);
|
|
Add(0, 31U, "001", "400", 1000000000U, 0, 0);
|
|
Add(0, 32U, "001", "400", 1000000000U, 0, 0);
|
|
Add(0, 33U, "001", "400", 1000000000U, 0, 0);
|
|
|
|
// L1 total size 2GB, score 2.2. If one file being comapcted, score 1.1.
|
|
Add(1, 4U, "050", "300", 1000000000U, 0, 0);
|
|
Add(1, 5U, "301", "350", 1000000000U, 0, 0);
|
|
|
|
// Output level overlaps with the beginning and the end of the chain
|
|
Add(2, 6U, "050", "100", 1U);
|
|
Add(2, 7U, "300", "400", 1U);
|
|
|
|
// If no file in L1 being compacted, L0->L1 compaction will be scheduled.
|
|
UpdateVersionStorageInfo(); // being_compacted flag is cleared here.
|
|
ASSERT_EQ(0, vstorage_->CompactionScoreLevel(0));
|
|
ASSERT_EQ(1, vstorage_->CompactionScoreLevel(1));
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, NotScheduleL1IfL0WithHigherPri3) {
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
mutable_cf_options_.level0_file_num_compaction_trigger = 2;
|
|
mutable_cf_options_.max_bytes_for_level_base = 900000000U;
|
|
|
|
// 6 L0 files, score 3.
|
|
Add(0, 1U, "000", "400", 1U);
|
|
Add(0, 2U, "001", "400", 1U, 0, 0);
|
|
Add(0, 3U, "001", "400", 1000000000U, 0, 0);
|
|
Add(0, 31U, "001", "400", 1000000000U, 0, 0);
|
|
Add(0, 32U, "001", "400", 1000000000U, 0, 0);
|
|
Add(0, 33U, "001", "400", 1000000000U, 0, 0);
|
|
|
|
// L1 score more than 6.
|
|
Add(1, 4U, "050", "300", 1000000000U, 0, 0);
|
|
file_map_[4u].first->being_compacted = true;
|
|
Add(1, 5U, "301", "350", 1000000000U, 0, 0);
|
|
Add(1, 51U, "351", "400", 6000000000U, 0, 0);
|
|
|
|
// Output level overlaps with the beginning and the end of the chain
|
|
Add(2, 6U, "050", "100", 1U);
|
|
Add(2, 7U, "300", "400", 1U);
|
|
|
|
// If score in L1 is larger than L0, L1 compaction goes through despite
|
|
// there is pending L0 compaction.
|
|
UpdateVersionStorageInfo();
|
|
ASSERT_EQ(1, vstorage_->CompactionScoreLevel(0));
|
|
ASSERT_EQ(0, vstorage_->CompactionScoreLevel(1));
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, EstimateCompactionBytesNeeded1) {
|
|
int num_levels = ioptions_.num_levels;
|
|
ioptions_.level_compaction_dynamic_level_bytes = false;
|
|
mutable_cf_options_.level0_file_num_compaction_trigger = 3;
|
|
mutable_cf_options_.max_bytes_for_level_base = 1000;
|
|
mutable_cf_options_.max_bytes_for_level_multiplier = 10;
|
|
NewVersionStorage(num_levels, kCompactionStyleLevel);
|
|
Add(0, 1U, "150", "200", 200);
|
|
Add(0, 2U, "150", "200", 200);
|
|
Add(0, 3U, "150", "200", 200);
|
|
// Level 1 is over target by 200
|
|
Add(1, 4U, "400", "500", 600);
|
|
Add(1, 5U, "600", "700", 600);
|
|
// Level 2 is less than target 10000 even added size of level 1
|
|
// Size ratio of L2/L1 is 9600 / 1200 = 8
|
|
Add(2, 6U, "150", "200", 2500);
|
|
Add(2, 7U, "201", "210", 2000);
|
|
Add(2, 8U, "300", "310", 2600);
|
|
Add(2, 9U, "400", "500", 2500);
|
|
// Level 3 exceeds target 100,000 of 1000
|
|
Add(3, 10U, "400", "500", 101000);
|
|
// Level 4 exceeds target 1,000,000 by 900 after adding size from level 3
|
|
// Size ratio L4/L3 is 9.9
|
|
// After merge from L3, L4 size is 1000900
|
|
Add(4, 11U, "400", "500", 999900);
|
|
Add(5, 11U, "400", "500", 8007200);
|
|
|
|
UpdateVersionStorageInfo();
|
|
|
|
ASSERT_EQ(200u * 9u + 10900u + 900u * 9,
|
|
vstorage_->estimated_compaction_needed_bytes());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, EstimateCompactionBytesNeeded2) {
|
|
int num_levels = ioptions_.num_levels;
|
|
ioptions_.level_compaction_dynamic_level_bytes = false;
|
|
mutable_cf_options_.level0_file_num_compaction_trigger = 3;
|
|
mutable_cf_options_.max_bytes_for_level_base = 1000;
|
|
mutable_cf_options_.max_bytes_for_level_multiplier = 10;
|
|
NewVersionStorage(num_levels, kCompactionStyleLevel);
|
|
Add(0, 1U, "150", "200", 200);
|
|
Add(0, 2U, "150", "200", 200);
|
|
Add(0, 4U, "150", "200", 200);
|
|
Add(0, 5U, "150", "200", 200);
|
|
Add(0, 6U, "150", "200", 200);
|
|
// Level 1 size will be 1400 after merging with L0
|
|
Add(1, 7U, "400", "500", 200);
|
|
Add(1, 8U, "600", "700", 200);
|
|
// Level 2 is less than target 10000 even added size of level 1
|
|
Add(2, 9U, "150", "200", 9100);
|
|
// Level 3 over the target, but since level 4 is empty, we assume it will be
|
|
// a trivial move.
|
|
Add(3, 10U, "400", "500", 101000);
|
|
|
|
UpdateVersionStorageInfo();
|
|
|
|
// estimated L1->L2 merge: 400 * (9100.0 / 1400.0 + 1.0)
|
|
ASSERT_EQ(1400u + 3000u, vstorage_->estimated_compaction_needed_bytes());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, EstimateCompactionBytesNeeded3) {
|
|
int num_levels = ioptions_.num_levels;
|
|
ioptions_.level_compaction_dynamic_level_bytes = false;
|
|
mutable_cf_options_.level0_file_num_compaction_trigger = 3;
|
|
mutable_cf_options_.max_bytes_for_level_base = 1000;
|
|
mutable_cf_options_.max_bytes_for_level_multiplier = 10;
|
|
NewVersionStorage(num_levels, kCompactionStyleLevel);
|
|
Add(0, 1U, "150", "200", 2000);
|
|
Add(0, 2U, "150", "200", 2000);
|
|
Add(0, 4U, "150", "200", 2000);
|
|
Add(0, 5U, "150", "200", 2000);
|
|
Add(0, 6U, "150", "200", 1000);
|
|
// Level 1 size will be 10000 after merging with L0
|
|
Add(1, 7U, "400", "500", 500);
|
|
Add(1, 8U, "600", "700", 500);
|
|
|
|
Add(2, 9U, "150", "200", 10000);
|
|
|
|
UpdateVersionStorageInfo();
|
|
|
|
ASSERT_EQ(10000u + 18000u, vstorage_->estimated_compaction_needed_bytes());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, EstimateCompactionBytesNeededDynamicLevel) {
|
|
int num_levels = ioptions_.num_levels;
|
|
ioptions_.level_compaction_dynamic_level_bytes = true;
|
|
mutable_cf_options_.level0_file_num_compaction_trigger = 3;
|
|
mutable_cf_options_.max_bytes_for_level_base = 1000;
|
|
mutable_cf_options_.max_bytes_for_level_multiplier = 10;
|
|
NewVersionStorage(num_levels, kCompactionStyleLevel);
|
|
|
|
// Set Last level size 50000
|
|
// num_levels - 1 target 5000
|
|
// num_levels - 2 is base level with taret 500
|
|
Add(num_levels - 1, 10U, "400", "500", 50000);
|
|
|
|
Add(0, 1U, "150", "200", 200);
|
|
Add(0, 2U, "150", "200", 200);
|
|
Add(0, 4U, "150", "200", 200);
|
|
Add(0, 5U, "150", "200", 200);
|
|
Add(0, 6U, "150", "200", 200);
|
|
// num_levels - 3 is over target by 100 + 1000
|
|
Add(num_levels - 3, 7U, "400", "500", 300);
|
|
Add(num_levels - 3, 8U, "600", "700", 300);
|
|
// num_levels - 2 is over target by 1100 + 200
|
|
Add(num_levels - 2, 9U, "150", "200", 5200);
|
|
|
|
UpdateVersionStorageInfo();
|
|
|
|
// Merging to the second last level: (5200 / 1600 + 1) * 1100
|
|
// Merging to the last level: (50000 / 6300 + 1) * 1300
|
|
ASSERT_EQ(1600u + 4675u + 11617u,
|
|
vstorage_->estimated_compaction_needed_bytes());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, IsBottommostLevelTest) {
|
|
// case 1: Higher levels are empty
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
Add(0, 1U, "a", "m");
|
|
Add(0, 2U, "c", "z");
|
|
Add(1, 3U, "d", "e");
|
|
Add(1, 4U, "l", "p");
|
|
Add(2, 5U, "g", "i");
|
|
Add(2, 6U, "x", "z");
|
|
UpdateVersionStorageInfo();
|
|
SetCompactionInputFilesLevels(2, 1);
|
|
AddToCompactionFiles(3U);
|
|
AddToCompactionFiles(5U);
|
|
bool result =
|
|
Compaction::TEST_IsBottommostLevel(2, vstorage_.get(), input_files_);
|
|
ASSERT_TRUE(result);
|
|
|
|
// case 2: Higher levels have no overlap
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
Add(0, 1U, "a", "m");
|
|
Add(0, 2U, "c", "z");
|
|
Add(1, 3U, "d", "e");
|
|
Add(1, 4U, "l", "p");
|
|
Add(2, 5U, "g", "i");
|
|
Add(2, 6U, "x", "z");
|
|
Add(3, 7U, "k", "p");
|
|
Add(3, 8U, "t", "w");
|
|
Add(4, 9U, "a", "b");
|
|
Add(5, 10U, "c", "cc");
|
|
UpdateVersionStorageInfo();
|
|
SetCompactionInputFilesLevels(2, 1);
|
|
AddToCompactionFiles(3U);
|
|
AddToCompactionFiles(5U);
|
|
result = Compaction::TEST_IsBottommostLevel(2, vstorage_.get(), input_files_);
|
|
ASSERT_TRUE(result);
|
|
|
|
// case 3.1: Higher levels (level 3) have overlap
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
Add(0, 1U, "a", "m");
|
|
Add(0, 2U, "c", "z");
|
|
Add(1, 3U, "d", "e");
|
|
Add(1, 4U, "l", "p");
|
|
Add(2, 5U, "g", "i");
|
|
Add(2, 6U, "x", "z");
|
|
Add(3, 7U, "e", "g");
|
|
Add(3, 8U, "h", "k");
|
|
Add(4, 9U, "a", "b");
|
|
Add(5, 10U, "c", "cc");
|
|
UpdateVersionStorageInfo();
|
|
SetCompactionInputFilesLevels(2, 1);
|
|
AddToCompactionFiles(3U);
|
|
AddToCompactionFiles(5U);
|
|
result = Compaction::TEST_IsBottommostLevel(2, vstorage_.get(), input_files_);
|
|
ASSERT_FALSE(result);
|
|
|
|
// case 3.2: Higher levels (level 5) have overlap
|
|
DeleteVersionStorage();
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
Add(0, 1U, "a", "m");
|
|
Add(0, 2U, "c", "z");
|
|
Add(1, 3U, "d", "e");
|
|
Add(1, 4U, "l", "p");
|
|
Add(2, 5U, "g", "i");
|
|
Add(2, 6U, "x", "z");
|
|
Add(3, 7U, "j", "k");
|
|
Add(3, 8U, "l", "m");
|
|
Add(4, 9U, "a", "b");
|
|
Add(5, 10U, "c", "cc");
|
|
Add(5, 11U, "h", "k");
|
|
Add(5, 12U, "y", "yy");
|
|
Add(5, 13U, "z", "zz");
|
|
UpdateVersionStorageInfo();
|
|
SetCompactionInputFilesLevels(2, 1);
|
|
AddToCompactionFiles(3U);
|
|
AddToCompactionFiles(5U);
|
|
result = Compaction::TEST_IsBottommostLevel(2, vstorage_.get(), input_files_);
|
|
ASSERT_FALSE(result);
|
|
|
|
// case 3.3: Higher levels (level 5) have overlap, but it's only overlapping
|
|
// one key ("d")
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
Add(0, 1U, "a", "m");
|
|
Add(0, 2U, "c", "z");
|
|
Add(1, 3U, "d", "e");
|
|
Add(1, 4U, "l", "p");
|
|
Add(2, 5U, "g", "i");
|
|
Add(2, 6U, "x", "z");
|
|
Add(3, 7U, "j", "k");
|
|
Add(3, 8U, "l", "m");
|
|
Add(4, 9U, "a", "b");
|
|
Add(5, 10U, "c", "cc");
|
|
Add(5, 11U, "ccc", "d");
|
|
Add(5, 12U, "y", "yy");
|
|
Add(5, 13U, "z", "zz");
|
|
UpdateVersionStorageInfo();
|
|
SetCompactionInputFilesLevels(2, 1);
|
|
AddToCompactionFiles(3U);
|
|
AddToCompactionFiles(5U);
|
|
result = Compaction::TEST_IsBottommostLevel(2, vstorage_.get(), input_files_);
|
|
ASSERT_FALSE(result);
|
|
|
|
// Level 0 files overlap
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
Add(0, 1U, "s", "t");
|
|
Add(0, 2U, "a", "m");
|
|
Add(0, 3U, "b", "z");
|
|
Add(0, 4U, "e", "f");
|
|
Add(5, 10U, "y", "z");
|
|
UpdateVersionStorageInfo();
|
|
SetCompactionInputFilesLevels(1, 0);
|
|
AddToCompactionFiles(1U);
|
|
AddToCompactionFiles(2U);
|
|
AddToCompactionFiles(3U);
|
|
AddToCompactionFiles(4U);
|
|
result = Compaction::TEST_IsBottommostLevel(2, vstorage_.get(), input_files_);
|
|
ASSERT_FALSE(result);
|
|
|
|
// Level 0 files don't overlap
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
Add(0, 1U, "s", "t");
|
|
Add(0, 2U, "a", "m");
|
|
Add(0, 3U, "b", "k");
|
|
Add(0, 4U, "e", "f");
|
|
Add(5, 10U, "y", "z");
|
|
UpdateVersionStorageInfo();
|
|
SetCompactionInputFilesLevels(1, 0);
|
|
AddToCompactionFiles(1U);
|
|
AddToCompactionFiles(2U);
|
|
AddToCompactionFiles(3U);
|
|
AddToCompactionFiles(4U);
|
|
result = Compaction::TEST_IsBottommostLevel(2, vstorage_.get(), input_files_);
|
|
ASSERT_TRUE(result);
|
|
|
|
// Level 1 files overlap
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
Add(0, 1U, "s", "t");
|
|
Add(0, 2U, "a", "m");
|
|
Add(0, 3U, "b", "k");
|
|
Add(0, 4U, "e", "f");
|
|
Add(1, 5U, "a", "m");
|
|
Add(1, 6U, "n", "o");
|
|
Add(1, 7U, "w", "y");
|
|
Add(5, 10U, "y", "z");
|
|
UpdateVersionStorageInfo();
|
|
SetCompactionInputFilesLevels(2, 0);
|
|
AddToCompactionFiles(1U);
|
|
AddToCompactionFiles(2U);
|
|
AddToCompactionFiles(3U);
|
|
AddToCompactionFiles(4U);
|
|
AddToCompactionFiles(5U);
|
|
AddToCompactionFiles(6U);
|
|
AddToCompactionFiles(7U);
|
|
result = Compaction::TEST_IsBottommostLevel(2, vstorage_.get(), input_files_);
|
|
ASSERT_FALSE(result);
|
|
|
|
DeleteVersionStorage();
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, MaxCompactionBytesHit) {
|
|
mutable_cf_options_.max_bytes_for_level_base = 1000000u;
|
|
mutable_cf_options_.max_compaction_bytes = 800000u;
|
|
ioptions_.level_compaction_dynamic_level_bytes = false;
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
// A compaction should be triggered and pick file 2 and 5.
|
|
// It cannot expand because adding file 1 and 3, the compaction size will
|
|
// exceed mutable_cf_options_.max_bytes_for_level_base.
|
|
Add(1, 1U, "100", "150", 300000U);
|
|
Add(1, 2U, "151", "200", 300001U, 0, 0);
|
|
Add(1, 3U, "201", "250", 300000U, 0, 0);
|
|
Add(1, 4U, "251", "300", 300000U, 0, 0);
|
|
Add(2, 5U, "160", "256", 1U);
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
ASSERT_EQ(2U, compaction->num_input_levels());
|
|
ASSERT_EQ(1U, compaction->num_input_files(0));
|
|
ASSERT_EQ(1U, compaction->num_input_files(1));
|
|
ASSERT_EQ(2U, compaction->input(0, 0)->fd.GetNumber());
|
|
ASSERT_EQ(5U, compaction->input(1, 0)->fd.GetNumber());
|
|
}
|
|
|
|
TEST_F(CompactionPickerTest, MaxCompactionBytesNotHit) {
|
|
mutable_cf_options_.max_bytes_for_level_base = 1000000u;
|
|
mutable_cf_options_.max_compaction_bytes = 1000000u;
|
|
ioptions_.level_compaction_dynamic_level_bytes = false;
|
|
NewVersionStorage(6, kCompactionStyleLevel);
|
|
// A compaction should be triggered and pick file 2 and 5.
|
|
// and it expands to file 1 and 3 too.
|
|
Add(1, 1U, "100", "150", 300000U);
|
|
Add(1, 2U, "151", "200", 300001U, 0, 0);
|
|
Add(1, 3U, "201", "250", 300000U, 0, 0);
|
|
Add(1, 4U, "251", "300", 300000U, 0, 0);
|
|
Add(2, 5U, "000", "233", 1U);
|
|
UpdateVersionStorageInfo();
|
|
|
|
std::unique_ptr<Compaction> compaction(level_compaction_picker.PickCompaction(
|
|
cf_name_, mutable_cf_options_, vstorage_.get(), &log_buffer_));
|
|
ASSERT_TRUE(compaction.get() != nullptr);
|
|
ASSERT_EQ(2U, compaction->num_input_levels());
|
|
ASSERT_EQ(3U, compaction->num_input_files(0));
|
|
ASSERT_EQ(1U, compaction->num_input_files(1));
|
|
ASSERT_EQ(1U, compaction->input(0, 0)->fd.GetNumber());
|
|
ASSERT_EQ(2U, compaction->input(0, 1)->fd.GetNumber());
|
|
ASSERT_EQ(3U, compaction->input(0, 2)->fd.GetNumber());
|
|
ASSERT_EQ(5U, compaction->input(1, 0)->fd.GetNumber());
|
|
}
|
|
|
|
} // namespace rocksdb
|
|
|
|
int main(int argc, char** argv) {
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
}
|