stringappend2.cc 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. // Copyright (c) Meta Platforms, Inc. and affiliates.
  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. #include "stringappend2.h"
  6. #include <cassert>
  7. #include <memory>
  8. #include <string>
  9. #include "rocksdb/merge_operator.h"
  10. #include "rocksdb/slice.h"
  11. #include "rocksdb/utilities/options_type.h"
  12. #include "utilities/merge_operators.h"
  13. namespace ROCKSDB_NAMESPACE {
  14. namespace {
  15. static std::unordered_map<std::string, OptionTypeInfo>
  16. stringappend2_merge_type_info = {
  17. {"delimiter",
  18. {0, OptionType::kString, OptionVerificationType::kNormal,
  19. OptionTypeFlags::kNone}},
  20. };
  21. } // namespace
  22. // Constructor: also specify the delimiter character.
  23. StringAppendTESTOperator::StringAppendTESTOperator(char delim_char)
  24. : delim_(1, delim_char) {
  25. RegisterOptions("Delimiter", &delim_, &stringappend2_merge_type_info);
  26. }
  27. StringAppendTESTOperator::StringAppendTESTOperator(const std::string& delim)
  28. : delim_(delim) {
  29. RegisterOptions("Delimiter", &delim_, &stringappend2_merge_type_info);
  30. }
  31. // Implementation for the merge operation (concatenates two strings)
  32. bool StringAppendTESTOperator::FullMergeV2(
  33. const MergeOperationInput& merge_in,
  34. MergeOperationOutput* merge_out) const {
  35. // Clear the *new_value for writing.
  36. merge_out->new_value.clear();
  37. if (merge_in.existing_value == nullptr && merge_in.operand_list.size() == 1) {
  38. // Only one operand
  39. merge_out->existing_operand = merge_in.operand_list.back();
  40. return true;
  41. }
  42. // Compute the space needed for the final result.
  43. size_t numBytes = 0;
  44. for (auto it = merge_in.operand_list.begin();
  45. it != merge_in.operand_list.end(); ++it) {
  46. numBytes += it->size() + delim_.size();
  47. }
  48. // Only print the delimiter after the first entry has been printed
  49. bool printDelim = false;
  50. // Prepend the *existing_value if one exists.
  51. if (merge_in.existing_value) {
  52. merge_out->new_value.reserve(numBytes + merge_in.existing_value->size());
  53. merge_out->new_value.append(merge_in.existing_value->data(),
  54. merge_in.existing_value->size());
  55. printDelim = true;
  56. } else if (numBytes) {
  57. // Without the existing (initial) value, the delimiter before the first of
  58. // subsequent operands becomes redundant.
  59. merge_out->new_value.reserve(numBytes - delim_.size());
  60. }
  61. // Concatenate the sequence of strings (and add a delimiter between each)
  62. for (auto it = merge_in.operand_list.begin();
  63. it != merge_in.operand_list.end(); ++it) {
  64. if (printDelim) {
  65. merge_out->new_value.append(delim_);
  66. }
  67. merge_out->new_value.append(it->data(), it->size());
  68. printDelim = true;
  69. }
  70. return true;
  71. }
  72. bool StringAppendTESTOperator::PartialMergeMulti(
  73. const Slice& /*key*/, const std::deque<Slice>& /*operand_list*/,
  74. std::string* /*new_value*/, Logger* /*logger*/) const {
  75. return false;
  76. }
  77. // A version of PartialMerge that actually performs "partial merging".
  78. // Use this to simulate the exact behaviour of the StringAppendOperator.
  79. bool StringAppendTESTOperator::_AssocPartialMergeMulti(
  80. const Slice& /*key*/, const std::deque<Slice>& operand_list,
  81. std::string* new_value, Logger* /*logger*/) const {
  82. // Clear the *new_value for writing
  83. assert(new_value);
  84. new_value->clear();
  85. assert(operand_list.size() >= 2);
  86. // Generic append
  87. // Determine and reserve correct size for *new_value.
  88. size_t size = 0;
  89. for (const auto& operand : operand_list) {
  90. size += operand.size();
  91. }
  92. size += (operand_list.size() - 1) * delim_.length(); // Delimiters
  93. new_value->reserve(size);
  94. // Apply concatenation
  95. new_value->assign(operand_list.front().data(), operand_list.front().size());
  96. for (std::deque<Slice>::const_iterator it = operand_list.begin() + 1;
  97. it != operand_list.end(); ++it) {
  98. new_value->append(delim_);
  99. new_value->append(it->data(), it->size());
  100. }
  101. return true;
  102. }
  103. std::shared_ptr<MergeOperator>
  104. MergeOperators::CreateStringAppendTESTOperator() {
  105. return std::make_shared<StringAppendTESTOperator>(',');
  106. }
  107. } // namespace ROCKSDB_NAMESPACE