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