Cache some conditions for DBImpl::MakeRoomForWrite

Summary:
Task 4580155. Some conditions in DBImpl::MakeRoomForWrite can be cached in
ColumnFamilyData, because theirs value can be changed only during compaction,
adding new memtable and/or add recalculation of compaction score.

These conditions are:

cfd->imm()->size() ==  cfd->options()->max_write_buffer_number - 1
cfd->current()->NumLevelFiles(0) >=  cfd->options()->level0_stop_writes_trigger
cfd->options()->soft_rate_limit > 0.0 &&
    (score = cfd->current()->MaxCompactionScore()) >  cfd->options()->soft_rate_limit
cfd->options()->hard_rate_limit > 1.0 &&
    (score = cfd->current()->MaxCompactionScore()) >  cfd->options()->hard_rate_limit

P.S.
As it's my first diff, Siying suggested to add everybody as a reviewers
for this diff. Sorry, if I forgot someone or add someone by mistake.

Test Plan: make all check

Reviewers: haobo, xjin, dhruba, yhchiang, zagfox, ljin, sdong

Reviewed By: sdong

Subscribers: leveldb

Differential Revision: https://reviews.facebook.net/D19311
main
Stanislau Hlebik 11 years ago
parent 81c5d98900
commit a3594867ba
  1. 38
      db/column_family.cc
  2. 40
      db/column_family.h
  3. 19
      db/db_impl.cc

