mirror of
https://github.com/facebook/rocksdb.git
synced 2026-07-07 14:47:40 +08:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b11a617acd | |||
| f96bb67e5e | |||
| 0b18f648e7 | |||
| 6ef136a7c6 | |||
| ca41f994dd | |||
| f92646cef2 |
+32
-23
@@ -2320,12 +2320,14 @@ Status DBImpl::BackgroundCompaction(bool* madeProgress,
|
||||
} else {
|
||||
// no need to refcount in iteration since it's always under a mutex
|
||||
for (auto cfd : *versions_->GetColumnFamilySet()) {
|
||||
if (!cfd->options()->disable_auto_compactions) {
|
||||
// Pick up latest mutable CF Options and use it throughout the
|
||||
// compaction job
|
||||
auto* mutable_cf_options = cfd->GetLatestMutableCFOptions();
|
||||
if (!mutable_cf_options->disable_auto_compactions) {
|
||||
// NOTE: try to avoid unnecessary copy of MutableCFOptions if
|
||||
// compaction is not necessary. Need to make sure mutex is held
|
||||
// until we make a copy in the following code
|
||||
c.reset(cfd->PickCompaction(
|
||||
*cfd->GetLatestMutableCFOptions(), log_buffer));
|
||||
c.reset(cfd->PickCompaction(*mutable_cf_options, log_buffer));
|
||||
if (c != nullptr) {
|
||||
// update statistics
|
||||
MeasureTime(stats_, NUM_FILES_IN_SINGLE_COMPACTION,
|
||||
@@ -2453,7 +2455,7 @@ void DBImpl::CleanupCompaction(CompactionState* compact, Status status) {
|
||||
compact->builder->Abandon();
|
||||
compact->builder.reset();
|
||||
} else {
|
||||
assert(compact->outfile == nullptr);
|
||||
assert(!status.ok() || compact->outfile == nullptr);
|
||||
}
|
||||
for (size_t i = 0; i < compact->outputs.size(); i++) {
|
||||
const CompactionState::Output& out = compact->outputs[i];
|
||||
@@ -2508,6 +2510,20 @@ Status DBImpl::OpenCompactionOutputFile(
|
||||
pending_outputs_[file_number] = compact->compaction->GetOutputPathId();
|
||||
mutex_.Unlock();
|
||||
}
|
||||
// Make the output file
|
||||
std::string fname = TableFileName(db_options_.db_paths, file_number,
|
||||
compact->compaction->GetOutputPathId());
|
||||
Status s = env_->NewWritableFile(fname, &compact->outfile, env_options_);
|
||||
|
||||
if (!s.ok()) {
|
||||
Log(InfoLogLevel::ERROR_LEVEL, db_options_.info_log,
|
||||
"[%s] OpenCompactionOutputFiles for table #%" PRIu64 " "
|
||||
"fails at NewWritableFile with status %s",
|
||||
compact->compaction->column_family_data()->GetName().c_str(),
|
||||
file_number, s.ToString().c_str());
|
||||
LogFlush(db_options_.info_log);
|
||||
return s;
|
||||
}
|
||||
CompactionState::Output out;
|
||||
out.number = file_number;
|
||||
out.path_id = compact->compaction->GetOutputPathId();
|
||||
@@ -2516,22 +2532,15 @@ Status DBImpl::OpenCompactionOutputFile(
|
||||
out.smallest_seqno = out.largest_seqno = 0;
|
||||
compact->outputs.push_back(out);
|
||||
|
||||
// Make the output file
|
||||
std::string fname = TableFileName(db_options_.db_paths, file_number,
|
||||
compact->compaction->GetOutputPathId());
|
||||
Status s = env_->NewWritableFile(fname, &compact->outfile, env_options_);
|
||||
compact->outfile->SetIOPriority(Env::IO_LOW);
|
||||
compact->outfile->SetPreallocationBlockSize(
|
||||
compact->compaction->OutputFilePreallocationSize(mutable_cf_options));
|
||||
|
||||
if (s.ok()) {
|
||||
compact->outfile->SetIOPriority(Env::IO_LOW);
|
||||
compact->outfile->SetPreallocationBlockSize(
|
||||
compact->compaction->OutputFilePreallocationSize(mutable_cf_options));
|
||||
|
||||
ColumnFamilyData* cfd = compact->compaction->column_family_data();
|
||||
compact->builder.reset(NewTableBuilder(
|
||||
*cfd->ioptions(), cfd->internal_comparator(), compact->outfile.get(),
|
||||
compact->compaction->OutputCompressionType(),
|
||||
cfd->ioptions()->compression_opts));
|
||||
}
|
||||
ColumnFamilyData* cfd = compact->compaction->column_family_data();
|
||||
compact->builder.reset(NewTableBuilder(
|
||||
*cfd->ioptions(), cfd->internal_comparator(), compact->outfile.get(),
|
||||
compact->compaction->OutputCompressionType(),
|
||||
cfd->ioptions()->compression_opts));
|
||||
LogFlush(db_options_.info_log);
|
||||
return s;
|
||||
}
|
||||
@@ -2729,7 +2738,7 @@ Status DBImpl::ProcessKeyValueCompaction(
|
||||
int64_t key_drop_obsolete = 0;
|
||||
int64_t loop_cnt = 0;
|
||||
while (input->Valid() && !shutting_down_.Acquire_Load() &&
|
||||
!cfd->IsDropped()) {
|
||||
!cfd->IsDropped() && status.ok()) {
|
||||
if (++loop_cnt > 1000) {
|
||||
if (key_drop_user > 0) {
|
||||
RecordTick(stats_, COMPACTION_KEY_DROP_USER, key_drop_user);
|
||||
@@ -4232,6 +4241,9 @@ Status DBImpl::SetNewMemtableAndNewLogFile(ColumnFamilyData* cfd,
|
||||
new_superversion = new SuperVersion();
|
||||
}
|
||||
}
|
||||
Log(db_options_.info_log,
|
||||
"[%s] New memtable created with log file: #%" PRIu64 "\n",
|
||||
cfd->GetName().c_str(), new_log_number);
|
||||
mutex_.Lock();
|
||||
if (!s.ok()) {
|
||||
// how do we fail if we're not creating new log?
|
||||
@@ -4264,9 +4276,6 @@ Status DBImpl::SetNewMemtableAndNewLogFile(ColumnFamilyData* cfd,
|
||||
cfd->imm()->Add(cfd->mem());
|
||||
new_mem->Ref();
|
||||
cfd->SetMemtable(new_mem);
|
||||
Log(db_options_.info_log,
|
||||
"[%s] New memtable created with log file: #%" PRIu64 "\n",
|
||||
cfd->GetName().c_str(), logfile_number_);
|
||||
context->superversions_to_free_.push_back(
|
||||
cfd->InstallSuperVersion(new_superversion, &mutex_, mutable_cf_options));
|
||||
return s;
|
||||
|
||||
+246
-14
@@ -120,6 +120,8 @@ static std::string Key(int i) {
|
||||
// Special Env used to delay background operations
|
||||
class SpecialEnv : public EnvWrapper {
|
||||
public:
|
||||
Random rnd_;
|
||||
|
||||
// sstable Sync() calls are blocked while this pointer is non-nullptr.
|
||||
port::AtomicPointer delay_sstable_sync_;
|
||||
|
||||
@@ -153,7 +155,13 @@ class SpecialEnv : public EnvWrapper {
|
||||
|
||||
std::atomic<int> sync_counter_;
|
||||
|
||||
explicit SpecialEnv(Env* base) : EnvWrapper(base) {
|
||||
std::atomic<uint32_t> non_writeable_rate_;
|
||||
|
||||
std::atomic<uint32_t> new_writable_count_;
|
||||
|
||||
std::atomic<uint32_t> periodic_non_writable_;
|
||||
|
||||
explicit SpecialEnv(Env* base) : EnvWrapper(base), rnd_(301) {
|
||||
delay_sstable_sync_.Release_Store(nullptr);
|
||||
drop_writes_.Release_Store(nullptr);
|
||||
no_space_.Release_Store(nullptr);
|
||||
@@ -165,6 +173,9 @@ class SpecialEnv : public EnvWrapper {
|
||||
log_write_error_.Release_Store(nullptr);
|
||||
bytes_written_ = 0;
|
||||
sync_counter_ = 0;
|
||||
non_writeable_rate_ = 0;
|
||||
new_writable_count_ = 0;
|
||||
periodic_non_writable_ = 0;
|
||||
}
|
||||
|
||||
Status NewWritableFile(const std::string& f, unique_ptr<WritableFile>* r,
|
||||
@@ -250,8 +261,19 @@ class SpecialEnv : public EnvWrapper {
|
||||
}
|
||||
};
|
||||
|
||||
if (non_writable_.Acquire_Load() != nullptr) {
|
||||
return Status::IOError("simulated write error");
|
||||
if (non_writeable_rate_.load(std::memory_order_acquire) > 0) {
|
||||
auto random_number = rnd_.Uniform(100);
|
||||
if (random_number < non_writeable_rate_.load()) {
|
||||
return Status::IOError("simulated random write error");
|
||||
}
|
||||
}
|
||||
|
||||
new_writable_count_++;
|
||||
|
||||
auto periodic_fail = periodic_non_writable_.load();
|
||||
if (periodic_fail > 0 &&
|
||||
new_writable_count_.load() % periodic_fail == 0) {
|
||||
return Status::IOError("simulated periodic write error");
|
||||
}
|
||||
|
||||
Status s = target()->NewWritableFile(f, r, soptions);
|
||||
@@ -5864,7 +5886,7 @@ TEST(DBTest, NonWritableFileSystem) {
|
||||
options.env = env_;
|
||||
Reopen(&options);
|
||||
ASSERT_OK(Put("foo", "v1"));
|
||||
env_->non_writable_.Release_Store(env_); // Force errors for new files
|
||||
env_->non_writeable_rate_.store(100); // Force errors for new files
|
||||
std::string big(100000, 'x');
|
||||
int errors = 0;
|
||||
for (int i = 0; i < 20; i++) {
|
||||
@@ -5874,7 +5896,7 @@ TEST(DBTest, NonWritableFileSystem) {
|
||||
}
|
||||
}
|
||||
ASSERT_GT(errors, 0);
|
||||
env_->non_writable_.Release_Store(nullptr);
|
||||
env_->non_writeable_rate_.store(0);
|
||||
} while (ChangeCompactOptions());
|
||||
}
|
||||
|
||||
@@ -8589,6 +8611,142 @@ TEST(DBTest, DynamicMemtableOptions) {
|
||||
ASSERT_TRUE(SizeAtLevel(0) > k128KB + k64KB - 2 * k5KB);
|
||||
}
|
||||
|
||||
TEST(DBTest, FileCreationRandomFailure) {
|
||||
Options options;
|
||||
options.env = env_;
|
||||
options.create_if_missing = true;
|
||||
options.write_buffer_size = 100000; // Small write buffer
|
||||
options.target_file_size_base = 200000;
|
||||
options.max_bytes_for_level_base = 1000000;
|
||||
options.max_bytes_for_level_multiplier = 2;
|
||||
|
||||
DestroyAndReopen(&options);
|
||||
Random rnd(301);
|
||||
|
||||
const int kTestSize = kCDTKeysPerBuffer * 4096;
|
||||
const int kTotalIteration = 100;
|
||||
// the second half of the test involves in random failure
|
||||
// of file creation.
|
||||
const int kRandomFailureTest = kTotalIteration / 2;
|
||||
std::vector<std::string> values;
|
||||
for (int i = 0; i < kTestSize; ++i) {
|
||||
values.push_back("NOT_FOUND");
|
||||
}
|
||||
for (int j = 0; j < kTotalIteration; ++j) {
|
||||
if (j == kRandomFailureTest) {
|
||||
env_->non_writeable_rate_.store(90);
|
||||
}
|
||||
for (int k = 0; k < kTestSize; ++k) {
|
||||
// here we expect some of the Put fails.
|
||||
std::string value = RandomString(&rnd, 100);
|
||||
Status s = Put(Key(k), Slice(value));
|
||||
if (s.ok()) {
|
||||
// update the latest successful put
|
||||
values[k] = value;
|
||||
}
|
||||
// But everything before we simulate the failure-test should succeed.
|
||||
if (j < kRandomFailureTest) {
|
||||
ASSERT_OK(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If rocksdb does not do the correct job, internal assert will fail here.
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
|
||||
// verify we have the latest successful update
|
||||
for (int k = 0; k < kTestSize; ++k) {
|
||||
auto v = Get(Key(k));
|
||||
ASSERT_EQ(v, values[k]);
|
||||
}
|
||||
|
||||
// reopen and reverify we have the latest successful update
|
||||
env_->non_writeable_rate_.store(0);
|
||||
Reopen(&options);
|
||||
for (int k = 0; k < kTestSize; ++k) {
|
||||
auto v = Get(Key(k));
|
||||
ASSERT_EQ(v, values[k]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DBTest, PartialCompactionFailure) {
|
||||
Options options;
|
||||
const int kKeySize = 16;
|
||||
const int kKvSize = 1000;
|
||||
const int kKeysPerBuffer = 100;
|
||||
const int kNumL1Files = 5;
|
||||
options.create_if_missing = true;
|
||||
options.write_buffer_size = kKeysPerBuffer * kKvSize;
|
||||
options.max_write_buffer_number = 2;
|
||||
options.target_file_size_base =
|
||||
options.write_buffer_size *
|
||||
(options.max_write_buffer_number - 1);
|
||||
options.level0_file_num_compaction_trigger = kNumL1Files;
|
||||
options.max_bytes_for_level_base =
|
||||
options.level0_file_num_compaction_trigger *
|
||||
options.target_file_size_base;
|
||||
options.max_bytes_for_level_multiplier = 2;
|
||||
options.compression = kNoCompression;
|
||||
|
||||
// The number of NewWritableFiles calls required by each operation.
|
||||
const int kNumInitialNewWritableFiles = 4;
|
||||
const int kNumLevel0FlushNewWritableFiles =
|
||||
options.level0_file_num_compaction_trigger * 2;
|
||||
const int kNumLevel1NewWritableFiles =
|
||||
options.level0_file_num_compaction_trigger + 1;
|
||||
// This setting will make one of the file-creation fail
|
||||
// in the first L0 -> L1 compaction while making sure
|
||||
// all flushes succeeed.
|
||||
env_->periodic_non_writable_ =
|
||||
kNumInitialNewWritableFiles + kNumLevel0FlushNewWritableFiles +
|
||||
kNumLevel1NewWritableFiles - 3;
|
||||
options.env = env_;
|
||||
|
||||
DestroyAndReopen(&options);
|
||||
|
||||
const int kNumKeys =
|
||||
options.level0_file_num_compaction_trigger *
|
||||
(options.max_write_buffer_number - 1) *
|
||||
kKeysPerBuffer * 1.0;
|
||||
|
||||
Random rnd(301);
|
||||
std::vector<std::string> keys;
|
||||
std::vector<std::string> values;
|
||||
for (int k = 0; k < kNumKeys; ++k) {
|
||||
keys.emplace_back(RandomString(&rnd, kKeySize));
|
||||
values.emplace_back(RandomString(&rnd, kKvSize - kKeySize));
|
||||
ASSERT_OK(Put(Slice(keys[k]), Slice(values[k])));
|
||||
}
|
||||
|
||||
dbfull()->TEST_WaitForFlushMemTable();
|
||||
// Make sure the number of L0 files can trigger compaction.
|
||||
ASSERT_GE(NumTableFilesAtLevel(0),
|
||||
options.level0_file_num_compaction_trigger);
|
||||
auto previous_num_level0_files = NumTableFilesAtLevel(0);
|
||||
// Expect compaction to fail here as one file will fail its
|
||||
// creation.
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
// Verify L0 -> L1 compaction does fail.
|
||||
ASSERT_EQ(NumTableFilesAtLevel(1), 0);
|
||||
// Verify all L0 files are still there.
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0), previous_num_level0_files);
|
||||
|
||||
// All key-values must exist after compaction fails.
|
||||
for (int k = 0; k < kNumKeys; ++k) {
|
||||
ASSERT_EQ(values[k], Get(keys[k]));
|
||||
}
|
||||
|
||||
// Make sure RocksDB will not get into corrupted state.
|
||||
Reopen(&options);
|
||||
|
||||
// Verify again after reopen.
|
||||
for (int k = 0; k < kNumKeys; ++k) {
|
||||
ASSERT_EQ(values[k], Get(keys[k]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST(DBTest, DynamicCompactionOptions) {
|
||||
const uint64_t k64KB = 1 << 16;
|
||||
const uint64_t k128KB = 1 << 17;
|
||||
@@ -8598,14 +8756,13 @@ TEST(DBTest, DynamicCompactionOptions) {
|
||||
options.env = env_;
|
||||
options.create_if_missing = true;
|
||||
options.compression = kNoCompression;
|
||||
options.max_background_compactions = 4;
|
||||
options.hard_rate_limit = 1.1;
|
||||
options.write_buffer_size = k128KB;
|
||||
options.max_write_buffer_number = 2;
|
||||
// Compaction related options
|
||||
options.level0_file_num_compaction_trigger = 3;
|
||||
options.level0_slowdown_writes_trigger = 10;
|
||||
options.level0_stop_writes_trigger = 20;
|
||||
options.level0_slowdown_writes_trigger = 4;
|
||||
options.level0_stop_writes_trigger = 8;
|
||||
options.max_grandparent_overlap_factor = 10;
|
||||
options.expanded_compaction_factor = 25;
|
||||
options.source_compaction_factor = 1;
|
||||
@@ -8613,9 +8770,13 @@ TEST(DBTest, DynamicCompactionOptions) {
|
||||
options.target_file_size_multiplier = 1;
|
||||
options.max_bytes_for_level_base = k256KB;
|
||||
options.max_bytes_for_level_multiplier = 4;
|
||||
|
||||
// Block flush thread and disable compaction thread
|
||||
env_->SetBackgroundThreads(1, Env::LOW);
|
||||
env_->SetBackgroundThreads(1, Env::HIGH);
|
||||
DestroyAndReopen(&options);
|
||||
|
||||
auto gen_l0_kb = [this](int start, int size, int stride = 1) {
|
||||
auto gen_l0_kb = [this](int start, int size, int stride) {
|
||||
Random rnd(301);
|
||||
std::vector<std::string> values;
|
||||
for (int i = 0; i < size; i++) {
|
||||
@@ -8627,11 +8788,11 @@ TEST(DBTest, DynamicCompactionOptions) {
|
||||
|
||||
// Write 3 files that have the same key range, trigger compaction and
|
||||
// result in one L1 file
|
||||
gen_l0_kb(0, 128);
|
||||
gen_l0_kb(0, 128, 1);
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0), 1);
|
||||
gen_l0_kb(0, 128);
|
||||
gen_l0_kb(0, 128, 1);
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0), 2);
|
||||
gen_l0_kb(0, 128);
|
||||
gen_l0_kb(0, 128, 1);
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_EQ("0,1", FilesPerLevel());
|
||||
std::vector<LiveFileMetaData> metadata;
|
||||
@@ -8646,9 +8807,9 @@ TEST(DBTest, DynamicCompactionOptions) {
|
||||
{"target_file_size_base", "65536"}
|
||||
}));
|
||||
|
||||
gen_l0_kb(0, 128);
|
||||
gen_l0_kb(0, 128, 1);
|
||||
ASSERT_EQ("1,1", FilesPerLevel());
|
||||
gen_l0_kb(0, 128);
|
||||
gen_l0_kb(0, 128, 1);
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_EQ("0,2", FilesPerLevel());
|
||||
metadata.clear();
|
||||
@@ -8684,6 +8845,77 @@ TEST(DBTest, DynamicCompactionOptions) {
|
||||
ASSERT_TRUE(SizeAtLevel(1) < 262144 * 1.1);
|
||||
ASSERT_TRUE(SizeAtLevel(2) < 2 * 262144 * 1.1);
|
||||
ASSERT_TRUE(SizeAtLevel(3) < 4 * 262144 * 1.1);
|
||||
// Clean up memtable and L0
|
||||
dbfull()->CompactRange(nullptr, nullptr);
|
||||
// Block compaction
|
||||
SleepingBackgroundTask sleeping_task_low1;
|
||||
env_->Schedule(&SleepingBackgroundTask::DoSleepTask, &sleeping_task_low1,
|
||||
Env::Priority::LOW);
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0), 0);
|
||||
int count = 0;
|
||||
Random rnd(301);
|
||||
WriteOptions wo;
|
||||
wo.timeout_hint_us = 10000;
|
||||
while (Put(Key(count), RandomString(&rnd, 1024), wo).ok() && count < 64) {
|
||||
// Wait for compaction so that put won't timeout
|
||||
dbfull()->TEST_FlushMemTable(true);
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQ(count, 8);
|
||||
// Unblock
|
||||
sleeping_task_low1.WakeUp();
|
||||
sleeping_task_low1.WaitUntilDone();
|
||||
|
||||
// Reduce stop trigger
|
||||
ASSERT_TRUE(dbfull()->SetOptions({
|
||||
{"level0_stop_writes_trigger", "6"}
|
||||
}));
|
||||
dbfull()->CompactRange(nullptr, nullptr);
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0), 0);
|
||||
|
||||
// Block compaction
|
||||
SleepingBackgroundTask sleeping_task_low2;
|
||||
env_->Schedule(&SleepingBackgroundTask::DoSleepTask, &sleeping_task_low2,
|
||||
Env::Priority::LOW);
|
||||
count = 0;
|
||||
while (Put(Key(count), RandomString(&rnd, 1024), wo).ok() && count < 64) {
|
||||
// Wait for compaction so that put won't timeout
|
||||
dbfull()->TEST_FlushMemTable(true);
|
||||
count++;
|
||||
}
|
||||
ASSERT_EQ(count, 6);
|
||||
// Unblock
|
||||
sleeping_task_low2.WakeUp();
|
||||
sleeping_task_low2.WaitUntilDone();
|
||||
|
||||
// Test disable_auto_compactions
|
||||
ASSERT_TRUE(dbfull()->SetOptions({
|
||||
{"disable_auto_compactions", "true"}
|
||||
}));
|
||||
dbfull()->CompactRange(nullptr, nullptr);
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0), 0);
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
ASSERT_OK(Put(Key(i), RandomString(&rnd, 1024)));
|
||||
// Wait for compaction so that put won't timeout
|
||||
dbfull()->TEST_FlushMemTable(true);
|
||||
}
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0), 4);
|
||||
|
||||
ASSERT_TRUE(dbfull()->SetOptions({
|
||||
{"disable_auto_compactions", "false"}
|
||||
}));
|
||||
dbfull()->CompactRange(nullptr, nullptr);
|
||||
ASSERT_EQ(NumTableFilesAtLevel(0), 0);
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
ASSERT_OK(Put(Key(i), RandomString(&rnd, 1024)));
|
||||
// Wait for compaction so that put won't timeout
|
||||
dbfull()->TEST_FlushMemTable(true);
|
||||
}
|
||||
dbfull()->TEST_WaitForCompact();
|
||||
ASSERT_LT(NumTableFilesAtLevel(0), 4);
|
||||
}
|
||||
|
||||
} // namespace rocksdb
|
||||
|
||||
+5
-1
@@ -64,7 +64,7 @@ void VersionEdit::Clear() {
|
||||
column_family_name_.clear();
|
||||
}
|
||||
|
||||
void VersionEdit::EncodeTo(std::string* dst) const {
|
||||
bool VersionEdit::EncodeTo(std::string* dst) const {
|
||||
if (has_comparator_) {
|
||||
PutVarint32(dst, kComparator);
|
||||
PutLengthPrefixedSlice(dst, comparator_);
|
||||
@@ -98,6 +98,9 @@ void VersionEdit::EncodeTo(std::string* dst) const {
|
||||
|
||||
for (size_t i = 0; i < new_files_.size(); i++) {
|
||||
const FileMetaData& f = new_files_[i].second;
|
||||
if (!f.smallest.Valid() || !f.largest.Valid()) {
|
||||
return false;
|
||||
}
|
||||
if (f.fd.GetPathId() == 0) {
|
||||
// Use older format to make sure user can roll back the build if they
|
||||
// don't config multiple DB paths.
|
||||
@@ -131,6 +134,7 @@ void VersionEdit::EncodeTo(std::string* dst) const {
|
||||
if (is_column_family_drop_) {
|
||||
PutVarint32(dst, kColumnFamilyDrop);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool GetInternalKey(Slice* input, InternalKey* dst) {
|
||||
|
||||
+2
-1
@@ -212,7 +212,8 @@ class VersionEdit {
|
||||
is_column_family_drop_ = true;
|
||||
}
|
||||
|
||||
void EncodeTo(std::string* dst) const;
|
||||
// return true on success.
|
||||
bool EncodeTo(std::string* dst) const;
|
||||
Status DecodeFrom(const Slice& src);
|
||||
|
||||
std::string DebugString(bool hex_key = false) const;
|
||||
|
||||
@@ -44,6 +44,16 @@ TEST(VersionEditTest, EncodeDecode) {
|
||||
TestEncodeDecode(edit);
|
||||
}
|
||||
|
||||
TEST(VersionEditTest, EncodeEmptyFile) {
|
||||
VersionEdit edit;
|
||||
edit.AddFile(0, 0, 0, 0,
|
||||
InternalKey(),
|
||||
InternalKey(),
|
||||
0, 0);
|
||||
std::string buffer;
|
||||
ASSERT_TRUE(!edit.EncodeTo(&buffer));
|
||||
}
|
||||
|
||||
TEST(VersionEditTest, ColumnFamilyTest) {
|
||||
VersionEdit edit;
|
||||
edit.SetColumnFamily(2);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#define ROCKSDB_MAJOR 3
|
||||
#define ROCKSDB_MINOR 6
|
||||
#define ROCKSDB_PATCH 0
|
||||
#define ROCKSDB_PATCH 2
|
||||
|
||||
// Do not use these. We made the mistake of declaring macros starting with
|
||||
// double underscore. Now we have to live with our choice. We'll deprecate these
|
||||
|
||||
+19
-4
@@ -736,14 +736,29 @@ class PosixWritableFile : public WritableFile {
|
||||
GetPreallocationStatus(&block_size, &last_allocated_block);
|
||||
if (last_allocated_block > 0) {
|
||||
// trim the extra space preallocated at the end of the file
|
||||
// NOTE(ljin): we probably don't want to surface failure as an IOError,
|
||||
// but it will be nice to log these errors.
|
||||
int dummy __attribute__((unused));
|
||||
dummy = ftruncate(fd_, filesize_); // ignore errors
|
||||
dummy = ftruncate(fd_, filesize_);
|
||||
#ifdef ROCKSDB_FALLOCATE_PRESENT
|
||||
// in some file systems, ftruncate only trims trailing space if the
|
||||
// new file size is smaller than the current size. Calling fallocate
|
||||
// with FALLOC_FL_PUNCH_HOLE flag to explicitly release these unused
|
||||
// blocks. FALLOC_FL_PUNCH_HOLE is supported on at least the following
|
||||
// filesystems:
|
||||
// XFS (since Linux 2.6.38)
|
||||
// ext4 (since Linux 3.0)
|
||||
// Btrfs (since Linux 3.7)
|
||||
// tmpfs (since Linux 3.5)
|
||||
// We ignore error since failure of this operation does not affect
|
||||
// correctness.
|
||||
fallocate(fd_, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
|
||||
filesize_, block_size * last_allocated_block - filesize_);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (close(fd_) < 0) {
|
||||
if (s.ok()) {
|
||||
s = IOError(filename_, errno);
|
||||
}
|
||||
s = IOError(filename_, errno);
|
||||
}
|
||||
fd_ = -1;
|
||||
return s;
|
||||
|
||||
+2
-2
@@ -516,7 +516,7 @@ TEST(EnvPosixTest, AllocateTest) {
|
||||
// allocate 100 MB
|
||||
size_t kPreallocateSize = 100 * 1024 * 1024;
|
||||
size_t kBlockSize = 512;
|
||||
std::string data = "test";
|
||||
std::string data(1024 * 1024, 'a');
|
||||
wfile->SetPreallocationBlockSize(kPreallocateSize);
|
||||
ASSERT_OK(wfile->Append(Slice(data)));
|
||||
ASSERT_OK(wfile->Flush());
|
||||
@@ -538,7 +538,7 @@ TEST(EnvPosixTest, AllocateTest) {
|
||||
stat(fname.c_str(), &f_stat);
|
||||
ASSERT_EQ((unsigned int)data.size(), f_stat.st_size);
|
||||
// verify that preallocated blocks were deallocated on file close
|
||||
ASSERT_GT(st_blocks, f_stat.st_blocks);
|
||||
ASSERT_EQ((f_stat.st_size + kBlockSize - 1) / kBlockSize, f_stat.st_blocks);
|
||||
}
|
||||
#endif // ROCKSDB_FALLOCATE_PRESENT
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ struct MutableCFOptions {
|
||||
options.memtable_prefix_bloom_huge_page_tlb_size),
|
||||
max_successive_merges(options.max_successive_merges),
|
||||
filter_deletes(options.filter_deletes),
|
||||
disable_auto_compactions(options.disable_auto_compactions),
|
||||
level0_file_num_compaction_trigger(
|
||||
options.level0_file_num_compaction_trigger),
|
||||
level0_slowdown_writes_trigger(options.level0_slowdown_writes_trigger),
|
||||
@@ -45,6 +46,7 @@ struct MutableCFOptions {
|
||||
memtable_prefix_bloom_huge_page_tlb_size(0),
|
||||
max_successive_merges(0),
|
||||
filter_deletes(false),
|
||||
disable_auto_compactions(false),
|
||||
level0_file_num_compaction_trigger(0),
|
||||
level0_slowdown_writes_trigger(0),
|
||||
level0_stop_writes_trigger(0),
|
||||
@@ -80,6 +82,7 @@ struct MutableCFOptions {
|
||||
bool filter_deletes;
|
||||
|
||||
// Compaction related options
|
||||
bool disable_auto_compactions;
|
||||
int level0_file_num_compaction_trigger;
|
||||
int level0_slowdown_writes_trigger;
|
||||
int level0_stop_writes_trigger;
|
||||
|
||||
@@ -100,7 +100,9 @@ bool ParseMemtableOptions(const std::string& name, const std::string& value,
|
||||
template<typename OptionsType>
|
||||
bool ParseCompactionOptions(const std::string& name, const std::string& value,
|
||||
OptionsType* new_options) {
|
||||
if (name == "level0_file_num_compaction_trigger") {
|
||||
if (name == "disable_auto_compactions") {
|
||||
new_options->disable_auto_compactions = ParseBoolean(name, value);
|
||||
} else if (name == "level0_file_num_compaction_trigger") {
|
||||
new_options->level0_file_num_compaction_trigger = ParseInt(value);
|
||||
} else if (name == "level0_slowdown_writes_trigger") {
|
||||
new_options->level0_slowdown_writes_trigger = ParseInt(value);
|
||||
@@ -221,8 +223,6 @@ bool GetOptionsFromStrings(
|
||||
new_options->soft_rate_limit = ParseDouble(o.second);
|
||||
} else if (o.first == "hard_rate_limit") {
|
||||
new_options->hard_rate_limit = ParseDouble(o.second);
|
||||
} else if (o.first == "disable_auto_compactions") {
|
||||
new_options->disable_auto_compactions = ParseBoolean(o.first, o.second);
|
||||
} else if (o.first == "purge_redundant_kvs_while_flush") {
|
||||
new_options->purge_redundant_kvs_while_flush =
|
||||
ParseBoolean(o.first, o.second);
|
||||
|
||||
Reference in New Issue
Block a user