Skip to content

Commit 011241b

Browse files
committed
DB::Flush() Do not wait for background threads when there is nothing in mem table
Summary: When we have multiple column families, users can issue Flush() on every column families to make sure everything is flushes, even if some of them might be empty. By skipping the waiting for empty cases, it can be greatly speed up. Still wait for people's comments before writing unit tests for it. Test Plan: Will write a unit test to make sure it is correct. Reviewers: ljin, yhchiang, igor Reviewed By: igor Subscribers: leveldb, dhruba Differential Revision: https://reviews.facebook.net/D22953
1 parent a2bb7c3 commit 011241b

File tree

4 files changed

+54
-2
lines changed

4 files changed

+54
-2
lines changed

db/db_impl.cc

+7-1
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ DBImpl::~DBImpl() {
375375
mutex_.Lock();
376376
if (flush_on_destroy_) {
377377
for (auto cfd : *versions_->GetColumnFamilySet()) {
378-
if (cfd->mem()->GetFirstSequenceNumber() != 0) {
378+
if (!cfd->mem()->IsEmpty()) {
379379
cfd->Ref();
380380
mutex_.Unlock();
381381
FlushMemTable(cfd, FlushOptions());
@@ -1905,6 +1905,12 @@ Status DBImpl::FlushMemTable(ColumnFamilyData* cfd,
19051905
{
19061906
WriteContext context;
19071907
MutexLock guard_lock(&mutex_);
1908+
1909+
if (cfd->imm()->size() == 0 && cfd->mem()->IsEmpty()) {
1910+
// Nothing to flush
1911+
return Status::OK();
1912+
}
1913+
19081914
s = BeginWrite(&w, 0);
19091915
assert(s.ok() && !w.done); // No timeout and nobody should do our job
19101916

db/db_test.cc

+43
Original file line numberDiff line numberDiff line change
@@ -2535,6 +2535,49 @@ class SleepingBackgroundTask {
25352535
bool done_with_sleep_;
25362536
};
25372537

2538+
TEST(DBTest, FlushEmptyColumnFamily) {
2539+
// Block flush thread and disable compaction thread
2540+
env_->SetBackgroundThreads(1, Env::HIGH);
2541+
env_->SetBackgroundThreads(1, Env::LOW);
2542+
SleepingBackgroundTask sleeping_task_low;
2543+
env_->Schedule(&SleepingBackgroundTask::DoSleepTask, &sleeping_task_low,
2544+
Env::Priority::LOW);
2545+
SleepingBackgroundTask sleeping_task_high;
2546+
env_->Schedule(&SleepingBackgroundTask::DoSleepTask, &sleeping_task_high,
2547+
Env::Priority::HIGH);
2548+
2549+
Options options = CurrentOptions();
2550+
// disable compaction
2551+
options.disable_auto_compactions = true;
2552+
WriteOptions writeOpt = WriteOptions();
2553+
writeOpt.disableWAL = true;
2554+
options.max_write_buffer_number = 2;
2555+
options.min_write_buffer_number_to_merge = 1;
2556+
CreateAndReopenWithCF({"pikachu"}, &options);
2557+
2558+
// Compaction can still go through even if no thread can flush the
2559+
// mem table.
2560+
ASSERT_OK(Flush(0));
2561+
ASSERT_OK(Flush(1));
2562+
2563+
// Insert can go through
2564+
ASSERT_OK(dbfull()->Put(writeOpt, handles_[0], "foo", "v1"));
2565+
ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "bar", "v1"));
2566+
2567+
ASSERT_EQ("v1", Get(0, "foo"));
2568+
ASSERT_EQ("v1", Get(1, "bar"));
2569+
2570+
sleeping_task_high.WakeUp();
2571+
sleeping_task_high.WaitUntilDone();
2572+
2573+
// Flush can still go through.
2574+
ASSERT_OK(Flush(0));
2575+
ASSERT_OK(Flush(1));
2576+
2577+
sleeping_task_low.WakeUp();
2578+
sleeping_task_low.WaitUntilDone();
2579+
}
2580+
25382581
TEST(DBTest, GetProperty) {
25392582
// Set sizes to both background thread pool to be 1 and block them.
25402583
env_->SetBackgroundThreads(1, Env::HIGH);

db/memtable.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ static bool SaveValue(void* arg, const char* entry) {
414414
bool MemTable::Get(const LookupKey& key, std::string* value, Status* s,
415415
MergeContext& merge_context, const Options& options) {
416416
// The sequence number is updated synchronously in version_set.h
417-
if (first_seqno_ == 0) {
417+
if (IsEmpty()) {
418418
// Avoiding recording stats for speed.
419419
return false;
420420
}

db/memtable.h

+3
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ class MemTable {
137137
// Returns the edits area that is needed for flushing the memtable
138138
VersionEdit* GetEdits() { return &edit_; }
139139

140+
// Returns if there is no entry inserted to the mem table.
141+
bool IsEmpty() const { return first_seqno_ == 0; }
142+
140143
// Returns the sequence number of the first element that was inserted
141144
// into the memtable
142145
SequenceNumber GetFirstSequenceNumber() { return first_seqno_; }

0 commit comments

Comments
 (0)