Coverage Report

Created: 2025-07-23 07:17

/src/rocksdb/env/file_system_tracer.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2019-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 "rocksdb/file_system.h"
9
#include "rocksdb/system_clock.h"
10
#include "trace_replay/io_tracer.h"
11
12
namespace ROCKSDB_NAMESPACE {
13
14
// FileSystemTracingWrapper is a wrapper class above FileSystem that forwards
15
// the call to the underlying storage system. It then invokes IOTracer to record
16
// file operations and other contextual information in a binary format for
17
// tracing. It overrides methods we are interested in tracing and extends
18
// FileSystemWrapper, which forwards all methods that are not explicitly
19
// overridden.
20
class FileSystemTracingWrapper : public FileSystemWrapper {
21
 public:
22
  FileSystemTracingWrapper(const std::shared_ptr<FileSystem>& t,
23
                           const std::shared_ptr<IOTracer>& io_tracer)
24
180k
      : FileSystemWrapper(t),
25
180k
        io_tracer_(io_tracer),
26
180k
        clock_(SystemClock::Default().get()) {}
27
28
180k
  ~FileSystemTracingWrapper() override {}
29
30
0
  static const char* kClassName() { return "FileSystemTracing"; }
31
0
  const char* Name() const override { return kClassName(); }
32
33
  IOStatus NewSequentialFile(const std::string& fname,
34
                             const FileOptions& file_opts,
35
                             std::unique_ptr<FSSequentialFile>* result,
36
                             IODebugContext* dbg) override;
37
38
  IOStatus NewRandomAccessFile(const std::string& fname,
39
                               const FileOptions& file_opts,
40
                               std::unique_ptr<FSRandomAccessFile>* result,
41
                               IODebugContext* dbg) override;
42
43
  IOStatus NewWritableFile(const std::string& fname,
44
                           const FileOptions& file_opts,
45
                           std::unique_ptr<FSWritableFile>* result,
46
                           IODebugContext* dbg) override;
47
48
  IOStatus ReopenWritableFile(const std::string& fname,
49
                              const FileOptions& file_opts,
50
                              std::unique_ptr<FSWritableFile>* result,
51
                              IODebugContext* dbg) override;
52
53
  IOStatus ReuseWritableFile(const std::string& fname,
54
                             const std::string& old_fname,
55
                             const FileOptions& file_opts,
56
                             std::unique_ptr<FSWritableFile>* result,
57
                             IODebugContext* dbg) override;
58
59
  IOStatus NewRandomRWFile(const std::string& fname, const FileOptions& options,
60
                           std::unique_ptr<FSRandomRWFile>* result,
61
                           IODebugContext* dbg) override;
62
63
  IOStatus NewDirectory(const std::string& name, const IOOptions& io_opts,
64
                        std::unique_ptr<FSDirectory>* result,
65
                        IODebugContext* dbg) override;
66
67
  IOStatus GetChildren(const std::string& dir, const IOOptions& io_opts,
68
                       std::vector<std::string>* r,
69
                       IODebugContext* dbg) override;
70
71
  IOStatus DeleteFile(const std::string& fname, const IOOptions& options,
72
                      IODebugContext* dbg) override;
73
74
  IOStatus CreateDir(const std::string& dirname, const IOOptions& options,
75
                     IODebugContext* dbg) override;
76
77
  IOStatus CreateDirIfMissing(const std::string& dirname,
78
                              const IOOptions& options,
79
                              IODebugContext* dbg) override;
80
81
  IOStatus DeleteDir(const std::string& dirname, const IOOptions& options,
82
                     IODebugContext* dbg) override;
83
84
  IOStatus GetFileSize(const std::string& fname, const IOOptions& options,
85
                       uint64_t* file_size, IODebugContext* dbg) override;
86
87
  IOStatus Truncate(const std::string& fname, size_t size,
88
                    const IOOptions& options, IODebugContext* dbg) override;
89
90
 private:
91
  std::shared_ptr<IOTracer> io_tracer_;
92
  SystemClock* clock_;
93
};
94
95
// The FileSystemPtr is a wrapper class that takes pointer to storage systems
96
// (such as posix filesystems). It overloads operator -> and returns a pointer
97
// of either FileSystem or FileSystemTracingWrapper based on whether tracing is
98
// enabled or  not. It is added to bypass FileSystemTracingWrapper when tracing
99
// is disabled.
100
class FileSystemPtr {
101
 public:
102
  FileSystemPtr(std::shared_ptr<FileSystem> fs,
103
                const std::shared_ptr<IOTracer>& io_tracer)
104
180k
      : fs_(fs), io_tracer_(io_tracer) {
105
180k
    fs_tracer_ = std::make_shared<FileSystemTracingWrapper>(fs_, io_tracer_);
106
180k
  }
107
108
934k
  std::shared_ptr<FileSystem> operator->() const {
109
934k
    if (io_tracer_ && io_tracer_->is_tracing_enabled()) {
110
0
      return fs_tracer_;
111
934k
    } else {
112
934k
      return fs_;
113
934k
    }
114
934k
  }
115
116
  /* Returns the underlying File System pointer */
117
467k
  FileSystem* get() const {
118
467k
    if (io_tracer_ && io_tracer_->is_tracing_enabled()) {
119
0
      return fs_tracer_.get();
120
467k
    } else {
121
467k
      return fs_.get();
122
467k
    }
123
467k
  }
124
125
 private:
126
  std::shared_ptr<FileSystem> fs_;
127
  std::shared_ptr<IOTracer> io_tracer_;
128
  std::shared_ptr<FileSystemTracingWrapper> fs_tracer_;
129
};
130
131
// FSSequentialFileTracingWrapper is a wrapper class above FSSequentialFile that
132
// forwards the call to the underlying storage system. It then invokes IOTracer
133
// to record file operations and other contextual information in a binary format
134
// for tracing. It overrides methods we are interested in tracing and extends
135
// FSSequentialFileWrapper, which forwards all methods that are not explicitly
136
// overridden.
137
class FSSequentialFileTracingWrapper : public FSSequentialFileOwnerWrapper {
138
 public:
139
  FSSequentialFileTracingWrapper(std::unique_ptr<FSSequentialFile>&& t,
140
                                 std::shared_ptr<IOTracer> io_tracer,
141
                                 const std::string& file_name)
142
208k
      : FSSequentialFileOwnerWrapper(std::move(t)),
143
208k
        io_tracer_(io_tracer),
144
208k
        clock_(SystemClock::Default().get()),
145
208k
        file_name_(file_name) {}
146
147
208k
  ~FSSequentialFileTracingWrapper() override {}
148
149
  IOStatus Read(size_t n, const IOOptions& options, Slice* result,
150
                char* scratch, IODebugContext* dbg) override;
151
152
  IOStatus InvalidateCache(size_t offset, size_t length) override;
153
154
  IOStatus PositionedRead(uint64_t offset, size_t n, const IOOptions& options,
155
                          Slice* result, char* scratch,
156
                          IODebugContext* dbg) override;
157
158
 private:
159
  std::shared_ptr<IOTracer> io_tracer_;
160
  SystemClock* clock_;
161
  std::string file_name_;
162
};
163
164
// The FSSequentialFilePtr is a wrapper class that takes pointer to storage
165
// systems (such as posix filesystems). It overloads operator -> and returns a
166
// pointer of either FSSequentialFile or FSSequentialFileTracingWrapper based on
167
// whether tracing is enabled or not. It is added to bypass
168
// FSSequentialFileTracingWrapper when tracing is disabled.
169
class FSSequentialFilePtr {
170
 public:
171
  FSSequentialFilePtr() = delete;
172
  FSSequentialFilePtr(std::unique_ptr<FSSequentialFile>&& fs,
173
                      const std::shared_ptr<IOTracer>& io_tracer,
174
                      const std::string& file_name)
175
208k
      : io_tracer_(io_tracer),
176
208k
        fs_tracer_(std::move(fs), io_tracer_,
177
208k
                   file_name.substr(file_name.find_last_of("/\\") +
178
208k
                                    1) /* pass file name */) {}
179
180
517k
  FSSequentialFile* operator->() const {
181
517k
    if (io_tracer_ && io_tracer_->is_tracing_enabled()) {
182
0
      return const_cast<FSSequentialFileTracingWrapper*>(&fs_tracer_);
183
517k
    } else {
184
517k
      return fs_tracer_.target();
185
517k
    }
186
517k
  }
187
188
0
  FSSequentialFile* get() const {
189
0
    if (io_tracer_ && io_tracer_->is_tracing_enabled()) {
190
0
      return const_cast<FSSequentialFileTracingWrapper*>(&fs_tracer_);
191
0
    } else {
192
0
      return fs_tracer_.target();
193
0
    }
194
0
  }
195
196
 private:
197
  std::shared_ptr<IOTracer> io_tracer_;
198
  FSSequentialFileTracingWrapper fs_tracer_;
199
};
200
201
// FSRandomAccessFileTracingWrapper is a wrapper class above FSRandomAccessFile
202
// that forwards the call to the underlying storage system. It then invokes
203
// IOTracer to record file operations and other contextual information in a
204
// binary format for tracing. It overrides methods we are interested in tracing
205
// and extends FSRandomAccessFileWrapper, which forwards all methods that are
206
// not explicitly overridden.
207
class FSRandomAccessFileTracingWrapper : public FSRandomAccessFileOwnerWrapper {
208
 public:
209
  FSRandomAccessFileTracingWrapper(std::unique_ptr<FSRandomAccessFile>&& t,
210
                                   std::shared_ptr<IOTracer> io_tracer,
211
                                   const std::string& file_name)
212
125k
      : FSRandomAccessFileOwnerWrapper(std::move(t)),
213
125k
        io_tracer_(io_tracer),
214
125k
        clock_(SystemClock::Default().get()),
215
125k
        file_name_(file_name) {}
216
217
126k
  ~FSRandomAccessFileTracingWrapper() override {}
218
219
  IOStatus Read(uint64_t offset, size_t n, const IOOptions& options,
220
                Slice* result, char* scratch,
221
                IODebugContext* dbg) const override;
222
223
  IOStatus MultiRead(FSReadRequest* reqs, size_t num_reqs,
224
                     const IOOptions& options, IODebugContext* dbg) override;
225
226
  IOStatus Prefetch(uint64_t offset, size_t n, const IOOptions& options,
227
                    IODebugContext* dbg) override;
228
229
  IOStatus InvalidateCache(size_t offset, size_t length) override;
230
231
  IOStatus ReadAsync(FSReadRequest& req, const IOOptions& opts,
232
                     std::function<void(FSReadRequest&, void*)> cb,
233
                     void* cb_arg, void** io_handle, IOHandleDeleter* del_fn,
234
                     IODebugContext* dbg) override;
235
236
  void ReadAsyncCallback(FSReadRequest& req, void* cb_arg);
237
238
 private:
239
  std::shared_ptr<IOTracer> io_tracer_;
240
  SystemClock* clock_;
241
  // Stores file name instead of full path.
242
  std::string file_name_;
243
244
  struct ReadAsyncCallbackInfo {
245
    uint64_t start_time_;
246
    std::function<void(FSReadRequest&, void*)> cb_;
247
    void* cb_arg_;
248
    std::string file_op_;
249
  };
250
};
251
252
// The FSRandomAccessFilePtr is a wrapper class that takes pointer to storage
253
// systems (such as posix filesystems). It overloads operator -> and returns a
254
// pointer of either FSRandomAccessFile or FSRandomAccessFileTracingWrapper
255
// based on whether tracing is enabled or not. It is added to bypass
256
// FSRandomAccessFileTracingWrapper when tracing is disabled.
257
class FSRandomAccessFilePtr {
258
 public:
259
  FSRandomAccessFilePtr(std::unique_ptr<FSRandomAccessFile>&& fs,
260
                        const std::shared_ptr<IOTracer>& io_tracer,
261
                        const std::string& file_name)
262
125k
      : io_tracer_(io_tracer),
263
125k
        fs_tracer_(std::move(fs), io_tracer_,
264
125k
                   file_name.substr(file_name.find_last_of("/\\") +
265
125k
                                    1) /* pass file name */) {}
266
267
2.41M
  FSRandomAccessFile* operator->() const {
268
2.41M
    if (io_tracer_ && io_tracer_->is_tracing_enabled()) {
269
0
      return const_cast<FSRandomAccessFileTracingWrapper*>(&fs_tracer_);
270
2.41M
    } else {
271
2.41M
      return fs_tracer_.target();
272
2.41M
    }
273
2.41M
  }
274
275
125k
  FSRandomAccessFile* get() const {
276
125k
    if (io_tracer_ && io_tracer_->is_tracing_enabled()) {
277
0
      return const_cast<FSRandomAccessFileTracingWrapper*>(&fs_tracer_);
278
125k
    } else {
279
125k
      return fs_tracer_.target();
280
125k
    }
281
125k
  }
282
283
 private:
284
  std::shared_ptr<IOTracer> io_tracer_;
285
  FSRandomAccessFileTracingWrapper fs_tracer_;
286
};
287
288
// FSWritableFileTracingWrapper is a wrapper class above FSWritableFile that
289
// forwards the call to the underlying storage system. It then invokes IOTracer
290
// to record file operations and other contextual information in a binary format
291
// for tracing. It overrides methods we are interested in tracing and extends
292
// FSWritableFileWrapper, which forwards all methods that are not explicitly
293
// overridden.
294
class FSWritableFileTracingWrapper : public FSWritableFileOwnerWrapper {
295
 public:
296
  FSWritableFileTracingWrapper(std::unique_ptr<FSWritableFile>&& t,
297
                               std::shared_ptr<IOTracer> io_tracer,
298
                               const std::string& file_name)
299
324k
      : FSWritableFileOwnerWrapper(std::move(t)),
300
324k
        io_tracer_(io_tracer),
301
324k
        clock_(SystemClock::Default().get()),
302
324k
        file_name_(file_name) {}
303
304
324k
  ~FSWritableFileTracingWrapper() override {}
305
306
  IOStatus Append(const Slice& data, const IOOptions& options,
307
                  IODebugContext* dbg) override;
308
  IOStatus Append(const Slice& data, const IOOptions& options,
309
                  const DataVerificationInfo& /*verification_info*/,
310
0
                  IODebugContext* dbg) override {
311
0
    return Append(data, options, dbg);
312
0
  }
313
314
  IOStatus PositionedAppend(const Slice& data, uint64_t offset,
315
                            const IOOptions& options,
316
                            IODebugContext* dbg) override;
317
  IOStatus PositionedAppend(const Slice& data, uint64_t offset,
318
                            const IOOptions& options,
319
                            const DataVerificationInfo& /*verification_info*/,
320
0
                            IODebugContext* dbg) override {
321
0
    return PositionedAppend(data, offset, options, dbg);
322
0
  }
323
324
  IOStatus Truncate(uint64_t size, const IOOptions& options,
325
                    IODebugContext* dbg) override;
326
327
  IOStatus Close(const IOOptions& options, IODebugContext* dbg) override;
328
329
  uint64_t GetFileSize(const IOOptions& options, IODebugContext* dbg) override;
330
331
  IOStatus InvalidateCache(size_t offset, size_t length) override;
332
333
 private:
334
  std::shared_ptr<IOTracer> io_tracer_;
335
  SystemClock* clock_;
336
  // Stores file name instead of full path.
337
  std::string file_name_;
338
};
339
340
// The FSWritableFilePtr is a wrapper class that takes pointer to storage
341
// systems (such as posix filesystems). It overloads operator -> and returns a
342
// pointer of either FSWritableFile or FSWritableFileTracingWrapper based on
343
// whether tracing is enabled or not. It is added to bypass
344
// FSWritableFileTracingWrapper when tracing is disabled.
345
class FSWritableFilePtr {
346
 public:
347
  FSWritableFilePtr(std::unique_ptr<FSWritableFile>&& fs,
348
                    const std::shared_ptr<IOTracer>& io_tracer,
349
                    const std::string& file_name)
350
324k
      : io_tracer_(io_tracer) {
351
324k
    fs_tracer_.reset(new FSWritableFileTracingWrapper(
352
324k
        std::move(fs), io_tracer_,
353
324k
        file_name.substr(file_name.find_last_of("/\\") +
354
324k
                         1) /* pass file name */));
355
324k
  }
356
357
141M
  FSWritableFile* operator->() const {
358
141M
    if (io_tracer_ && io_tracer_->is_tracing_enabled()) {
359
0
      return fs_tracer_.get();
360
141M
    } else {
361
141M
      return fs_tracer_->target();
362
141M
    }
363
141M
  }
364
365
35.4M
  FSWritableFile* get() const {
366
35.4M
    if (io_tracer_ && io_tracer_->is_tracing_enabled()) {
367
0
      return fs_tracer_.get();
368
35.4M
    } else if (fs_tracer_) {
369
34.8M
      return fs_tracer_->target();
370
34.8M
    } else {
371
513k
      return nullptr;
372
513k
    }
373
35.4M
  }
374
375
324k
  void reset() {
376
324k
    fs_tracer_.reset();
377
324k
    io_tracer_ = nullptr;
378
324k
  }
379
380
 private:
381
  std::shared_ptr<IOTracer> io_tracer_;
382
  std::unique_ptr<FSWritableFileTracingWrapper> fs_tracer_;
383
};
384
385
// FSRandomRWFileTracingWrapper is a wrapper class above FSRandomRWFile that
386
// forwards the call to the underlying storage system. It then invokes IOTracer
387
// to record file operations and other contextual information in a binary format
388
// for tracing. It overrides methods we are interested in tracing and extends
389
// FSRandomRWFileWrapper, which forwards all methods that are not explicitly
390
// overridden.
391
class FSRandomRWFileTracingWrapper : public FSRandomRWFileOwnerWrapper {
392
 public:
393
  FSRandomRWFileTracingWrapper(std::unique_ptr<FSRandomRWFile>&& t,
394
                               std::shared_ptr<IOTracer> io_tracer,
395
                               const std::string& file_name)
396
0
      : FSRandomRWFileOwnerWrapper(std::move(t)),
397
0
        io_tracer_(io_tracer),
398
0
        clock_(SystemClock::Default().get()),
399
0
        file_name_(file_name) {}
400
401
0
  ~FSRandomRWFileTracingWrapper() override {}
402
403
  IOStatus Write(uint64_t offset, const Slice& data, const IOOptions& options,
404
                 IODebugContext* dbg) override;
405
406
  IOStatus Read(uint64_t offset, size_t n, const IOOptions& options,
407
                Slice* result, char* scratch,
408
                IODebugContext* dbg) const override;
409
410
  IOStatus Flush(const IOOptions& options, IODebugContext* dbg) override;
411
412
  IOStatus Close(const IOOptions& options, IODebugContext* dbg) override;
413
414
  IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override;
415
416
  IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override;
417
418
 private:
419
  std::shared_ptr<IOTracer> io_tracer_;
420
  SystemClock* clock_;
421
  // Stores file name instead of full path.
422
  std::string file_name_;
423
};
424
425
// The FSRandomRWFilePtr is a wrapper class that takes pointer to storage
426
// systems (such as posix filesystems). It overloads operator -> and returns a
427
// pointer of either FSRandomRWFile or FSRandomRWFileTracingWrapper based on
428
// whether tracing is enabled or not. It is added to bypass
429
// FSRandomRWFileTracingWrapper when tracing is disabled.
430
class FSRandomRWFilePtr {
431
 public:
432
  FSRandomRWFilePtr(std::unique_ptr<FSRandomRWFile>&& fs,
433
                    std::shared_ptr<IOTracer> io_tracer,
434
                    const std::string& file_name)
435
0
      : io_tracer_(io_tracer),
436
0
        fs_tracer_(std::move(fs), io_tracer_,
437
0
                   file_name.substr(file_name.find_last_of("/\\") +
438
0
                                    1) /* pass file name */) {}
439
440
0
  FSRandomRWFile* operator->() const {
441
0
    if (io_tracer_ && io_tracer_->is_tracing_enabled()) {
442
0
      return const_cast<FSRandomRWFileTracingWrapper*>(&fs_tracer_);
443
0
    } else {
444
0
      return fs_tracer_.target();
445
0
    }
446
0
  }
447
448
0
  FSRandomRWFile* get() const {
449
0
    if (io_tracer_ && io_tracer_->is_tracing_enabled()) {
450
0
      return const_cast<FSRandomRWFileTracingWrapper*>(&fs_tracer_);
451
0
    } else {
452
0
      return fs_tracer_.target();
453
0
    }
454
0
  }
455
456
 private:
457
  std::shared_ptr<IOTracer> io_tracer_;
458
  FSRandomRWFileTracingWrapper fs_tracer_;
459
};
460
461
}  // namespace ROCKSDB_NAMESPACE