merge_operator.cc 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. //
  6. /**
  7. * Back-end implementation details specific to the Merge Operator.
  8. */
  9. #include "rocksdb/merge_operator.h"
  10. #include <type_traits>
  11. #include "db/wide/wide_columns_helper.h"
  12. #include "util/overload.h"
  13. namespace ROCKSDB_NAMESPACE {
  14. bool MergeOperator::FullMergeV2(const MergeOperationInput& merge_in,
  15. MergeOperationOutput* merge_out) const {
  16. // If FullMergeV2 is not implemented, we convert the operand_list to
  17. // std::deque<std::string> and pass it to FullMerge
  18. std::deque<std::string> operand_list_str;
  19. for (auto& op : merge_in.operand_list) {
  20. operand_list_str.emplace_back(op.data(), op.size());
  21. }
  22. return FullMerge(merge_in.key, merge_in.existing_value, operand_list_str,
  23. &merge_out->new_value, merge_in.logger);
  24. }
  25. bool MergeOperator::FullMergeV3(const MergeOperationInputV3& merge_in,
  26. MergeOperationOutputV3* merge_out) const {
  27. assert(merge_out);
  28. Slice value_of_default; // avoid warning about in_v2 pointing at this
  29. MergeOperationInput in_v2(merge_in.key, nullptr, merge_in.operand_list,
  30. merge_in.logger);
  31. std::string new_value;
  32. Slice existing_operand(nullptr, 0);
  33. MergeOperationOutput out_v2(new_value, existing_operand);
  34. return std::visit(
  35. overload{
  36. [&](const auto& existing) -> bool {
  37. using T = std::decay_t<decltype(existing)>;
  38. if constexpr (std::is_same_v<T, Slice>) {
  39. in_v2.existing_value = &existing;
  40. }
  41. const bool result = FullMergeV2(in_v2, &out_v2);
  42. if (!result) {
  43. merge_out->op_failure_scope = out_v2.op_failure_scope;
  44. return false;
  45. }
  46. if (existing_operand.data()) {
  47. merge_out->new_value = existing_operand;
  48. } else {
  49. merge_out->new_value = std::move(new_value);
  50. }
  51. return true;
  52. },
  53. [&](const WideColumns& existing_columns) -> bool {
  54. const bool has_default_column =
  55. WideColumnsHelper::HasDefaultColumn(existing_columns);
  56. if (has_default_column) {
  57. value_of_default = existing_columns.front().value();
  58. }
  59. in_v2.existing_value = &value_of_default;
  60. const bool result = FullMergeV2(in_v2, &out_v2);
  61. if (!result) {
  62. merge_out->op_failure_scope = out_v2.op_failure_scope;
  63. return false;
  64. }
  65. merge_out->new_value = MergeOperationOutputV3::NewColumns();
  66. auto& new_columns = std::get<MergeOperationOutputV3::NewColumns>(
  67. merge_out->new_value);
  68. new_columns.reserve(has_default_column
  69. ? existing_columns.size()
  70. : (existing_columns.size() + 1));
  71. if (existing_operand.data()) {
  72. new_columns.emplace_back(kDefaultWideColumnName.ToString(),
  73. existing_operand.ToString());
  74. } else {
  75. new_columns.emplace_back(kDefaultWideColumnName.ToString(),
  76. std::move(new_value));
  77. }
  78. for (size_t i = has_default_column ? 1 : 0;
  79. i < existing_columns.size(); ++i) {
  80. new_columns.emplace_back(existing_columns[i].name().ToString(),
  81. existing_columns[i].value().ToString());
  82. }
  83. return true;
  84. }},
  85. merge_in.existing_value);
  86. }
  87. // The default implementation of PartialMergeMulti, which invokes
  88. // PartialMerge multiple times internally and merges two operands at
  89. // a time.
  90. bool MergeOperator::PartialMergeMulti(const Slice& key,
  91. const std::deque<Slice>& operand_list,
  92. std::string* new_value,
  93. Logger* logger) const {
  94. assert(operand_list.size() >= 2);
  95. // Simply loop through the operands
  96. Slice temp_slice(operand_list[0]);
  97. for (size_t i = 1; i < operand_list.size(); ++i) {
  98. auto& operand = operand_list[i];
  99. std::string temp_value;
  100. if (!PartialMerge(key, temp_slice, operand, &temp_value, logger)) {
  101. return false;
  102. }
  103. swap(temp_value, *new_value);
  104. temp_slice = Slice(*new_value);
  105. }
  106. // The result will be in *new_value. All merges succeeded.
  107. return true;
  108. }
  109. // Given a "real" merge from the library, call the user's
  110. // associative merge function one-by-one on each of the operands.
  111. // NOTE: It is assumed that the client's merge-operator will handle any errors.
  112. bool AssociativeMergeOperator::FullMergeV2(
  113. const MergeOperationInput& merge_in,
  114. MergeOperationOutput* merge_out) const {
  115. // Simply loop through the operands
  116. Slice temp_existing;
  117. const Slice* existing_value = merge_in.existing_value;
  118. for (const auto& operand : merge_in.operand_list) {
  119. std::string temp_value;
  120. if (!Merge(merge_in.key, existing_value, operand, &temp_value,
  121. merge_in.logger)) {
  122. return false;
  123. }
  124. swap(temp_value, merge_out->new_value);
  125. temp_existing = Slice(merge_out->new_value);
  126. existing_value = &temp_existing;
  127. }
  128. // The result will be in *new_value. All merges succeeded.
  129. return true;
  130. }
  131. // Call the user defined simple merge on the operands;
  132. // NOTE: It is assumed that the client's merge-operator will handle any errors.
  133. bool AssociativeMergeOperator::PartialMerge(const Slice& key,
  134. const Slice& left_operand,
  135. const Slice& right_operand,
  136. std::string* new_value,
  137. Logger* logger) const {
  138. return Merge(key, &left_operand, right_operand, new_value, logger);
  139. }
  140. } // namespace ROCKSDB_NAMESPACE