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 #include <algorithm>
8 #include <memory>
9 #include <string>
10 #include <vector>
11 #include "rocksdb/slice.h"
12 
13 namespace ROCKSDB_NAMESPACE {
14 
15 const std::vector<Slice> empty_operand_list;
16 
17 // The merge context for merging a user key.
18 // When doing a Get(), DB will create such a class and pass it when
19 // issuing Get() operation to memtables and version_set. The operands
20 // will be fetched from the context when issuing partial of full merge.
21 class MergeContext {
22  public:
23   // Clear all the operands
Clear()24   void Clear() {
25     if (operand_list_) {
26       operand_list_->clear();
27       copied_operands_->clear();
28     }
29   }
30 
31   // Push a merge operand
32   void PushOperand(const Slice& operand_slice, bool operand_pinned = false) {
33     Initialize();
34     SetDirectionBackward();
35 
36     if (operand_pinned) {
37       operand_list_->push_back(operand_slice);
38     } else {
39       // We need to have our own copy of the operand since it's not pinned
40       copied_operands_->emplace_back(
41           new std::string(operand_slice.data(), operand_slice.size()));
42       operand_list_->push_back(*copied_operands_->back());
43     }
44   }
45 
46   // Push back a merge operand
47   void PushOperandBack(const Slice& operand_slice,
48                        bool operand_pinned = false) {
49     Initialize();
50     SetDirectionForward();
51 
52     if (operand_pinned) {
53       operand_list_->push_back(operand_slice);
54     } else {
55       // We need to have our own copy of the operand since it's not pinned
56       copied_operands_->emplace_back(
57           new std::string(operand_slice.data(), operand_slice.size()));
58       operand_list_->push_back(*copied_operands_->back());
59     }
60   }
61 
62   // return total number of operands in the list
GetNumOperands()63   size_t GetNumOperands() const {
64     if (!operand_list_) {
65       return 0;
66     }
67     return operand_list_->size();
68   }
69 
70   // Get the operand at the index.
GetOperand(int index)71   Slice GetOperand(int index) {
72     assert(operand_list_);
73 
74     SetDirectionForward();
75     return (*operand_list_)[index];
76   }
77 
78   // Same as GetOperandsDirectionForward
GetOperands()79   const std::vector<Slice>& GetOperands() {
80     return GetOperandsDirectionForward();
81   }
82 
83   // Return all the operands in the order as they were merged (passed to
84   // FullMerge or FullMergeV2)
GetOperandsDirectionForward()85   const std::vector<Slice>& GetOperandsDirectionForward() {
86     if (!operand_list_) {
87       return empty_operand_list;
88     }
89 
90     SetDirectionForward();
91     return *operand_list_;
92   }
93 
94   // Return all the operands in the reversed order relative to how they were
95   // merged (passed to FullMerge or FullMergeV2)
GetOperandsDirectionBackward()96   const std::vector<Slice>& GetOperandsDirectionBackward() {
97     if (!operand_list_) {
98       return empty_operand_list;
99     }
100 
101     SetDirectionBackward();
102     return *operand_list_;
103   }
104 
105  private:
Initialize()106   void Initialize() {
107     if (!operand_list_) {
108       operand_list_.reset(new std::vector<Slice>());
109       copied_operands_.reset(new std::vector<std::unique_ptr<std::string>>());
110     }
111   }
112 
SetDirectionForward()113   void SetDirectionForward() {
114     if (operands_reversed_ == true) {
115       std::reverse(operand_list_->begin(), operand_list_->end());
116       operands_reversed_ = false;
117     }
118   }
119 
SetDirectionBackward()120   void SetDirectionBackward() {
121     if (operands_reversed_ == false) {
122       std::reverse(operand_list_->begin(), operand_list_->end());
123       operands_reversed_ = true;
124     }
125   }
126 
127   // List of operands
128   std::unique_ptr<std::vector<Slice>> operand_list_;
129   // Copy of operands that are not pinned.
130   std::unique_ptr<std::vector<std::unique_ptr<std::string>>> copied_operands_;
131   bool operands_reversed_ = true;
132 };
133 
134 }  // namespace ROCKSDB_NAMESPACE
135