Coverage Report

Created: 2026-11-12 08:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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