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