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.cc
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
#include "trace_replay/trace_replay.h"
7
8
#include <chrono>
9
#include <iterator>
10
#include <optional>
11
#include <sstream>
12
#include <thread>
13
14
#include "db/db_impl/db_impl.h"
15
#include "rocksdb/env.h"
16
#include "rocksdb/iterator.h"
17
#include "rocksdb/options.h"
18
#include "rocksdb/slice.h"
19
#include "rocksdb/system_clock.h"
20
#include "rocksdb/trace_reader_writer.h"
21
#include "rocksdb/write_batch.h"
22
#include "util/coding.h"
23
#include "util/string_util.h"
24
25
namespace ROCKSDB_NAMESPACE {
26
27
const std::string kTraceMagic = "feedcafedeadbeef";
28
29
namespace {
30
31
// The boolean ReadOptions fields TracedReadOptions records, by bit. Append
32
// only: a field's bit is part of the trace format.
33
constexpr bool ReadOptions::* kReadOptionsFlags[] = {
34
    &ReadOptions::verify_checksums,
35
    &ReadOptions::fill_cache,
36
    &ReadOptions::ignore_range_deletions,
37
    &ReadOptions::async_io,
38
    &ReadOptions::optimize_multiget_for_io,
39
    &ReadOptions::tailing,
40
    &ReadOptions::total_order_seek,
41
    &ReadOptions::auto_prefix_mode,
42
    &ReadOptions::prefix_same_as_start,
43
    &ReadOptions::pin_data,
44
    &ReadOptions::adaptive_readahead,
45
    &ReadOptions::background_purge_on_iterator_cleanup,
46
    &ReadOptions::auto_readahead_size,
47
    &ReadOptions::allow_unprepared_value,
48
};
49
50
// TracedWriteOptions' boolean fields, by bit. Append only.
51
constexpr uint32_t kWriteSyncBit = 1u << 0;
52
constexpr uint32_t kWriteDisableWALBit = 1u << 1;
53
constexpr uint32_t kWriteNoSlowdownBit = 1u << 2;
54
55
0
bool DecodeIOPriority(uint32_t value, Env::IOPriority* priority) {
56
0
  if (value > Env::IO_TOTAL) {
57
0
    return false;
58
0
  }
59
0
  *priority = static_cast<Env::IOPriority>(value);
60
0
  return true;
61
0
}
62
63
}  // namespace
64
65
TracedWriteOptions::TracedWriteOptions(const WriteOptions& options)
66
0
    : sync(options.sync),
67
0
      disable_wal(options.disableWAL),
68
0
      no_slowdown(options.no_slowdown),
69
0
      rate_limiter_priority(options.rate_limiter_priority) {}
70
71
0
void TracedWriteOptions::EncodeTo(std::string* dst) const {
72
0
  uint32_t flags = 0;
73
0
  flags |= sync ? kWriteSyncBit : 0;
74
0
  flags |= disable_wal ? kWriteDisableWALBit : 0;
75
0
  flags |= no_slowdown ? kWriteNoSlowdownBit : 0;
76
0
  std::string body;
77
0
  PutVarint32(&body, flags);
78
0
  PutVarint32(&body, static_cast<uint32_t>(rate_limiter_priority));
79
0
  PutLengthPrefixedSlice(dst, body);
80
0
}
81
82
0
Status TracedWriteOptions::DecodeFrom(Slice* input, WriteOptions* options) {
83
0
  Slice body;
84
0
  uint32_t flags = 0;
85
0
  uint32_t priority = 0;
86
0
  if (!GetLengthPrefixedSlice(input, &body) || !GetVarint32(&body, &flags) ||
87
0
      !GetVarint32(&body, &priority) ||
88
0
      !DecodeIOPriority(priority, &options->rate_limiter_priority)) {
89
0
    return Status::Corruption("Unable to decode the traced WriteOptions");
90
0
  }
91
0
  options->sync = (flags & kWriteSyncBit) != 0;
92
0
  options->disableWAL = (flags & kWriteDisableWALBit) != 0;
93
0
  options->no_slowdown = (flags & kWriteNoSlowdownBit) != 0;
94
0
  return Status::OK();
95
0
}
96
97
TracedReadOptions::TracedReadOptions(const ReadOptions& options)
98
12.5k
    : readahead_size(options.readahead_size),
99
12.5k
      max_skippable_internal_keys(options.max_skippable_internal_keys),
100
12.5k
      value_size_soft_limit(options.value_size_soft_limit),
101
12.5k
      read_tier(options.read_tier),
102
12.5k
      rate_limiter_priority(options.rate_limiter_priority) {
103
187k
  for (size_t i = 0; i < std::size(kReadOptionsFlags); ++i) {
104
175k
    if (options.*kReadOptionsFlags[i]) {
105
50.0k
      flags |= uint32_t{1} << i;
106
50.0k
    }
107
175k
  }
108
12.5k
}
109
110
0
void TracedReadOptions::EncodeTo(std::string* dst) const {
111
0
  std::string body;
112
0
  PutVarint32(&body, flags);
113
0
  PutVarint32(&body, static_cast<uint32_t>(read_tier));
114
0
  PutVarint32(&body, static_cast<uint32_t>(rate_limiter_priority));
115
0
  PutVarint64(&body, readahead_size);
116
0
  PutVarint64(&body, max_skippable_internal_keys);
117
0
  PutVarint64(&body, value_size_soft_limit);
118
0
  PutLengthPrefixedSlice(dst, body);
119
0
}
120
121
0
Status TracedReadOptions::DecodeFrom(Slice* input, ReadOptions* options) {
122
0
  Slice body;
123
0
  uint32_t flags = 0;
124
0
  uint32_t read_tier = 0;
125
0
  uint32_t priority = 0;
126
0
  uint64_t readahead_size = 0;
127
0
  uint64_t max_skippable_internal_keys = 0;
128
0
  uint64_t value_size_soft_limit = 0;
129
0
  if (!GetLengthPrefixedSlice(input, &body) || !GetVarint32(&body, &flags) ||
130
0
      !GetVarint32(&body, &read_tier) || read_tier > kMemtableTier ||
131
0
      !GetVarint32(&body, &priority) ||
132
0
      !DecodeIOPriority(priority, &options->rate_limiter_priority) ||
133
0
      !GetVarint64(&body, &readahead_size) ||
134
0
      !GetVarint64(&body, &max_skippable_internal_keys) ||
135
0
      !GetVarint64(&body, &value_size_soft_limit)) {
136
0
    return Status::Corruption("Unable to decode the traced ReadOptions");
137
0
  }
138
0
  for (size_t i = 0; i < std::size(kReadOptionsFlags); ++i) {
139
0
    options->*kReadOptionsFlags[i] = (flags >> i) & 1;
140
0
  }
141
0
  options->read_tier = static_cast<ReadTier>(read_tier);
142
0
  options->readahead_size = static_cast<size_t>(readahead_size);
143
0
  options->max_skippable_internal_keys = max_skippable_internal_keys;
144
0
  options->value_size_soft_limit = value_size_soft_limit;
145
0
  return Status::OK();
146
0
}
147
148
namespace {
149
0
void DecodeCFAndKey(std::string& buffer, uint32_t* cf_id, Slice* key) {
150
0
  Slice buf(buffer);
151
0
  GetFixed32(&buf, cf_id);
152
0
  GetLengthPrefixedSlice(&buf, key);
153
0
}
154
}  // namespace
155
156
0
Status TracerHelper::ParseVersionStr(std::string& v_string, int* v_num) {
157
0
  if (v_string.find_first_of('.') == std::string::npos ||
158
0
      v_string.find_first_of('.') != v_string.find_last_of('.')) {
159
0
    return Status::Corruption(
160
0
        "Corrupted trace file. Incorrect version format.");
161
0
  }
162
0
  int tmp_num = 0;
163
0
  for (int i = 0; i < static_cast<int>(v_string.size()); i++) {
164
0
    if (v_string[i] == '.') {
165
0
      continue;
166
0
    } else if (isdigit(v_string[i])) {
167
0
      tmp_num = tmp_num * 10 + (v_string[i] - '0');
168
0
    } else {
169
0
      return Status::Corruption(
170
0
          "Corrupted trace file. Incorrect version format");
171
0
    }
172
0
  }
173
0
  *v_num = tmp_num;
174
0
  return Status::OK();
175
0
}
176
177
Status TracerHelper::ParseTraceHeader(const Trace& header, int* trace_version,
178
0
                                      int* db_version) {
179
0
  std::vector<std::string> s_vec;
180
0
  int begin = 0;
181
0
  int end;
182
0
  for (int i = 0; i < 3; i++) {
183
0
    assert(header.payload.find('\t', begin) != std::string::npos);
184
0
    end = static_cast<int>(header.payload.find('\t', begin));
185
0
    s_vec.push_back(header.payload.substr(begin, end - begin));
186
0
    begin = end + 1;
187
0
  }
188
189
0
  std::string t_v_str;
190
0
  std::string db_v_str;
191
0
  assert(s_vec.size() == 3);
192
0
  assert(s_vec[1].find("Trace Version: ") != std::string::npos);
193
0
  t_v_str = s_vec[1].substr(15);
194
0
  assert(s_vec[2].find("RocksDB Version: ") != std::string::npos);
195
0
  db_v_str = s_vec[2].substr(17);
196
197
0
  Status s;
198
0
  s = ParseVersionStr(t_v_str, trace_version);
199
0
  if (s != Status::OK()) {
200
0
    return s;
201
0
  }
202
0
  s = ParseVersionStr(db_v_str, db_version);
203
0
  return s;
204
0
}
205
206
0
void TracerHelper::EncodeTrace(const Trace& trace, std::string* encoded_trace) {
207
0
  assert(encoded_trace);
208
0
  PutFixed64(encoded_trace, trace.ts);
209
0
  encoded_trace->push_back(trace.type);
210
0
  PutFixed32(encoded_trace, static_cast<uint32_t>(trace.payload.size()));
211
0
  encoded_trace->append(trace.payload);
212
0
}
213
214
Status TracerHelper::DecodeTrace(const std::string& encoded_trace,
215
0
                                 Trace* trace) {
216
0
  assert(trace != nullptr);
217
0
  Slice enc_slice = Slice(encoded_trace);
218
0
  if (!GetFixed64(&enc_slice, &trace->ts)) {
219
0
    return Status::Incomplete("Decode trace string failed");
220
0
  }
221
0
  if (enc_slice.size() < kTraceTypeSize + kTracePayloadLengthSize) {
222
0
    return Status::Incomplete("Decode trace string failed");
223
0
  }
224
0
  trace->type = static_cast<TraceType>(enc_slice[0]);
225
0
  enc_slice.remove_prefix(kTraceTypeSize + kTracePayloadLengthSize);
226
0
  trace->payload = enc_slice.ToString();
227
0
  return Status::OK();
228
0
}
229
230
Status TracerHelper::DecodeHeader(const std::string& encoded_trace,
231
0
                                  Trace* header) {
232
0
  Status s = TracerHelper::DecodeTrace(encoded_trace, header);
233
234
0
  if (header->type != kTraceBegin) {
235
0
    return Status::Corruption("Corrupted trace file. Incorrect header.");
236
0
  }
237
0
  if (header->payload.substr(0, kTraceMagic.length()) != kTraceMagic) {
238
0
    return Status::Corruption("Corrupted trace file. Incorrect magic.");
239
0
  }
240
241
0
  return s;
242
0
}
243
244
bool TracerHelper::SetPayloadMap(uint64_t& payload_map,
245
0
                                 const TracePayloadType payload_type) {
246
0
  uint64_t old_state = payload_map;
247
0
  uint64_t tmp = 1;
248
0
  payload_map |= (tmp << payload_type);
249
0
  return old_state != payload_map;
250
0
}
251
252
Status TracerHelper::DecodeTraceRecord(Trace* trace, int trace_file_version,
253
0
                                       std::unique_ptr<TraceRecord>* record) {
254
0
  assert(trace != nullptr);
255
256
0
  if (record != nullptr) {
257
0
    record->reset(nullptr);
258
0
  }
259
260
0
  switch (trace->type) {
261
    // Write
262
0
    case kTraceWrite: {
263
0
      PinnableSlice rep;
264
0
      std::optional<WriteOptions> write_options;
265
0
      if (trace_file_version < 2) {
266
0
        rep.PinSelf(trace->payload);
267
0
      } else {
268
0
        Slice buf(trace->payload);
269
0
        GetFixed64(&buf, &trace->payload_map);
270
0
        int64_t payload_map = static_cast<int64_t>(trace->payload_map);
271
0
        Slice write_batch_data;
272
0
        while (payload_map) {
273
          // Find the rightmost set bit.
274
0
          uint32_t set_pos =
275
0
              static_cast<uint32_t>(log2(payload_map & -payload_map));
276
0
          switch (set_pos) {
277
0
            case TracePayloadType::kWriteBatchData: {
278
0
              GetLengthPrefixedSlice(&buf, &write_batch_data);
279
0
              break;
280
0
            }
281
0
            case TracePayloadType::kWriteOptions: {
282
0
              Status s = TracedWriteOptions::DecodeFrom(
283
0
                  &buf, &write_options.emplace());
284
0
              if (!s.ok()) {
285
0
                return s;
286
0
              }
287
0
              break;
288
0
            }
289
0
            default: {
290
              // A field from a newer version. Fields are encoded in bit order,
291
              // so this one and any after it are left undecoded.
292
0
              payload_map = 0;
293
0
              break;
294
0
            }
295
0
          }
296
          // unset the rightmost bit.
297
0
          payload_map &= (payload_map - 1);
298
0
        }
299
0
        rep.PinSelf(write_batch_data);
300
0
      }
301
302
0
      if (record != nullptr) {
303
0
        auto* write = new WriteQueryTraceRecord(std::move(rep), trace->ts);
304
0
        if (write_options) {
305
0
          write->SetWriteOptions(*write_options);
306
0
        }
307
0
        record->reset(write);
308
0
      }
309
310
0
      return Status::OK();
311
0
    }
312
    // Get
313
0
    case kTraceGet: {
314
0
      uint32_t cf_id = 0;
315
0
      Slice get_key;
316
0
      std::optional<ReadOptions> read_options;
317
318
0
      if (trace_file_version < 2) {
319
0
        DecodeCFAndKey(trace->payload, &cf_id, &get_key);
320
0
      } else {
321
0
        Slice buf(trace->payload);
322
0
        GetFixed64(&buf, &trace->payload_map);
323
0
        int64_t payload_map = static_cast<int64_t>(trace->payload_map);
324
0
        while (payload_map) {
325
          // Find the rightmost set bit.
326
0
          uint32_t set_pos =
327
0
              static_cast<uint32_t>(log2(payload_map & -payload_map));
328
0
          switch (set_pos) {
329
0
            case TracePayloadType::kGetCFID: {
330
0
              GetFixed32(&buf, &cf_id);
331
0
              break;
332
0
            }
333
0
            case TracePayloadType::kGetKey: {
334
0
              GetLengthPrefixedSlice(&buf, &get_key);
335
0
              break;
336
0
            }
337
0
            case TracePayloadType::kGetReadOptions: {
338
0
              Status s =
339
0
                  TracedReadOptions::DecodeFrom(&buf, &read_options.emplace());
340
0
              if (!s.ok()) {
341
0
                return s;
342
0
              }
343
0
              break;
344
0
            }
345
0
            default: {
346
              // A field from a newer version. Fields are encoded in bit order,
347
              // so this one and any after it are left undecoded.
348
0
              payload_map = 0;
349
0
              break;
350
0
            }
351
0
          }
352
          // unset the rightmost bit.
353
0
          payload_map &= (payload_map - 1);
354
0
        }
355
0
      }
356
357
0
      if (record != nullptr) {
358
0
        PinnableSlice ps;
359
0
        ps.PinSelf(get_key);
360
0
        auto* get = new GetQueryTraceRecord(cf_id, std::move(ps), trace->ts);
361
0
        if (read_options) {
362
0
          get->SetReadOptions(*read_options);
363
0
        }
364
0
        record->reset(get);
365
0
      }
366
367
0
      return Status::OK();
368
0
    }
369
    // Iterator Seek and SeekForPrev
370
0
    case kTraceIteratorSeek:
371
0
    case kTraceIteratorSeekForPrev: {
372
0
      uint32_t cf_id = 0;
373
0
      Slice iter_key;
374
0
      Slice lower_bound;
375
0
      Slice upper_bound;
376
0
      std::optional<ReadOptions> read_options;
377
378
0
      if (trace_file_version < 2) {
379
0
        DecodeCFAndKey(trace->payload, &cf_id, &iter_key);
380
0
      } else {
381
0
        Slice buf(trace->payload);
382
0
        GetFixed64(&buf, &trace->payload_map);
383
0
        int64_t payload_map = static_cast<int64_t>(trace->payload_map);
384
0
        while (payload_map) {
385
          // Find the rightmost set bit.
386
0
          uint32_t set_pos =
387
0
              static_cast<uint32_t>(log2(payload_map & -payload_map));
388
0
          switch (set_pos) {
389
0
            case TracePayloadType::kIterCFID: {
390
0
              GetFixed32(&buf, &cf_id);
391
0
              break;
392
0
            }
393
0
            case TracePayloadType::kIterKey: {
394
0
              GetLengthPrefixedSlice(&buf, &iter_key);
395
0
              break;
396
0
            }
397
0
            case TracePayloadType::kIterLowerBound: {
398
0
              GetLengthPrefixedSlice(&buf, &lower_bound);
399
0
              break;
400
0
            }
401
0
            case TracePayloadType::kIterUpperBound: {
402
0
              GetLengthPrefixedSlice(&buf, &upper_bound);
403
0
              break;
404
0
            }
405
0
            case TracePayloadType::kIterReadOptions: {
406
0
              Status s =
407
0
                  TracedReadOptions::DecodeFrom(&buf, &read_options.emplace());
408
0
              if (!s.ok()) {
409
0
                return s;
410
0
              }
411
0
              break;
412
0
            }
413
0
            default: {
414
              // A field from a newer version. Fields are encoded in bit order,
415
              // so this one and any after it are left undecoded.
416
0
              payload_map = 0;
417
0
              break;
418
0
            }
419
0
          }
420
          // unset the rightmost bit.
421
0
          payload_map &= (payload_map - 1);
422
0
        }
423
0
      }
424
425
0
      if (record != nullptr) {
426
0
        PinnableSlice ps_key;
427
0
        ps_key.PinSelf(iter_key);
428
0
        PinnableSlice ps_lower;
429
0
        ps_lower.PinSelf(lower_bound);
430
0
        PinnableSlice ps_upper;
431
0
        ps_upper.PinSelf(upper_bound);
432
0
        auto* seek = new IteratorSeekQueryTraceRecord(
433
0
            static_cast<IteratorSeekQueryTraceRecord::SeekType>(trace->type),
434
0
            cf_id, std::move(ps_key), std::move(ps_lower), std::move(ps_upper),
435
0
            trace->ts);
436
0
        if (read_options) {
437
0
          seek->SetReadOptions(*read_options);
438
0
        }
439
0
        record->reset(seek);
440
0
      }
441
442
0
      return Status::OK();
443
0
    }
444
    // MultiGet
445
0
    case kTraceMultiGet: {
446
0
      if (trace_file_version < 2) {
447
0
        return Status::Corruption("MultiGet is not supported.");
448
0
      }
449
450
0
      uint32_t multiget_size = 0;
451
0
      std::vector<uint32_t> cf_ids;
452
0
      std::vector<PinnableSlice> multiget_keys;
453
454
0
      Slice cfids_payload;
455
0
      Slice keys_payload;
456
0
      std::optional<ReadOptions> read_options;
457
0
      Slice buf(trace->payload);
458
0
      GetFixed64(&buf, &trace->payload_map);
459
0
      int64_t payload_map = static_cast<int64_t>(trace->payload_map);
460
0
      while (payload_map) {
461
        // Find the rightmost set bit.
462
0
        uint32_t set_pos =
463
0
            static_cast<uint32_t>(log2(payload_map & -payload_map));
464
0
        switch (set_pos) {
465
0
          case TracePayloadType::kMultiGetSize: {
466
0
            GetFixed32(&buf, &multiget_size);
467
0
            break;
468
0
          }
469
0
          case TracePayloadType::kMultiGetCFIDs: {
470
0
            GetLengthPrefixedSlice(&buf, &cfids_payload);
471
0
            break;
472
0
          }
473
0
          case TracePayloadType::kMultiGetKeys: {
474
0
            GetLengthPrefixedSlice(&buf, &keys_payload);
475
0
            break;
476
0
          }
477
0
          case TracePayloadType::kMultiGetReadOptions: {
478
0
            Status s =
479
0
                TracedReadOptions::DecodeFrom(&buf, &read_options.emplace());
480
0
            if (!s.ok()) {
481
0
              return s;
482
0
            }
483
0
            break;
484
0
          }
485
0
          default: {
486
            // A field from a newer version. Fields are encoded in bit order, so
487
            // this one and any after it are left undecoded.
488
0
            payload_map = 0;
489
0
            break;
490
0
          }
491
0
        }
492
        // unset the rightmost bit.
493
0
        payload_map &= (payload_map - 1);
494
0
      }
495
0
      if (multiget_size == 0) {
496
0
        return Status::InvalidArgument("Empty MultiGet cf_ids or keys.");
497
0
      }
498
499
      // Decode the cfids_payload and keys_payload
500
0
      cf_ids.reserve(multiget_size);
501
0
      multiget_keys.reserve(multiget_size);
502
0
      for (uint32_t i = 0; i < multiget_size; i++) {
503
0
        uint32_t tmp_cfid = 0;
504
0
        Slice tmp_key;
505
0
        GetFixed32(&cfids_payload, &tmp_cfid);
506
0
        GetLengthPrefixedSlice(&keys_payload, &tmp_key);
507
0
        cf_ids.push_back(tmp_cfid);
508
0
        Slice s(tmp_key);
509
0
        PinnableSlice ps;
510
0
        ps.PinSelf(s);
511
0
        multiget_keys.push_back(std::move(ps));
512
0
      }
513
514
0
      if (record != nullptr) {
515
0
        auto* multiget = new MultiGetQueryTraceRecord(
516
0
            std::move(cf_ids), std::move(multiget_keys), trace->ts);
517
0
        if (read_options) {
518
0
          multiget->SetReadOptions(*read_options);
519
0
        }
520
0
        record->reset(multiget);
521
0
      }
522
523
0
      return Status::OK();
524
0
    }
525
0
    case kTraceNone:
526
0
    case kTraceBegin:
527
0
    case kTraceEnd:
528
0
    case kBlockTraceIndexBlock:
529
0
    case kBlockTraceFilterBlock:
530
0
    case kBlockTraceDataBlock:
531
0
    case kBlockTraceUncompressionDictBlock:
532
0
    case kBlockTraceRangeDeletionBlock:
533
0
    case kIOTracer:
534
0
    case kTraceMax:
535
0
    default:
536
0
      return Status::NotSupported("Unsupported trace type.");
537
0
  }
538
0
}
539
540
Tracer::Tracer(SystemClock* clock, const TraceOptions& trace_options,
541
               std::unique_ptr<TraceWriter>&& trace_writer)
542
0
    : clock_(clock),
543
0
      trace_options_(trace_options),
544
0
      trace_writer_(std::move(trace_writer)),
545
0
      trace_request_count_(0),
546
0
      trace_write_status_(Status::OK()) {
547
  // TODO: What if this fails?
548
0
  WriteHeader().PermitUncheckedError();
549
0
}
550
551
0
Tracer::~Tracer() { trace_writer_.reset(); }
552
553
Status Tracer::Write(WriteBatch* write_batch,
554
0
                     const TracedWriteOptions& options) {
555
0
  TraceType trace_type = kTraceWrite;
556
0
  if (ShouldSkipTrace(trace_type)) {
557
0
    return Status::OK();
558
0
  }
559
0
  Trace trace;
560
0
  trace.ts = clock_->NowMicros();
561
0
  trace.type = trace_type;
562
0
  TracerHelper::SetPayloadMap(trace.payload_map,
563
0
                              TracePayloadType::kWriteBatchData);
564
0
  if (trace_options_.include_read_write_options) {
565
0
    TracerHelper::SetPayloadMap(trace.payload_map,
566
0
                                TracePayloadType::kWriteOptions);
567
0
  }
568
0
  PutFixed64(&trace.payload, trace.payload_map);
569
0
  PutLengthPrefixedSlice(&trace.payload, Slice(write_batch->Data()));
570
0
  if (trace_options_.include_read_write_options) {
571
0
    options.EncodeTo(&trace.payload);
572
0
  }
573
0
  return WriteTrace(trace);
574
0
}
575
576
Status Tracer::Get(ColumnFamilyHandle* column_family, const Slice& key,
577
0
                   const ReadOptions& read_options) {
578
0
  TraceType trace_type = kTraceGet;
579
0
  if (ShouldSkipTrace(trace_type)) {
580
0
    return Status::OK();
581
0
  }
582
0
  Trace trace;
583
0
  trace.ts = clock_->NowMicros();
584
0
  trace.type = trace_type;
585
  // Set the payloadmap of the struct member that will be encoded in the
586
  // payload.
587
0
  TracerHelper::SetPayloadMap(trace.payload_map, TracePayloadType::kGetCFID);
588
0
  TracerHelper::SetPayloadMap(trace.payload_map, TracePayloadType::kGetKey);
589
0
  if (trace_options_.include_read_write_options) {
590
0
    TracerHelper::SetPayloadMap(trace.payload_map,
591
0
                                TracePayloadType::kGetReadOptions);
592
0
  }
593
  // Encode the Get struct members into payload. Make sure add them in order.
594
0
  PutFixed64(&trace.payload, trace.payload_map);
595
0
  PutFixed32(&trace.payload, column_family->GetID());
596
0
  PutLengthPrefixedSlice(&trace.payload, key);
597
0
  if (trace_options_.include_read_write_options) {
598
0
    TracedReadOptions(read_options).EncodeTo(&trace.payload);
599
0
  }
600
0
  return WriteTrace(trace);
601
0
}
602
603
Status Tracer::IteratorSeek(const uint32_t& cf_id, const Slice& key,
604
                            const Slice& lower_bound, const Slice upper_bound,
605
0
                            const TracedReadOptions& read_options) {
606
0
  return IteratorSeekImpl(kTraceIteratorSeek, cf_id, key, lower_bound,
607
0
                          upper_bound, read_options);
608
0
}
609
610
Status Tracer::IteratorSeekForPrev(const uint32_t& cf_id, const Slice& key,
611
                                   const Slice& lower_bound,
612
                                   const Slice upper_bound,
613
0
                                   const TracedReadOptions& read_options) {
614
0
  return IteratorSeekImpl(kTraceIteratorSeekForPrev, cf_id, key, lower_bound,
615
0
                          upper_bound, read_options);
616
0
}
617
618
Status Tracer::IteratorSeekImpl(TraceType trace_type, uint32_t cf_id,
619
                                const Slice& key, const Slice& lower_bound,
620
                                const Slice& upper_bound,
621
0
                                const TracedReadOptions& read_options) {
622
0
  if (ShouldSkipTrace(trace_type)) {
623
0
    return Status::OK();
624
0
  }
625
0
  Trace trace;
626
0
  trace.ts = clock_->NowMicros();
627
0
  trace.type = trace_type;
628
  // Set the payloadmap of the struct member that will be encoded in the
629
  // payload.
630
0
  TracerHelper::SetPayloadMap(trace.payload_map, TracePayloadType::kIterCFID);
631
0
  TracerHelper::SetPayloadMap(trace.payload_map, TracePayloadType::kIterKey);
632
0
  if (lower_bound.size() > 0) {
633
0
    TracerHelper::SetPayloadMap(trace.payload_map,
634
0
                                TracePayloadType::kIterLowerBound);
635
0
  }
636
0
  if (upper_bound.size() > 0) {
637
0
    TracerHelper::SetPayloadMap(trace.payload_map,
638
0
                                TracePayloadType::kIterUpperBound);
639
0
  }
640
0
  if (trace_options_.include_read_write_options) {
641
0
    TracerHelper::SetPayloadMap(trace.payload_map,
642
0
                                TracePayloadType::kIterReadOptions);
643
0
  }
644
  // Encode the Iterator struct members into payload. Make sure add them in
645
  // order.
646
0
  PutFixed64(&trace.payload, trace.payload_map);
647
0
  PutFixed32(&trace.payload, cf_id);
648
0
  PutLengthPrefixedSlice(&trace.payload, key);
649
0
  if (lower_bound.size() > 0) {
650
0
    PutLengthPrefixedSlice(&trace.payload, lower_bound);
651
0
  }
652
0
  if (upper_bound.size() > 0) {
653
0
    PutLengthPrefixedSlice(&trace.payload, upper_bound);
654
0
  }
655
0
  if (trace_options_.include_read_write_options) {
656
0
    read_options.EncodeTo(&trace.payload);
657
0
  }
658
0
  return WriteTrace(trace);
659
0
}
660
661
Status Tracer::MultiGet(const size_t num_keys,
662
                        ColumnFamilyHandle** column_families, const Slice* keys,
663
0
                        const ReadOptions& read_options) {
664
0
  if (num_keys == 0) {
665
0
    return Status::OK();
666
0
  }
667
0
  std::vector<ColumnFamilyHandle*> v_column_families;
668
0
  std::vector<Slice> v_keys;
669
0
  v_column_families.resize(num_keys);
670
0
  v_keys.resize(num_keys);
671
0
  for (size_t i = 0; i < num_keys; i++) {
672
0
    v_column_families[i] = column_families[i];
673
0
    v_keys[i] = keys[i];
674
0
  }
675
0
  return MultiGet(v_column_families, v_keys, read_options);
676
0
}
677
678
Status Tracer::MultiGet(const size_t num_keys,
679
                        ColumnFamilyHandle* column_family, const Slice* keys,
680
0
                        const ReadOptions& read_options) {
681
0
  if (num_keys == 0) {
682
0
    return Status::OK();
683
0
  }
684
0
  std::vector<ColumnFamilyHandle*> column_families;
685
0
  std::vector<Slice> v_keys;
686
0
  column_families.resize(num_keys);
687
0
  v_keys.resize(num_keys);
688
0
  for (size_t i = 0; i < num_keys; i++) {
689
0
    column_families[i] = column_family;
690
0
    v_keys[i] = keys[i];
691
0
  }
692
0
  return MultiGet(column_families, v_keys, read_options);
693
0
}
694
695
Status Tracer::MultiGet(const std::vector<ColumnFamilyHandle*>& column_families,
696
                        const std::vector<Slice>& keys,
697
0
                        const ReadOptions& read_options) {
698
0
  if (column_families.size() != keys.size()) {
699
0
    return Status::Corruption("the CFs size and keys size does not match!");
700
0
  }
701
0
  TraceType trace_type = kTraceMultiGet;
702
0
  if (ShouldSkipTrace(trace_type)) {
703
0
    return Status::OK();
704
0
  }
705
0
  uint32_t multiget_size = static_cast<uint32_t>(keys.size());
706
0
  Trace trace;
707
0
  trace.ts = clock_->NowMicros();
708
0
  trace.type = trace_type;
709
  // Set the payloadmap of the struct member that will be encoded in the
710
  // payload.
711
0
  TracerHelper::SetPayloadMap(trace.payload_map,
712
0
                              TracePayloadType::kMultiGetSize);
713
0
  TracerHelper::SetPayloadMap(trace.payload_map,
714
0
                              TracePayloadType::kMultiGetCFIDs);
715
0
  TracerHelper::SetPayloadMap(trace.payload_map,
716
0
                              TracePayloadType::kMultiGetKeys);
717
0
  if (trace_options_.include_read_write_options) {
718
0
    TracerHelper::SetPayloadMap(trace.payload_map,
719
0
                                TracePayloadType::kMultiGetReadOptions);
720
0
  }
721
  // Encode the CFIDs inorder
722
0
  std::string cfids_payload;
723
0
  std::string keys_payload;
724
0
  for (uint32_t i = 0; i < multiget_size; i++) {
725
0
    assert(i < column_families.size());
726
0
    assert(i < keys.size());
727
0
    PutFixed32(&cfids_payload, column_families[i]->GetID());
728
0
    PutLengthPrefixedSlice(&keys_payload, keys[i]);
729
0
  }
730
  // Encode the Get struct members into payload. Make sure add them in order.
731
0
  PutFixed64(&trace.payload, trace.payload_map);
732
0
  PutFixed32(&trace.payload, multiget_size);
733
0
  PutLengthPrefixedSlice(&trace.payload, cfids_payload);
734
0
  PutLengthPrefixedSlice(&trace.payload, keys_payload);
735
0
  if (trace_options_.include_read_write_options) {
736
0
    TracedReadOptions(read_options).EncodeTo(&trace.payload);
737
0
  }
738
0
  return WriteTrace(trace);
739
0
}
740
741
0
bool Tracer::ShouldSkipTrace(const TraceType& trace_type) {
742
0
  if (IsTraceFileOverMax()) {
743
0
    return true;
744
0
  }
745
746
0
  TraceFilterType filter_mask = kTraceFilterNone;
747
0
  switch (trace_type) {
748
0
    case kTraceNone:
749
0
    case kTraceBegin:
750
0
    case kTraceEnd:
751
0
      filter_mask = kTraceFilterNone;
752
0
      break;
753
0
    case kTraceWrite:
754
0
      filter_mask = kTraceFilterWrite;
755
0
      break;
756
0
    case kTraceGet:
757
0
      filter_mask = kTraceFilterGet;
758
0
      break;
759
0
    case kTraceIteratorSeek:
760
0
      filter_mask = kTraceFilterIteratorSeek;
761
0
      break;
762
0
    case kTraceIteratorSeekForPrev:
763
0
      filter_mask = kTraceFilterIteratorSeekForPrev;
764
0
      break;
765
0
    case kBlockTraceIndexBlock:
766
0
    case kBlockTraceFilterBlock:
767
0
    case kBlockTraceDataBlock:
768
0
    case kBlockTraceUncompressionDictBlock:
769
0
    case kBlockTraceRangeDeletionBlock:
770
0
    case kIOTracer:
771
0
      filter_mask = kTraceFilterNone;
772
0
      break;
773
0
    case kTraceMultiGet:
774
0
      filter_mask = kTraceFilterMultiGet;
775
0
      break;
776
0
    case kTraceMax:
777
0
      assert(false);
778
0
      filter_mask = kTraceFilterNone;
779
0
      break;
780
0
  }
781
0
  if (filter_mask != kTraceFilterNone && trace_options_.filter & filter_mask) {
782
0
    return true;
783
0
  }
784
785
0
  ++trace_request_count_;
786
0
  if (trace_request_count_ < trace_options_.sampling_frequency) {
787
0
    return true;
788
0
  }
789
0
  trace_request_count_ = 0;
790
0
  return false;
791
0
}
792
793
0
bool Tracer::IsTraceFileOverMax() {
794
0
  uint64_t trace_file_size = trace_writer_->GetFileSize();
795
0
  return (trace_file_size > trace_options_.max_trace_file_size);
796
0
}
797
798
0
Status Tracer::WriteHeader() {
799
0
  std::ostringstream s;
800
0
  s << kTraceMagic << "\t" << "Trace Version: " << kTraceFileMajorVersion << "."
801
0
    << kTraceFileMinorVersion << "\t" << "RocksDB Version: " << kMajorVersion
802
0
    << "." << kMinorVersion << "\t" << "Format: Timestamp OpType Payload\n";
803
0
  std::string header(s.str());
804
805
0
  Trace trace;
806
0
  trace.ts = clock_->NowMicros();
807
0
  trace.type = kTraceBegin;
808
0
  trace.payload = header;
809
0
  return WriteTrace(trace);
810
0
}
811
812
0
Status Tracer::WriteFooter() {
813
0
  Trace trace;
814
0
  trace.ts = clock_->NowMicros();
815
0
  trace.type = kTraceEnd;
816
0
  TracerHelper::SetPayloadMap(trace.payload_map,
817
0
                              TracePayloadType::kEmptyPayload);
818
0
  trace.payload = "";
819
0
  return WriteTrace(trace);
820
0
}
821
822
0
Status Tracer::WriteTrace(const Trace& trace) {
823
0
  if (!trace_write_status_.ok()) {
824
0
    return Status::Incomplete("Tracing has seen error: %s",
825
0
                              trace_write_status_.ToString());
826
0
  }
827
0
  assert(trace_write_status_.ok());
828
0
  std::string encoded_trace;
829
0
  TracerHelper::EncodeTrace(trace, &encoded_trace);
830
0
  Status s = trace_writer_->Write(Slice(encoded_trace));
831
0
  if (!s.ok()) {
832
0
    trace_write_status_ = s;
833
0
  }
834
0
  return s;
835
0
}
836
837
0
Status Tracer::Close() { return WriteFooter(); }
838
839
}  // namespace ROCKSDB_NAMESPACE