Revisit the interface of MergeHelper::TimedFullMerge(WithEntity) (#10932)

Summary:
The patch refines/reworks `MergeHelper::TimedFullMerge(WithEntity)`
a bit in two ways. First, it eliminates the recently introduced `TimedFullMerge`
overload, which makes the responsibilities clearer by making sure the query
result (`value` for `Get`, `columns` for `GetEntity`) is set uniformly in
`SaveValue` and `GetContext`. Second, it changes the interface of
`TimedFullMergeWithEntity` so it exposes its result in a serialized form; this
is a more decoupled design which will come in handy when adding support
for `Merge` with wide-column entities to `DBIter`.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/10932

Test Plan: `make check`

Reviewed By: akankshamahajan15

Differential Revision: D41129399

Pulled By: ltamasi

fbshipit-source-id: 69d8da358c77d4fc7e8c40f4dafc2c129a710677
This commit is contained in:
Levi Tamasi 2022-11-09 12:54:05 -08:00 committed by Facebook GitHub Bot
parent c62f322169
commit 2ea109521f
5 changed files with 124 additions and 85 deletions

View File

@ -1066,11 +1066,21 @@ static bool SaveValue(void* arg, const char* entry) {
assert(s->do_merge);
if (s->value || s->columns) {
std::string result;
*(s->status) = MergeHelper::TimedFullMerge(
merge_operator, s->key->user_key(), &v,
merge_context->GetOperands(), s->value, s->columns, s->logger,
s->statistics, s->clock, /* result_operand */ nullptr,
merge_context->GetOperands(), &result, s->logger, s->statistics,
s->clock, /* result_operand */ nullptr,
/* update_num_ops_stats */ true);
if (s->status->ok()) {
if (s->value) {
*(s->value) = std::move(result);
} else {
assert(s->columns);
s->columns->SetPlainValue(result);
}
}
}
} else if (s->value) {
s->value->assign(v.data(), v.size());
@ -1115,11 +1125,27 @@ static bool SaveValue(void* arg, const char* entry) {
} else if (*(s->merge_in_progress)) {
assert(s->do_merge);
if (s->value || s->columns) {
if (s->value) {
Slice value_of_default;
*(s->status) = WideColumnSerialization::GetValueOfDefaultColumn(
v, value_of_default);
if (s->status->ok()) {
*(s->status) = MergeHelper::TimedFullMerge(
merge_operator, s->key->user_key(), &value_of_default,
merge_context->GetOperands(), s->value, s->logger,
s->statistics, s->clock, /* result_operand */ nullptr,
/* update_num_ops_stats */ true);
}
} else if (s->columns) {
std::string result;
*(s->status) = MergeHelper::TimedFullMergeWithEntity(
merge_operator, s->key->user_key(), v,
merge_context->GetOperands(), s->value, s->columns, s->logger,
s->statistics, s->clock, /* update_num_ops_stats */ true);
merge_context->GetOperands(), &result, s->logger, s->statistics,
s->clock, /* update_num_ops_stats */ true);
if (s->status->ok()) {
*(s->status) = s->columns->SetWideColumnValue(result);
}
}
} else if (s->value) {
Slice value_of_default;
@ -1150,11 +1176,21 @@ static bool SaveValue(void* arg, const char* entry) {
case kTypeRangeDeletion: {
if (*(s->merge_in_progress)) {
if (s->value || s->columns) {
std::string result;
*(s->status) = MergeHelper::TimedFullMerge(
merge_operator, s->key->user_key(), nullptr,
merge_context->GetOperands(), s->value, s->columns, s->logger,
s->statistics, s->clock, /* result_operand */ nullptr,
merge_context->GetOperands(), &result, s->logger, s->statistics,
s->clock, /* result_operand */ nullptr,
/* update_num_ops_stats */ true);
if (s->status->ok()) {
if (s->value) {
*(s->value) = std::move(result);
} else {
assert(s->columns);
s->columns->SetPlainValue(result);
}
}
}
} else {
*(s->status) = Status::NotFound();
@ -1180,11 +1216,21 @@ static bool SaveValue(void* arg, const char* entry) {
if (s->do_merge && merge_operator->ShouldMerge(
merge_context->GetOperandsDirectionBackward())) {
if (s->value || s->columns) {
std::string result;
*(s->status) = MergeHelper::TimedFullMerge(
merge_operator, s->key->user_key(), nullptr,
merge_context->GetOperands(), s->value, s->columns, s->logger,
s->statistics, s->clock, /* result_operand */ nullptr,
merge_context->GetOperands(), &result, s->logger, s->statistics,
s->clock, /* result_operand */ nullptr,
/* update_num_ops_stats */ true);
if (s->status->ok()) {
if (s->value) {
*(s->value) = std::move(result);
} else {
assert(s->columns);
s->columns->SetPlainValue(result);
}
}
}
*(s->found_final_value) = true;

View File

@ -112,44 +112,10 @@ Status MergeHelper::TimedFullMerge(const MergeOperator* merge_operator,
return Status::OK();
}
Status MergeHelper::TimedFullMerge(const MergeOperator* merge_operator,
const Slice& key, const Slice* base_value,
const std::vector<Slice>& operands,
std::string* value,
PinnableWideColumns* columns, Logger* logger,
Statistics* statistics, SystemClock* clock,
Slice* result_operand,
bool update_num_ops_stats) {
assert(value || columns);
assert(!value || !columns);
std::string result;
const Status s =
TimedFullMerge(merge_operator, key, base_value, operands, &result, logger,
statistics, clock, result_operand, update_num_ops_stats);
if (!s.ok()) {
return s;
}
if (value) {
*value = std::move(result);
return Status::OK();
}
assert(columns);
columns->SetPlainValue(result);
return Status::OK();
}
Status MergeHelper::TimedFullMergeWithEntity(
const MergeOperator* merge_operator, const Slice& key, Slice base_entity,
const std::vector<Slice>& operands, std::string* value,
PinnableWideColumns* columns, Logger* logger, Statistics* statistics,
SystemClock* clock, bool update_num_ops_stats) {
assert(value || columns);
assert(!value || !columns);
const std::vector<Slice>& operands, std::string* result, Logger* logger,
Statistics* statistics, SystemClock* clock, bool update_num_ops_stats) {
WideColumns base_columns;
{
@ -168,44 +134,35 @@ Status MergeHelper::TimedFullMergeWithEntity(
value_of_default = base_columns[0].value();
}
std::string result;
std::string merge_result;
{
constexpr Slice* result_operand = nullptr;
const Status s = TimedFullMerge(
merge_operator, key, &value_of_default, operands, &result, logger,
merge_operator, key, &value_of_default, operands, &merge_result, logger,
statistics, clock, result_operand, update_num_ops_stats);
if (!s.ok()) {
return s;
}
}
if (value) {
*value = std::move(result);
return Status::OK();
}
assert(columns);
std::string output;
if (has_default_column) {
base_columns[0].value() = result;
base_columns[0].value() = merge_result;
const Status s = WideColumnSerialization::Serialize(base_columns, output);
const Status s = WideColumnSerialization::Serialize(base_columns, *result);
if (!s.ok()) {
return s;
}
} else {
const Status s =
WideColumnSerialization::Serialize(result, base_columns, output);
WideColumnSerialization::Serialize(merge_result, base_columns, *result);
if (!s.ok()) {
return s;
}
}
return columns->SetWideColumnValue(output);
return Status::OK();
}
// PRE: iter points to the first merge type entry

View File

@ -57,19 +57,10 @@ class MergeHelper {
Slice* result_operand,
bool update_num_ops_stats);
static Status TimedFullMerge(const MergeOperator* merge_operator,
const Slice& key, const Slice* base_value,
const std::vector<Slice>& operands,
std::string* value, PinnableWideColumns* columns,
Logger* logger, Statistics* statistics,
SystemClock* clock, Slice* result_operand,
bool update_num_ops_stats);
static Status TimedFullMergeWithEntity(
const MergeOperator* merge_operator, const Slice& key, Slice base_entity,
const std::vector<Slice>& operands, std::string* value,
PinnableWideColumns* columns, Logger* logger, Statistics* statistics,
SystemClock* clock, bool update_num_ops_stats);
const std::vector<Slice>& operands, std::string* result, Logger* logger,
Statistics* statistics, SystemClock* clock, bool update_num_ops_stats);
// During compaction, merge entries until we hit
// - a corrupted key

View File

@ -2384,15 +2384,19 @@ void Version::Get(const ReadOptions& read_options, const LookupKey& k,
}
// merge_operands are in saver and we hit the beginning of the key history
// do a final merge of nullptr and operands;
std::string* str_value = value != nullptr ? value->GetSelf() : nullptr;
if (str_value || columns) {
if (value || columns) {
std::string result;
*status = MergeHelper::TimedFullMerge(
merge_operator_, user_key, nullptr, merge_context->GetOperands(),
str_value, columns, info_log_, db_statistics_, clock_,
&result, info_log_, db_statistics_, clock_,
/* result_operand */ nullptr, /* update_num_ops_stats */ true);
if (status->ok()) {
if (LIKELY(value != nullptr)) {
*(value->GetSelf()) = std::move(result);
value->PinSelf();
} else {
assert(columns != nullptr);
columns->SetPlainValue(result);
}
}
}

View File

@ -468,10 +468,10 @@ void GetContext::Merge(const Slice* value) {
assert(do_merge_);
assert(!pinnable_val_ || !columns_);
std::string result;
const Status s = MergeHelper::TimedFullMerge(
merge_operator_, user_key_, value, merge_context_->GetOperands(),
pinnable_val_ ? pinnable_val_->GetSelf() : nullptr, columns_, logger_,
statistics_, clock_, /* result_operand */ nullptr,
merge_operator_, user_key_, value, merge_context_->GetOperands(), &result,
logger_, statistics_, clock_, /* result_operand */ nullptr,
/* update_num_ops_stats */ true);
if (!s.ok()) {
state_ = kCorrupt;
@ -479,25 +479,66 @@ void GetContext::Merge(const Slice* value) {
}
if (LIKELY(pinnable_val_ != nullptr)) {
*(pinnable_val_->GetSelf()) = std::move(result);
pinnable_val_->PinSelf();
return;
}
assert(columns_);
columns_->SetPlainValue(result);
}
void GetContext::MergeWithEntity(Slice entity) {
assert(do_merge_);
assert(!pinnable_val_ || !columns_);
const Status s = MergeHelper::TimedFullMergeWithEntity(
merge_operator_, user_key_, entity, merge_context_->GetOperands(),
pinnable_val_ ? pinnable_val_->GetSelf() : nullptr, columns_, logger_,
statistics_, clock_, /* update_num_ops_stats */ true);
if (!s.ok()) {
state_ = kCorrupt;
if (LIKELY(pinnable_val_ != nullptr)) {
Slice value_of_default;
{
const Status s = WideColumnSerialization::GetValueOfDefaultColumn(
entity, value_of_default);
if (!s.ok()) {
state_ = kCorrupt;
return;
}
}
{
const Status s = MergeHelper::TimedFullMerge(
merge_operator_, user_key_, &value_of_default,
merge_context_->GetOperands(), pinnable_val_->GetSelf(), logger_,
statistics_, clock_, /* result_operand */ nullptr,
/* update_num_ops_stats */ true);
if (!s.ok()) {
state_ = kCorrupt;
return;
}
}
pinnable_val_->PinSelf();
return;
}
if (LIKELY(pinnable_val_ != nullptr)) {
pinnable_val_->PinSelf();
std::string result;
{
const Status s = MergeHelper::TimedFullMergeWithEntity(
merge_operator_, user_key_, entity, merge_context_->GetOperands(),
&result, logger_, statistics_, clock_, /* update_num_ops_stats */ true);
if (!s.ok()) {
state_ = kCorrupt;
return;
}
}
{
assert(columns_);
const Status s = columns_->SetWideColumnValue(result);
if (!s.ok()) {
state_ = kCorrupt;
return;
}
}
}