1 /**
2  * @author Deon Nicholas (dnicholas@fb.com)
3  * Copyright 2013 Facebook
4  */
5 
6 #include "stringappend2.h"
7 
8 #include <memory>
9 #include <string>
10 #include <assert.h>
11 
12 #include "rocksdb/slice.h"
13 #include "rocksdb/merge_operator.h"
14 #include "utilities/merge_operators.h"
15 
16 namespace rocksdb {
17 
18 // Constructor: also specify the delimiter character.
StringAppendTESTOperator(char delim_char)19 StringAppendTESTOperator::StringAppendTESTOperator(char delim_char)
20     : delim_(delim_char) {
21 }
22 
23 // Implementation for the merge operation (concatenates two strings)
FullMergeV2(const MergeOperationInput & merge_in,MergeOperationOutput * merge_out) const24 bool StringAppendTESTOperator::FullMergeV2(
25     const MergeOperationInput& merge_in,
26     MergeOperationOutput* merge_out) const {
27   // Clear the *new_value for writing.
28   merge_out->new_value.clear();
29 
30   if (merge_in.existing_value == nullptr && merge_in.operand_list.size() == 1) {
31     // Only one operand
32     merge_out->existing_operand = merge_in.operand_list.back();
33     return true;
34   }
35 
36   // Compute the space needed for the final result.
37   size_t numBytes = 0;
38   for (auto it = merge_in.operand_list.begin();
39        it != merge_in.operand_list.end(); ++it) {
40     numBytes += it->size() + 1;   // Plus 1 for the delimiter
41   }
42 
43   // Only print the delimiter after the first entry has been printed
44   bool printDelim = false;
45 
46   // Prepend the *existing_value if one exists.
47   if (merge_in.existing_value) {
48     merge_out->new_value.reserve(numBytes + merge_in.existing_value->size());
49     merge_out->new_value.append(merge_in.existing_value->data(),
50                                 merge_in.existing_value->size());
51     printDelim = true;
52   } else if (numBytes) {
53     merge_out->new_value.reserve(
54         numBytes - 1);  // Minus 1 since we have one less delimiter
55   }
56 
57   // Concatenate the sequence of strings (and add a delimiter between each)
58   for (auto it = merge_in.operand_list.begin();
59        it != merge_in.operand_list.end(); ++it) {
60     if (printDelim) {
61       merge_out->new_value.append(1, delim_);
62     }
63     merge_out->new_value.append(it->data(), it->size());
64     printDelim = true;
65   }
66 
67   return true;
68 }
69 
PartialMergeMulti(const Slice &,const std::deque<Slice> &,std::string *,Logger *) const70 bool StringAppendTESTOperator::PartialMergeMulti(
71     const Slice& /*key*/, const std::deque<Slice>& /*operand_list*/,
72     std::string* /*new_value*/, Logger* /*logger*/) const {
73   return false;
74 }
75 
76 // A version of PartialMerge that actually performs "partial merging".
77 // Use this to simulate the exact behaviour of the StringAppendOperator.
_AssocPartialMergeMulti(const Slice &,const std::deque<Slice> & operand_list,std::string * new_value,Logger *) const78 bool StringAppendTESTOperator::_AssocPartialMergeMulti(
79     const Slice& /*key*/, const std::deque<Slice>& operand_list,
80     std::string* new_value, Logger* /*logger*/) const {
81   // Clear the *new_value for writing
82   assert(new_value);
83   new_value->clear();
84   assert(operand_list.size() >= 2);
85 
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;  // Delimiters
93   new_value->reserve(size);
94 
95   // Apply concatenation
96   new_value->assign(operand_list.front().data(), operand_list.front().size());
97 
98   for (std::deque<Slice>::const_iterator it = operand_list.begin() + 1;
99        it != operand_list.end(); ++it) {
100     new_value->append(1, delim_);
101     new_value->append(it->data(), it->size());
102   }
103 
104   return true;
105 }
106 
Name() const107 const char* StringAppendTESTOperator::Name() const  {
108   return "StringAppendTESTOperator";
109 }
110 
111 
112 std::shared_ptr<MergeOperator>
CreateStringAppendTESTOperator()113 MergeOperators::CreateStringAppendTESTOperator() {
114   return std::make_shared<StringAppendTESTOperator>(',');
115 }
116 
117 } // namespace rocksdb
118