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 
10 #include "rocksdb/merge_operator.h"
11 
12 namespace ROCKSDB_NAMESPACE {
13 
FullMergeV2(const MergeOperationInput & merge_in,MergeOperationOutput * merge_out) const14 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 
26 // The default implementation of PartialMergeMulti, which invokes
27 // PartialMerge multiple times internally and merges two operands at
28 // a time.
PartialMergeMulti(const Slice & key,const std::deque<Slice> & operand_list,std::string * new_value,Logger * logger) const29 bool MergeOperator::PartialMergeMulti(const Slice& key,
30                                       const std::deque<Slice>& operand_list,
31                                       std::string* new_value,
32                                       Logger* logger) const {
33   assert(operand_list.size() >= 2);
34   // Simply loop through the operands
35   Slice temp_slice(operand_list[0]);
36 
37   for (size_t i = 1; i < operand_list.size(); ++i) {
38     auto& operand = operand_list[i];
39     std::string temp_value;
40     if (!PartialMerge(key, temp_slice, operand, &temp_value, logger)) {
41       return false;
42     }
43     swap(temp_value, *new_value);
44     temp_slice = Slice(*new_value);
45   }
46 
47   // The result will be in *new_value. All merges succeeded.
48   return true;
49 }
50 
51 // Given a "real" merge from the library, call the user's
52 // associative merge function one-by-one on each of the operands.
53 // NOTE: It is assumed that the client's merge-operator will handle any errors.
FullMergeV2(const MergeOperationInput & merge_in,MergeOperationOutput * merge_out) const54 bool AssociativeMergeOperator::FullMergeV2(
55     const MergeOperationInput& merge_in,
56     MergeOperationOutput* merge_out) const {
57   // Simply loop through the operands
58   Slice temp_existing;
59   const Slice* existing_value = merge_in.existing_value;
60   for (const auto& operand : merge_in.operand_list) {
61     std::string temp_value;
62     if (!Merge(merge_in.key, existing_value, operand, &temp_value,
63                merge_in.logger)) {
64       return false;
65     }
66     swap(temp_value, merge_out->new_value);
67     temp_existing = Slice(merge_out->new_value);
68     existing_value = &temp_existing;
69   }
70 
71   // The result will be in *new_value. All merges succeeded.
72   return true;
73 }
74 
75 // Call the user defined simple merge on the operands;
76 // NOTE: It is assumed that the client's merge-operator will handle any errors.
PartialMerge(const Slice & key,const Slice & left_operand,const Slice & right_operand,std::string * new_value,Logger * logger) const77 bool AssociativeMergeOperator::PartialMerge(
78     const Slice& key,
79     const Slice& left_operand,
80     const Slice& right_operand,
81     std::string* new_value,
82     Logger* logger) const {
83   return Merge(key, &left_operand, right_operand, new_value, logger);
84 }
85 
86 }  // namespace ROCKSDB_NAMESPACE
87