Optimize GetLatestSequenceForKey

Summary: DBImpl::GetLatestSequenceForKey() can do memcpy's to load a value that will never be used.  This can be optimized by changing all the Get() functions called to optionally not fetch the value (and only fetch the sequencenumber).

Test Plan: optimistic_transaction_test and transaction_test

Reviewers: anthony

Reviewed By: anthony

Subscribers: leveldb, dhruba, hermanlee4

Differential Revision: https://reviews.facebook.net/D52227
This commit is contained in:
Reid Horuff 2015-12-21 16:57:04 -08:00
parent e541dcc8fa
commit da032495d3
3 changed files with 41 additions and 37 deletions

View File

@ -5686,7 +5686,6 @@ Status DBImpl::GetLatestSequenceForKey(SuperVersion* sv, const Slice& key,
bool cache_only, SequenceNumber* seq, bool cache_only, SequenceNumber* seq,
bool* found_record_for_key) { bool* found_record_for_key) {
Status s; Status s;
std::string value;
MergeContext merge_context; MergeContext merge_context;
SequenceNumber current_seq = versions_->LastSequence(); SequenceNumber current_seq = versions_->LastSequence();
@ -5695,11 +5694,8 @@ Status DBImpl::GetLatestSequenceForKey(SuperVersion* sv, const Slice& key,
*seq = kMaxSequenceNumber; *seq = kMaxSequenceNumber;
*found_record_for_key = false; *found_record_for_key = false;
// TODO(agiardullo): Should optimize all the Get() functions below to not
// return a value since we do not use it.
// Check if there is a record for this key in the latest memtable // Check if there is a record for this key in the latest memtable
sv->mem->Get(lkey, &value, &s, &merge_context, seq); sv->mem->Get(lkey, nullptr, &s, &merge_context, seq);
if (!(s.ok() || s.IsNotFound() || s.IsMergeInProgress())) { if (!(s.ok() || s.IsNotFound() || s.IsMergeInProgress())) {
// unexpected error reading memtable. // unexpected error reading memtable.
@ -5717,7 +5713,7 @@ Status DBImpl::GetLatestSequenceForKey(SuperVersion* sv, const Slice& key,
} }
// Check if there is a record for this key in the immutable memtables // Check if there is a record for this key in the immutable memtables
sv->imm->Get(lkey, &value, &s, &merge_context, seq); sv->imm->Get(lkey, nullptr, &s, &merge_context, seq);
if (!(s.ok() || s.IsNotFound() || s.IsMergeInProgress())) { if (!(s.ok() || s.IsNotFound() || s.IsMergeInProgress())) {
// unexpected error reading memtable. // unexpected error reading memtable.
@ -5735,7 +5731,7 @@ Status DBImpl::GetLatestSequenceForKey(SuperVersion* sv, const Slice& key,
} }
// Check if there is a record for this key in the immutable memtables // Check if there is a record for this key in the immutable memtables
sv->imm->GetFromHistory(lkey, &value, &s, &merge_context, seq); sv->imm->GetFromHistory(lkey, nullptr, &s, &merge_context, seq);
if (!(s.ok() || s.IsNotFound() || s.IsMergeInProgress())) { if (!(s.ok() || s.IsNotFound() || s.IsMergeInProgress())) {
// unexpected error reading memtable. // unexpected error reading memtable.
@ -5758,7 +5754,7 @@ Status DBImpl::GetLatestSequenceForKey(SuperVersion* sv, const Slice& key,
// Check tables // Check tables
ReadOptions read_options; ReadOptions read_options;
sv->current->Get(read_options, lkey, &value, &s, &merge_context, sv->current->Get(read_options, lkey, nullptr, &s, &merge_context,
nullptr /* value_found */, found_record_for_key, seq); nullptr /* value_found */, found_record_for_key, seq);
if (!(s.ok() || s.IsNotFound() || s.IsMergeInProgress())) { if (!(s.ok() || s.IsNotFound() || s.IsMergeInProgress())) {

View File

@ -500,7 +500,7 @@ static bool SaveValue(void* arg, const char* entry) {
*(s->status) = *(s->status) =
Status::Corruption("Error: Could not perform merge."); Status::Corruption("Error: Could not perform merge.");
} }
} else { } else if (s->value != nullptr) {
s->value->assign(v.data(), v.size()); s->value->assign(v.data(), v.size());
} }
if (s->inplace_update_support) { if (s->inplace_update_support) {

View File

@ -70,7 +70,9 @@ void GetContext::SaveValue(const Slice& value, SequenceNumber seq) {
appendToReplayLog(replay_log_, kTypeValue, value); appendToReplayLog(replay_log_, kTypeValue, value);
state_ = kFound; state_ = kFound;
value_->assign(value.data(), value.size()); if (value_ != nullptr) {
value_->assign(value.data(), value.size());
}
} }
bool GetContext::SaveValue(const ParsedInternalKey& parsed_key, bool GetContext::SaveValue(const ParsedInternalKey& parsed_key,
@ -93,23 +95,27 @@ bool GetContext::SaveValue(const ParsedInternalKey& parsed_key,
assert(state_ == kNotFound || state_ == kMerge); assert(state_ == kNotFound || state_ == kMerge);
if (kNotFound == state_) { if (kNotFound == state_) {
state_ = kFound; state_ = kFound;
value_->assign(value.data(), value.size()); if (value_ != nullptr) {
value_->assign(value.data(), value.size());
}
} else if (kMerge == state_) { } else if (kMerge == state_) {
assert(merge_operator_ != nullptr); assert(merge_operator_ != nullptr);
state_ = kFound; state_ = kFound;
bool merge_success = false; if (value_ != nullptr) {
{ bool merge_success = false;
StopWatchNano timer(env_, statistics_ != nullptr); {
PERF_TIMER_GUARD(merge_operator_time_nanos); StopWatchNano timer(env_, statistics_ != nullptr);
merge_success = merge_operator_->FullMerge( PERF_TIMER_GUARD(merge_operator_time_nanos);
user_key_, &value, merge_context_->GetOperands(), value_, merge_success = merge_operator_->FullMerge(
logger_); user_key_, &value, merge_context_->GetOperands(), value_,
RecordTick(statistics_, MERGE_OPERATION_TOTAL_TIME, logger_);
timer.ElapsedNanosSafe()); RecordTick(statistics_, MERGE_OPERATION_TOTAL_TIME,
} timer.ElapsedNanosSafe());
if (!merge_success) { }
RecordTick(statistics_, NUMBER_MERGE_FAILURES); if (!merge_success) {
state_ = kCorrupt; RecordTick(statistics_, NUMBER_MERGE_FAILURES);
state_ = kCorrupt;
}
} }
} }
return false; return false;
@ -123,19 +129,21 @@ bool GetContext::SaveValue(const ParsedInternalKey& parsed_key,
state_ = kDeleted; state_ = kDeleted;
} else if (kMerge == state_) { } else if (kMerge == state_) {
state_ = kFound; state_ = kFound;
bool merge_success = false; if (value_ != nullptr) {
{ bool merge_success = false;
StopWatchNano timer(env_, statistics_ != nullptr); {
PERF_TIMER_GUARD(merge_operator_time_nanos); StopWatchNano timer(env_, statistics_ != nullptr);
merge_success = merge_operator_->FullMerge( PERF_TIMER_GUARD(merge_operator_time_nanos);
user_key_, nullptr, merge_context_->GetOperands(), value_, merge_success = merge_operator_->FullMerge(
logger_); user_key_, nullptr, merge_context_->GetOperands(), value_,
RecordTick(statistics_, MERGE_OPERATION_TOTAL_TIME, logger_);
timer.ElapsedNanosSafe()); RecordTick(statistics_, MERGE_OPERATION_TOTAL_TIME,
} timer.ElapsedNanosSafe());
if (!merge_success) { }
RecordTick(statistics_, NUMBER_MERGE_FAILURES); if (!merge_success) {
state_ = kCorrupt; RecordTick(statistics_, NUMBER_MERGE_FAILURES);
state_ = kCorrupt;
}
} }
} }
return false; return false;