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 <string> 8 #include "db/dbformat.h" 9 #include "db/merge_context.h" 10 #include "db/read_callback.h" 11 #include "rocksdb/env.h" 12 #include "rocksdb/statistics.h" 13 #include "rocksdb/types.h" 14 #include "table/block_based/block.h" 15 16 namespace ROCKSDB_NAMESPACE { 17 class MergeContext; 18 class PinnedIteratorsManager; 19 20 // Data structure for accumulating statistics during a point lookup. At the 21 // end of the point lookup, the corresponding ticker stats are updated. This 22 // avoids the overhead of frequent ticker stats updates 23 struct GetContextStats { 24 uint64_t num_cache_hit = 0; 25 uint64_t num_cache_index_hit = 0; 26 uint64_t num_cache_data_hit = 0; 27 uint64_t num_cache_filter_hit = 0; 28 uint64_t num_cache_compression_dict_hit = 0; 29 uint64_t num_cache_index_miss = 0; 30 uint64_t num_cache_filter_miss = 0; 31 uint64_t num_cache_data_miss = 0; 32 uint64_t num_cache_compression_dict_miss = 0; 33 uint64_t num_cache_bytes_read = 0; 34 uint64_t num_cache_miss = 0; 35 uint64_t num_cache_add = 0; 36 uint64_t num_cache_bytes_write = 0; 37 uint64_t num_cache_index_add = 0; 38 uint64_t num_cache_index_bytes_insert = 0; 39 uint64_t num_cache_data_add = 0; 40 uint64_t num_cache_data_bytes_insert = 0; 41 uint64_t num_cache_filter_add = 0; 42 uint64_t num_cache_filter_bytes_insert = 0; 43 uint64_t num_cache_compression_dict_add = 0; 44 uint64_t num_cache_compression_dict_bytes_insert = 0; 45 }; 46 47 // A class to hold context about a point lookup, such as pointer to value 48 // slice, key, merge context etc, as well as the current state of the 49 // lookup. Any user using GetContext to track the lookup result must call 50 // SaveValue() whenever the internal key is found. This can happen 51 // repeatedly in case of merge operands. In case the key may exist with 52 // high probability, but IO is required to confirm and the user doesn't allow 53 // it, MarkKeyMayExist() must be called instead of SaveValue(). 54 class GetContext { 55 public: 56 // Current state of the point lookup. All except kNotFound and kMerge are 57 // terminal states 58 enum GetState { 59 kNotFound, 60 kFound, 61 kDeleted, 62 kCorrupt, 63 kMerge, // saver contains the current merge result (the operands) 64 kBlobIndex, 65 }; 66 GetContextStats get_context_stats_; 67 68 // Constructor 69 // @param value Holds the value corresponding to user_key. If its nullptr 70 // then return all merge operands corresponding to user_key 71 // via merge_context 72 // @param value_found If non-nullptr, set to false if key may be present 73 // but we can't be certain because we cannot do IO 74 // @param max_covering_tombstone_seq Pointer to highest sequence number of 75 // range deletion covering the key. When an internal key 76 // is found with smaller sequence number, the lookup 77 // terminates 78 // @param seq If non-nullptr, the sequence number of the found key will be 79 // saved here 80 // @param callback Pointer to ReadCallback to perform additional checks 81 // for visibility of a key 82 // @param is_blob_index If non-nullptr, will be used to indicate if a found 83 // key is of type blob index 84 // @param do_merge True if value associated with user_key has to be returned 85 // and false if all the merge operands associated with user_key has to be 86 // returned. Id do_merge=false then all the merge operands are stored in 87 // merge_context and they are never merged. The value pointer is untouched. 88 GetContext(const Comparator* ucmp, const MergeOperator* merge_operator, 89 Logger* logger, Statistics* statistics, GetState init_state, 90 const Slice& user_key, PinnableSlice* value, 91 bool* value_found, MergeContext* merge_context, bool do_merge, 92 SequenceNumber* max_covering_tombstone_seq, Env* env, 93 SequenceNumber* seq = nullptr, 94 PinnedIteratorsManager* _pinned_iters_mgr = nullptr, 95 ReadCallback* callback = nullptr, bool* is_blob_index = nullptr, 96 uint64_t tracing_get_id = 0); 97 GetContext(const Comparator* ucmp, const MergeOperator* merge_operator, 98 Logger* logger, Statistics* statistics, GetState init_state, 99 const Slice& user_key, PinnableSlice* value, 100 std::string* timestamp, bool* value_found, 101 MergeContext* merge_context, bool do_merge, 102 SequenceNumber* max_covering_tombstone_seq, Env* env, 103 SequenceNumber* seq = nullptr, 104 PinnedIteratorsManager* _pinned_iters_mgr = nullptr, 105 ReadCallback* callback = nullptr, bool* is_blob_index = nullptr, 106 uint64_t tracing_get_id = 0); 107 108 GetContext() = delete; 109 110 // This can be called to indicate that a key may be present, but cannot be 111 // confirmed due to IO not allowed 112 void MarkKeyMayExist(); 113 114 // Records this key, value, and any meta-data (such as sequence number and 115 // state) into this GetContext. 116 // 117 // If the parsed_key matches the user key that we are looking for, sets 118 // matched to true. 119 // 120 // Returns True if more keys need to be read (due to merges) or 121 // False if the complete value has been found. 122 bool SaveValue(const ParsedInternalKey& parsed_key, const Slice& value, 123 bool* matched, Cleanable* value_pinner = nullptr); 124 125 // Simplified version of the previous function. Should only be used when we 126 // know that the operation is a Put. 127 void SaveValue(const Slice& value, SequenceNumber seq); 128 State()129 GetState State() const { return state_; } 130 max_covering_tombstone_seq()131 SequenceNumber* max_covering_tombstone_seq() { 132 return max_covering_tombstone_seq_; 133 } 134 pinned_iters_mgr()135 PinnedIteratorsManager* pinned_iters_mgr() { return pinned_iters_mgr_; } 136 137 // If a non-null string is passed, all the SaveValue calls will be 138 // logged into the string. The operations can then be replayed on 139 // another GetContext with replayGetContextLog. SetReplayLog(std::string * replay_log)140 void SetReplayLog(std::string* replay_log) { replay_log_ = replay_log; } 141 142 // Do we need to fetch the SequenceNumber for this key? NeedToReadSequence()143 bool NeedToReadSequence() const { return (seq_ != nullptr); } 144 sample()145 bool sample() const { return sample_; } 146 CheckCallback(SequenceNumber seq)147 bool CheckCallback(SequenceNumber seq) { 148 if (callback_) { 149 return callback_->IsVisible(seq); 150 } 151 return true; 152 } 153 154 void ReportCounters(); 155 has_callback()156 bool has_callback() const { return callback_ != nullptr; } 157 get_tracing_get_id()158 uint64_t get_tracing_get_id() const { return tracing_get_id_; } 159 160 void push_operand(const Slice& value, Cleanable* value_pinner); 161 162 private: 163 const Comparator* ucmp_; 164 const MergeOperator* merge_operator_; 165 // the merge operations encountered; 166 Logger* logger_; 167 Statistics* statistics_; 168 169 GetState state_; 170 Slice user_key_; 171 PinnableSlice* pinnable_val_; 172 std::string* timestamp_; 173 bool* value_found_; // Is value set correctly? Used by KeyMayExist 174 MergeContext* merge_context_; 175 SequenceNumber* max_covering_tombstone_seq_; 176 Env* env_; 177 // If a key is found, seq_ will be set to the SequenceNumber of most recent 178 // write to the key or kMaxSequenceNumber if unknown 179 SequenceNumber* seq_; 180 std::string* replay_log_; 181 // Used to temporarily pin blocks when state_ == GetContext::kMerge 182 PinnedIteratorsManager* pinned_iters_mgr_; 183 ReadCallback* callback_; 184 bool sample_; 185 // Value is true if it's called as part of DB Get API and false if it's 186 // called as part of DB GetMergeOperands API. When it's false merge operators 187 // are never merged. 188 bool do_merge_; 189 bool* is_blob_index_; 190 // Used for block cache tracing only. A tracing get id uniquely identifies a 191 // Get or a MultiGet. 192 const uint64_t tracing_get_id_; 193 }; 194 195 // Call this to replay a log and bring the get_context up to date. The replay 196 // log must have been created by another GetContext object, whose replay log 197 // must have been set by calling GetContext::SetReplayLog(). 198 void replayGetContextLog(const Slice& replay_log, const Slice& user_key, 199 GetContext* get_context, 200 Cleanable* value_pinner = nullptr); 201 202 } // namespace ROCKSDB_NAMESPACE 203