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