]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/include/rocksdb/merge_operator.h
import 14.2.4 nautilus point release
[ceph.git] / ceph / src / rocksdb / include / rocksdb / merge_operator.h
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 #pragma once
7
8 #include <deque>
9 #include <memory>
10 #include <string>
11 #include <vector>
12
13 #include "rocksdb/slice.h"
14
15 namespace rocksdb {
16
17 class Slice;
18 class Logger;
19
20 // The Merge Operator
21 //
22 // Essentially, a MergeOperator specifies the SEMANTICS of a merge, which only
23 // client knows. It could be numeric addition, list append, string
24 // concatenation, edit data structure, ... , anything.
25 // The library, on the other hand, is concerned with the exercise of this
26 // interface, at the right time (during get, iteration, compaction...)
27 //
28 // To use merge, the client needs to provide an object implementing one of
29 // the following interfaces:
30 // a) AssociativeMergeOperator - for most simple semantics (always take
31 // two values, and merge them into one value, which is then put back
32 // into rocksdb); numeric addition and string concatenation are examples;
33 //
34 // b) MergeOperator - the generic class for all the more abstract / complex
35 // operations; one method (FullMergeV2) to merge a Put/Delete value with a
36 // merge operand; and another method (PartialMerge) that merges multiple
37 // operands together. this is especially useful if your key values have
38 // complex structures but you would still like to support client-specific
39 // incremental updates.
40 //
41 // AssociativeMergeOperator is simpler to implement. MergeOperator is simply
42 // more powerful.
43 //
44 // Refer to rocksdb-merge wiki for more details and example implementations.
45 //
46 class MergeOperator {
47 public:
48 virtual ~MergeOperator() {}
49
50 // Gives the client a way to express the read -> modify -> write semantics
51 // key: (IN) The key that's associated with this merge operation.
52 // Client could multiplex the merge operator based on it
53 // if the key space is partitioned and different subspaces
54 // refer to different types of data which have different
55 // merge operation semantics
56 // existing: (IN) null indicates that the key does not exist before this op
57 // operand_list:(IN) the sequence of merge operations to apply, front() first.
58 // new_value:(OUT) Client is responsible for filling the merge result here.
59 // The string that new_value is pointing to will be empty.
60 // logger: (IN) Client could use this to log errors during merge.
61 //
62 // Return true on success.
63 // All values passed in will be client-specific values. So if this method
64 // returns false, it is because client specified bad data or there was
65 // internal corruption. This will be treated as an error by the library.
66 //
67 // Also make use of the *logger for error messages.
68 virtual bool FullMerge(const Slice& /*key*/, const Slice* /*existing_value*/,
69 const std::deque<std::string>& /*operand_list*/,
70 std::string* /*new_value*/, Logger* /*logger*/) const {
71 // deprecated, please use FullMergeV2()
72 assert(false);
73 return false;
74 }
75
76 struct MergeOperationInput {
77 explicit MergeOperationInput(const Slice& _key,
78 const Slice* _existing_value,
79 const std::vector<Slice>& _operand_list,
80 Logger* _logger)
81 : key(_key),
82 existing_value(_existing_value),
83 operand_list(_operand_list),
84 logger(_logger) {}
85
86 // The key associated with the merge operation.
87 const Slice& key;
88 // The existing value of the current key, nullptr means that the
89 // value doesn't exist.
90 const Slice* existing_value;
91 // A list of operands to apply.
92 const std::vector<Slice>& operand_list;
93 // Logger could be used by client to log any errors that happen during
94 // the merge operation.
95 Logger* logger;
96 };
97
98 struct MergeOperationOutput {
99 explicit MergeOperationOutput(std::string& _new_value,
100 Slice& _existing_operand)
101 : new_value(_new_value), existing_operand(_existing_operand) {}
102
103 // Client is responsible for filling the merge result here.
104 std::string& new_value;
105 // If the merge result is one of the existing operands (or existing_value),
106 // client can set this field to the operand (or existing_value) instead of
107 // using new_value.
108 Slice& existing_operand;
109 };
110
111 // This function applies a stack of merge operands in chrionological order
112 // on top of an existing value. There are two ways in which this method is
113 // being used:
114 // a) During Get() operation, it used to calculate the final value of a key
115 // b) During compaction, in order to collapse some operands with the based
116 // value.
117 //
118 // Note: The name of the method is somewhat misleading, as both in the cases
119 // of Get() or compaction it may be called on a subset of operands:
120 // K: 0 +1 +2 +7 +4 +5 2 +1 +2
121 // ^
122 // |
123 // snapshot
124 // In the example above, Get(K) operation will call FullMerge with a base
125 // value of 2 and operands [+1, +2]. Compaction process might decide to
126 // collapse the beginning of the history up to the snapshot by performing
127 // full Merge with base value of 0 and operands [+1, +2, +7, +3].
128 virtual bool FullMergeV2(const MergeOperationInput& merge_in,
129 MergeOperationOutput* merge_out) const;
130
131 // This function performs merge(left_op, right_op)
132 // when both the operands are themselves merge operation types
133 // that you would have passed to a DB::Merge() call in the same order
134 // (i.e.: DB::Merge(key,left_op), followed by DB::Merge(key,right_op)).
135 //
136 // PartialMerge should combine them into a single merge operation that is
137 // saved into *new_value, and then it should return true.
138 // *new_value should be constructed such that a call to
139 // DB::Merge(key, *new_value) would yield the same result as a call
140 // to DB::Merge(key, left_op) followed by DB::Merge(key, right_op).
141 //
142 // The string that new_value is pointing to will be empty.
143 //
144 // The default implementation of PartialMergeMulti will use this function
145 // as a helper, for backward compatibility. Any successor class of
146 // MergeOperator should either implement PartialMerge or PartialMergeMulti,
147 // although implementing PartialMergeMulti is suggested as it is in general
148 // more effective to merge multiple operands at a time instead of two
149 // operands at a time.
150 //
151 // If it is impossible or infeasible to combine the two operations,
152 // leave new_value unchanged and return false. The library will
153 // internally keep track of the operations, and apply them in the
154 // correct order once a base-value (a Put/Delete/End-of-Database) is seen.
155 //
156 // TODO: Presently there is no way to differentiate between error/corruption
157 // and simply "return false". For now, the client should simply return
158 // false in any case it cannot perform partial-merge, regardless of reason.
159 // If there is corruption in the data, handle it in the FullMergeV2() function
160 // and return false there. The default implementation of PartialMerge will
161 // always return false.
162 virtual bool PartialMerge(const Slice& /*key*/, const Slice& /*left_operand*/,
163 const Slice& /*right_operand*/,
164 std::string* /*new_value*/,
165 Logger* /*logger*/) const {
166 return false;
167 }
168
169 // This function performs merge when all the operands are themselves merge
170 // operation types that you would have passed to a DB::Merge() call in the
171 // same order (front() first)
172 // (i.e. DB::Merge(key, operand_list[0]), followed by
173 // DB::Merge(key, operand_list[1]), ...)
174 //
175 // PartialMergeMulti should combine them into a single merge operation that is
176 // saved into *new_value, and then it should return true. *new_value should
177 // be constructed such that a call to DB::Merge(key, *new_value) would yield
178 // the same result as subquential individual calls to DB::Merge(key, operand)
179 // for each operand in operand_list from front() to back().
180 //
181 // The string that new_value is pointing to will be empty.
182 //
183 // The PartialMergeMulti function will be called when there are at least two
184 // operands.
185 //
186 // In the default implementation, PartialMergeMulti will invoke PartialMerge
187 // multiple times, where each time it only merges two operands. Developers
188 // should either implement PartialMergeMulti, or implement PartialMerge which
189 // is served as the helper function of the default PartialMergeMulti.
190 virtual bool PartialMergeMulti(const Slice& key,
191 const std::deque<Slice>& operand_list,
192 std::string* new_value, Logger* logger) const;
193
194 // The name of the MergeOperator. Used to check for MergeOperator
195 // mismatches (i.e., a DB created with one MergeOperator is
196 // accessed using a different MergeOperator)
197 // TODO: the name is currently not stored persistently and thus
198 // no checking is enforced. Client is responsible for providing
199 // consistent MergeOperator between DB opens.
200 virtual const char* Name() const = 0;
201
202 // Determines whether the PartialMerge can be called with just a single
203 // merge operand.
204 // Override and return true for allowing a single operand. PartialMerge
205 // and PartialMergeMulti should be overridden and implemented
206 // correctly to properly handle a single operand.
207 virtual bool AllowSingleOperand() const { return false; }
208
209 // Allows to control when to invoke a full merge during Get.
210 // This could be used to limit the number of merge operands that are looked at
211 // during a point lookup, thereby helping in limiting the number of levels to
212 // read from.
213 // Doesn't help with iterators.
214 //
215 // Note: the merge operands are passed to this function in the reversed order
216 // relative to how they were merged (passed to FullMerge or FullMergeV2)
217 // for performance reasons, see also:
218 // https://github.com/facebook/rocksdb/issues/3865
219 virtual bool ShouldMerge(const std::vector<Slice>& /*operands*/) const {
220 return false;
221 }
222 };
223
224 // The simpler, associative merge operator.
225 class AssociativeMergeOperator : public MergeOperator {
226 public:
227 ~AssociativeMergeOperator() override {}
228
229 // Gives the client a way to express the read -> modify -> write semantics
230 // key: (IN) The key that's associated with this merge operation.
231 // existing_value:(IN) null indicates the key does not exist before this op
232 // value: (IN) the value to update/merge the existing_value with
233 // new_value: (OUT) Client is responsible for filling the merge result
234 // here. The string that new_value is pointing to will be empty.
235 // logger: (IN) Client could use this to log errors during merge.
236 //
237 // Return true on success.
238 // All values passed in will be client-specific values. So if this method
239 // returns false, it is because client specified bad data or there was
240 // internal corruption. The client should assume that this will be treated
241 // as an error by the library.
242 virtual bool Merge(const Slice& key, const Slice* existing_value,
243 const Slice& value, std::string* new_value,
244 Logger* logger) const = 0;
245
246 private:
247 // Default implementations of the MergeOperator functions
248 bool FullMergeV2(const MergeOperationInput& merge_in,
249 MergeOperationOutput* merge_out) const override;
250
251 bool PartialMerge(const Slice& key, const Slice& left_operand,
252 const Slice& right_operand, std::string* new_value,
253 Logger* logger) const override;
254 };
255
256 } // namespace rocksdb