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