@ -243,6 +243,8 @@ ColumnFamilyData::ColumnFamilyData(const std::string& dbname, uint32_t id,
const ColumnFamilyOptions* cf_options = &options_; const ColumnFamilyOptions* cf_options = &options_;
cf_options->Dump(options_.info_log.get()); cf_options->Dump(options_.info_log.get());
} }
RecalculateWriteStallConditions();
} }
// DB mutex held // DB mutex held
@ -295,6 +297,35 @@ ColumnFamilyData::~ColumnFamilyData() {
} }
} }
void ColumnFamilyData::RecalculateWriteStallConditions() {
need_wait_for_num_memtables_ =
(imm()->size() == options()->max_write_buffer_number - 1);
if (current_ != nullptr) {
need_wait_for_num_level0_files_ =
(current_->NumLevelFiles(0) >= options()->level0_stop_writes_trigger);
} else {
need_wait_for_num_level0_files_ = false;
}
RecalculateWriteStallRateLimitsConditions();
}
void ColumnFamilyData::RecalculateWriteStallRateLimitsConditions() {
if (current_ != nullptr) {
exceeds_hard_rate_limit_ =
(options()->hard_rate_limit > 1.0 &&
current_->MaxCompactionScore() > options()->hard_rate_limit);
exceeds_soft_rate_limit_ =
(options()->soft_rate_limit > 0.0 &&
current_->MaxCompactionScore() > options()->soft_rate_limit);
} else {
exceeds_hard_rate_limit_ = false;
exceeds_soft_rate_limit_ = false;
}
}
const EnvOptions* ColumnFamilyData::soptions() const { const EnvOptions* ColumnFamilyData::soptions() const {
return &(column_family_set_->storage_options_); return &(column_family_set_->storage_options_);
} }
@ -316,7 +347,9 @@ void ColumnFamilyData::CreateNewMemtable() {
} }
Compaction* ColumnFamilyData::PickCompaction(LogBuffer* log_buffer) { Compaction* ColumnFamilyData::PickCompaction(LogBuffer* log_buffer) {
return compaction_picker_->PickCompaction(current_, log_buffer); auto result = compaction_picker_->PickCompaction(current_, log_buffer);
RecalculateWriteStallRateLimitsConditions();
return result;
} }
Compaction* ColumnFamilyData::CompactRange(int input_level, int output_level, Compaction* ColumnFamilyData::CompactRange(int input_level, int output_level,
@ -420,6 +453,9 @@ SuperVersion* ColumnFamilyData::InstallSuperVersion(
if (column_family_set_->db_options_->allow_thread_local) { if (column_family_set_->db_options_->allow_thread_local) {
ResetThreadLocalSuperVersions(); ResetThreadLocalSuperVersions();
} }
RecalculateWriteStallConditions();
if (old_superversion != nullptr && old_superversion->Unref()) { if (old_superversion != nullptr && old_superversion->Unref()) {
old_superversion->Cleanup(); old_superversion->Cleanup();
return old_superversion; // will let caller delete outside of mutex return old_superversion; // will let caller delete outside of mutex

@ -229,6 +229,22 @@ class ColumnFamilyData {
return need_slowdown_for_num_level0_files_; return need_slowdown_for_num_level0_files_;
} }
bool NeedWaitForNumLevel0Files() const {
return need_wait_for_num_level0_files_;
}
bool NeedWaitForNumMemtables() const {
return need_wait_for_num_memtables_;
}
bool ExceedsSoftRateLimit() const {
return exceeds_soft_rate_limit_;
}
bool ExceedsHardRateLimit() const {
return exceeds_hard_rate_limit_;
}
private: private:
friend class ColumnFamilySet; friend class ColumnFamilySet;
ColumnFamilyData(const std::string& dbname, uint32_t id, ColumnFamilyData(const std::string& dbname, uint32_t id,
@ -238,6 +254,14 @@ class ColumnFamilyData {
const EnvOptions& storage_options, const EnvOptions& storage_options,
ColumnFamilySet* column_family_set); ColumnFamilySet* column_family_set);
// Recalculate some small conditions, which are changed only during
// compaction, adding new memtable and/or
// recalculation of compaction score. These values are used in
// DBImpl::MakeRoomForWrite function to decide, if it need to make
// a write stall
void RecalculateWriteStallConditions();
void RecalculateWriteStallRateLimitsConditions();
uint32_t id_; uint32_t id_;
const std::string name_; const std::string name_;
Version* dummy_versions_; // Head of circular doubly-linked list of versions. Version* dummy_versions_; // Head of circular doubly-linked list of versions.
@ -282,6 +306,22 @@ class ColumnFamilyData {
// we have too many level 0 files // we have too many level 0 files
bool need_slowdown_for_num_level0_files_; bool need_slowdown_for_num_level0_files_;
// These 4 variables are updated only after compaction,
// adding new memtable, flushing memtables to files
// and/or add recalculation of compaction score.
// That's why theirs values are cached in ColumnFamilyData.
// Recalculation is made by RecalculateWriteStallConditions and
// RecalculateWriteStallRateLimitsConditions function. They are used
// in DBImpl::MakeRoomForWrite function to decide, if it need
// to sleep during write operation
bool need_wait_for_num_memtables_;
bool need_wait_for_num_level0_files_;
bool exceeds_hard_rate_limit_;
bool exceeds_soft_rate_limit_;
// An object that keeps all the compaction stats // An object that keeps all the compaction stats
// and picks the next compaction // and picks the next compaction
std::unique_ptr<CompactionPicker> compaction_picker_; std::unique_ptr<CompactionPicker> compaction_picker_;

@ -4026,8 +4026,7 @@ Status DBImpl::MakeRoomForWrite(
DelayLoggingAndReset(); DelayLoggingAndReset();
} }
break; break;
} else if (cfd->imm()->size() == } else if (cfd->NeedWaitForNumMemtables()) {
cfd->options()->max_write_buffer_number - 1) {
// We have filled up the current memtable, but the previous // We have filled up the current memtable, but the previous
// ones are still being flushed, so we wait. // ones are still being flushed, so we wait.
DelayLoggingAndReset(); DelayLoggingAndReset();
@ -4048,9 +4047,7 @@ Status DBImpl::MakeRoomForWrite(
STALL_MEMTABLE_COMPACTION_MICROS, stall); STALL_MEMTABLE_COMPACTION_MICROS, stall);
cfd->internal_stats()->RecordWriteStall( cfd->internal_stats()->RecordWriteStall(
InternalStats::MEMTABLE_COMPACTION, stall); InternalStats::MEMTABLE_COMPACTION, stall);
} else if (cfd->current()->NumLevelFiles(0) >= } else if (cfd->NeedWaitForNumLevel0Files()) {
cfd->options()->level0_stop_writes_trigger) {
// There are too many level-0 files.
DelayLoggingAndReset(); DelayLoggingAndReset();
Log(options_.info_log, "[%s] wait for fewer level0 files...\n", Log(options_.info_log, "[%s] wait for fewer level0 files...\n",
cfd->GetName().c_str()); cfd->GetName().c_str());
@ -4064,12 +4061,10 @@ Status DBImpl::MakeRoomForWrite(
RecordTick(options_.statistics.get(), STALL_L0_NUM_FILES_MICROS, stall); RecordTick(options_.statistics.get(), STALL_L0_NUM_FILES_MICROS, stall);
cfd->internal_stats()->RecordWriteStall(InternalStats::LEVEL0_NUM_FILES, cfd->internal_stats()->RecordWriteStall(InternalStats::LEVEL0_NUM_FILES,
stall); stall);
} else if (allow_hard_rate_limit_delay && } else if (allow_hard_rate_limit_delay && cfd->ExceedsHardRateLimit()) {
cfd->options()->hard_rate_limit > 1.0 &&
(score = cfd->current()->MaxCompactionScore()) >
cfd->options()->hard_rate_limit) {
// Delay a write when the compaction score for any level is too large. // Delay a write when the compaction score for any level is too large.
int max_level = cfd->current()->MaxCompactionScoreLevel(); int max_level = cfd->current()->MaxCompactionScoreLevel();
score = cfd->current()->MaxCompactionScore();
mutex_.Unlock(); mutex_.Unlock();
uint64_t delayed; uint64_t delayed;
{ {
@ -4090,10 +4085,8 @@ Status DBImpl::MakeRoomForWrite(
allow_hard_rate_limit_delay = false; allow_hard_rate_limit_delay = false;
} }
mutex_.Lock(); mutex_.Lock();
} else if (allow_soft_rate_limit_delay && } else if (allow_soft_rate_limit_delay && cfd->ExceedsSoftRateLimit()) {
cfd->options()->soft_rate_limit > 0.0 && score = cfd->current()->MaxCompactionScore();
(score = cfd->current()->MaxCompactionScore()) >
cfd->options()->soft_rate_limit) {
// Delay a write when the compaction score for any level is too large. // Delay a write when the compaction score for any level is too large.
// TODO: add statistics // TODO: add statistics
mutex_.Unlock(); mutex_.Unlock();

Loading…
Cancel
Save