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