/src/rocksdb/trace_replay/trace_replay.h
Line | Count | Source |
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 | | |
8 | | #include <atomic> |
9 | | #include <memory> |
10 | | #include <mutex> |
11 | | #include <string> |
12 | | #include <unordered_map> |
13 | | #include <utility> |
14 | | |
15 | | #include "rocksdb/options.h" |
16 | | #include "rocksdb/rocksdb_namespace.h" |
17 | | #include "rocksdb/status.h" |
18 | | #include "rocksdb/trace_record.h" |
19 | | #include "rocksdb/utilities/replayer.h" |
20 | | |
21 | | namespace ROCKSDB_NAMESPACE { |
22 | | |
23 | | // This file contains Tracer and Replayer classes that enable capturing and |
24 | | // replaying RocksDB traces. |
25 | | |
26 | | class ColumnFamilyHandle; |
27 | | class ColumnFamilyData; |
28 | | class DB; |
29 | | class DBImpl; |
30 | | class Env; |
31 | | class Slice; |
32 | | class SystemClock; |
33 | | class TraceReader; |
34 | | class TraceWriter; |
35 | | class WriteBatch; |
36 | | |
37 | | struct ReadOptions; |
38 | | struct TraceOptions; |
39 | | struct WriteOptions; |
40 | | |
41 | | extern const std::string kTraceMagic; |
42 | | const unsigned int kTraceTimestampSize = 8; |
43 | | const unsigned int kTraceTypeSize = 1; |
44 | | const unsigned int kTracePayloadLengthSize = 4; |
45 | | const unsigned int kTraceMetadataSize = |
46 | | kTraceTimestampSize + kTraceTypeSize + kTracePayloadLengthSize; |
47 | | |
48 | | static const int kTraceFileMajorVersion = 0; |
49 | | static const int kTraceFileMinorVersion = 2; |
50 | | |
51 | | // The data structure that defines a single trace. |
52 | | struct Trace { |
53 | | uint64_t ts; // timestamp |
54 | | TraceType type; |
55 | | // Each bit in payload_map stores which corresponding struct member added in |
56 | | // the payload. Each TraceType has its corresponding payload struct. For |
57 | | // example, if bit at position 0 is set in write payload, then the write batch |
58 | | // will be addedd. |
59 | | uint64_t payload_map = 0; |
60 | | // Each trace type has its own payload_struct, which will be serialized in the |
61 | | // payload. |
62 | | std::string payload; |
63 | | |
64 | 0 | void reset() { |
65 | 0 | ts = 0; |
66 | 0 | type = kTraceMax; |
67 | 0 | payload_map = 0; |
68 | 0 | payload.clear(); |
69 | 0 | } |
70 | | }; |
71 | | |
72 | | enum TracePayloadType : char { |
73 | | // Each member of all query payload structs should have a corresponding flag |
74 | | // here. Make sure to add them sequentially in the order of it is added. |
75 | | kEmptyPayload = 0, |
76 | | kWriteBatchData = 1, |
77 | | kGetCFID = 2, |
78 | | kGetKey = 3, |
79 | | kIterCFID = 4, |
80 | | kIterKey = 5, |
81 | | kIterLowerBound = 6, |
82 | | kIterUpperBound = 7, |
83 | | kMultiGetSize = 8, |
84 | | kMultiGetCFIDs = 9, |
85 | | kMultiGetKeys = 10, |
86 | | // TraceOptions::include_read_write_options. Encoded after the fields above, |
87 | | // so a decoder that does not know them can skip them. |
88 | | kWriteOptions = 11, |
89 | | kGetReadOptions = 12, |
90 | | kIterReadOptions = 13, |
91 | | kMultiGetReadOptions = 14, |
92 | | }; |
93 | | |
94 | | // The WriteOptions fields a query trace records with |
95 | | // TraceOptions::include_read_write_options. |
96 | | struct TracedWriteOptions { |
97 | 0 | TracedWriteOptions() = default; |
98 | | explicit TracedWriteOptions(const WriteOptions& options); |
99 | | |
100 | | // Appends a length-prefixed encoding: fields added later go at its end, and |
101 | | // DecodeFrom() ignores what it does not know. |
102 | | void EncodeTo(std::string* dst) const; |
103 | | // Reads one encoding from the front of `input` into `*options`. |
104 | | static Status DecodeFrom(Slice* input, WriteOptions* options); |
105 | | |
106 | | bool sync = false; |
107 | | bool disable_wal = false; |
108 | | bool no_slowdown = false; |
109 | | Env::IOPriority rate_limiter_priority = Env::IO_TOTAL; |
110 | | }; |
111 | | |
112 | | // The ReadOptions fields a query trace records with |
113 | | // TraceOptions::include_read_write_options. An iterator keeps one for the |
114 | | // seeks it traces. |
115 | | struct TracedReadOptions { |
116 | | TracedReadOptions() = default; |
117 | | explicit TracedReadOptions(const ReadOptions& options); |
118 | | |
119 | | // Same contract as TracedWriteOptions::EncodeTo() and DecodeFrom(). |
120 | | void EncodeTo(std::string* dst) const; |
121 | | static Status DecodeFrom(Slice* input, ReadOptions* options); |
122 | | |
123 | | uint64_t readahead_size = 0; |
124 | | uint64_t max_skippable_internal_keys = 0; |
125 | | uint64_t value_size_soft_limit = 0; |
126 | | // Bit i holds the i-th boolean field of kReadOptionsFlags |
127 | | // (trace_replay.cc). |
128 | | uint32_t flags = 0; |
129 | | ReadTier read_tier = kReadAllTier; |
130 | | Env::IOPriority rate_limiter_priority = Env::IO_TOTAL; |
131 | | }; |
132 | | |
133 | | class TracerHelper { |
134 | | public: |
135 | | // Parse the string with major and minor version only |
136 | | static Status ParseVersionStr(std::string& v_string, int* v_num); |
137 | | |
138 | | // Parse the trace file version and db version in trace header |
139 | | static Status ParseTraceHeader(const Trace& header, int* trace_version, |
140 | | int* db_version); |
141 | | |
142 | | // Encode a version 0.1 trace object into the given string. |
143 | | static void EncodeTrace(const Trace& trace, std::string* encoded_trace); |
144 | | |
145 | | // Decode a string into the given trace object. |
146 | | static Status DecodeTrace(const std::string& encoded_trace, Trace* trace); |
147 | | |
148 | | // Decode a string into the given trace header. |
149 | | static Status DecodeHeader(const std::string& encoded_trace, Trace* header); |
150 | | |
151 | | // Set the payload map based on the payload type |
152 | | static bool SetPayloadMap(uint64_t& payload_map, |
153 | | const TracePayloadType payload_type); |
154 | | |
155 | | // Decode a Trace object into the corresponding TraceRecord. |
156 | | // Return Status::OK() if nothing is wrong, record will be set accordingly. |
157 | | // Return Status::NotSupported() if the trace type is not support, or the |
158 | | // corresponding error status, record will be set to nullptr. |
159 | | static Status DecodeTraceRecord(Trace* trace, int trace_file_version, |
160 | | std::unique_ptr<TraceRecord>* record); |
161 | | }; |
162 | | |
163 | | // Tracer captures all RocksDB operations using a user-provided TraceWriter. |
164 | | // Every RocksDB operation is written as a single trace. Each trace will have a |
165 | | // timestamp and type, followed by the trace payload. |
166 | | class Tracer { |
167 | | public: |
168 | | Tracer(SystemClock* clock, const TraceOptions& trace_options, |
169 | | std::unique_ptr<TraceWriter>&& trace_writer); |
170 | | ~Tracer(); |
171 | | |
172 | | // Trace all write operations -- Put, Merge, Delete, SingleDelete, Write. |
173 | | // The options are recorded only with |
174 | | // TraceOptions::include_read_write_options, as are the read options below. |
175 | | Status Write(WriteBatch* write_batch, const TracedWriteOptions& options); |
176 | | |
177 | | // Trace Get operations. |
178 | | Status Get(ColumnFamilyHandle* cfname, const Slice& key, |
179 | | const ReadOptions& read_options); |
180 | | |
181 | | // Trace Iterators. |
182 | | Status IteratorSeek(const uint32_t& cf_id, const Slice& key, |
183 | | const Slice& lower_bound, const Slice upper_bound, |
184 | | const TracedReadOptions& read_options); |
185 | | Status IteratorSeekForPrev(const uint32_t& cf_id, const Slice& key, |
186 | | const Slice& lower_bound, const Slice upper_bound, |
187 | | const TracedReadOptions& read_options); |
188 | | |
189 | | // Trace MultiGet |
190 | | |
191 | | Status MultiGet(const size_t num_keys, ColumnFamilyHandle** column_families, |
192 | | const Slice* keys, const ReadOptions& read_options); |
193 | | |
194 | | Status MultiGet(const size_t num_keys, ColumnFamilyHandle* column_family, |
195 | | const Slice* keys, const ReadOptions& read_options); |
196 | | |
197 | | Status MultiGet(const std::vector<ColumnFamilyHandle*>& column_family, |
198 | | const std::vector<Slice>& keys, |
199 | | const ReadOptions& read_options); |
200 | | |
201 | | // Returns true if the trace is over the configured max trace file limit. |
202 | | // False otherwise. |
203 | | bool IsTraceFileOverMax(); |
204 | | |
205 | | // Returns true if the order of write trace records must match the order of |
206 | | // the corresponding records logged to WAL and applied to the DB. |
207 | 0 | bool IsWriteOrderPreserved() { return trace_options_.preserve_write_order; } |
208 | | |
209 | | // Writes a trace footer at the end of the tracing |
210 | | Status Close(); |
211 | | |
212 | | private: |
213 | | // Write a trace header at the beginning, typically on initiating a trace, |
214 | | // with some metadata like a magic number, trace version, RocksDB version, and |
215 | | // trace format. |
216 | | Status WriteHeader(); |
217 | | |
218 | | // Write a trace footer, typically on ending a trace, with some metadata. |
219 | | Status WriteFooter(); |
220 | | |
221 | | // Write a single trace using the provided TraceWriter to the underlying |
222 | | // system, say, a filesystem or a streaming service. |
223 | | Status WriteTrace(const Trace& trace); |
224 | | |
225 | | // Shared by IteratorSeek() and IteratorSeekForPrev(). |
226 | | Status IteratorSeekImpl(TraceType trace_type, uint32_t cf_id, |
227 | | const Slice& key, const Slice& lower_bound, |
228 | | const Slice& upper_bound, |
229 | | const TracedReadOptions& read_options); |
230 | | |
231 | | // Helps in filtering and sampling of traces. |
232 | | // Returns true if a trace should be skipped, false otherwise. |
233 | | bool ShouldSkipTrace(const TraceType& type); |
234 | | |
235 | | SystemClock* clock_; |
236 | | TraceOptions trace_options_; |
237 | | std::unique_ptr<TraceWriter> trace_writer_; |
238 | | uint64_t trace_request_count_; |
239 | | Status trace_write_status_; |
240 | | }; |
241 | | |
242 | | } // namespace ROCKSDB_NAMESPACE |