• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

llnl / dftracer-utils / 29787659139

20 Jul 2026 11:34PM UTC coverage: 51.578% (-1.1%) from 52.66%
29787659139

Pull #99

github

web-flow
Merge ee805adeb into 06bc84ec9
Pull Request #99: Support CM time_metric (NS/MS/SEC/US) across reader and viz

34832 of 86278 branches covered (40.37%)

Branch coverage included in aggregate %.

1034 of 1319 new or added lines in 30 files covered. (78.39%)

5193 existing lines in 197 files now uncovered.

35349 of 49791 relevant lines covered (70.99%)

9765.54 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

60.54
/src/dftracer/utils/core/rocksdb/filesystem.cpp
1
#include <dftracer/utils/core/common/object_pool.h>
2
#include <dftracer/utils/core/io/io_backend.h>
3
#include <dftracer/utils/core/io/io_thread_pool.h>
4
#include <dftracer/utils/core/pipeline/executor.h>
5
#include <dftracer/utils/core/rocksdb/filesystem.h>
6
#include <fcntl.h>
7
#include <rocksdb/env.h>
8
#include <rocksdb/file_system.h>
9
#include <rocksdb/io_status.h>
10
#include <rocksdb/slice.h>
11
#include <sys/stat.h>
12
#include <unistd.h>
13

14
#include <algorithm>
15
#include <cerrno>
16
#include <condition_variable>
17
#include <cstdint>
18
#include <cstring>
19
#include <mutex>
20
#include <string>
21
#include <string_view>
22

23
namespace dftracer::utils::rocksdb {
24

25
namespace {
26

27
io::IoBackend* current_io_backend() {
384,619✔
28
    auto* executor = Executor::current();
384,619✔
29
    if (executor == nullptr || !executor->has_io_backend()) {
384,619!
30
        return nullptr;
247,466✔
31
    }
32
    return &executor->io_backend();
137,153✔
33
}
384,619✔
34

35
class DfTracerFileSystem;
36

37
struct AsyncReadHandle {
38
    explicit AsyncReadHandle(DfTracerFileSystem* owner_) : owner(owner_) {}
4!
39

40
    static void* operator new(std::size_t size) {
1✔
41
        return ObjectPool::instance().allocate(size);
1✔
42
    }
43

44
    static void operator delete(void* ptr, std::size_t size) noexcept {
1✔
45
        ObjectPool::instance().deallocate(ptr, size);
1!
46
    }
1✔
47

48
    DfTracerFileSystem* owner;
49
    std::mutex mutex;
50
    std::condition_variable cv;
51
    bool finished = false;
1✔
52
    bool callback_delivered = false;
1✔
53
    bool aborted = false;
1✔
54
    bool running = false;
1✔
55
    std::string path;
56
    std::uint64_t offset = 0;
1✔
57
    std::size_t len = 0;
1✔
58
    char* scratch = nullptr;
1✔
59
    ::rocksdb::Slice result;
60
    ::rocksdb::IOStatus status;
61
    std::function<void(::rocksdb::FSReadRequest&, void*)> callback;
62
    void* callback_arg = nullptr;
1✔
63
};
64

65
::rocksdb::IOStatus io_error(std::string_view op, std::string_view path) {
627✔
66
    return ::rocksdb::IOStatus::IOError(
627!
67
        std::string(path), std::string(op) + ": " + std::strerror(errno));
627!
UNCOV
68
}
×
69

70
ssize_t pread_sync(int fd, void* buf, std::size_t len, off_t offset) {
232,852✔
71
    if (auto* backend = current_io_backend(); backend != nullptr) {
232,852✔
72
        return backend->submit_read_sync(fd, buf, len, offset);
76,654✔
73
    }
74
    return ::pread(fd, buf, len, offset);
156,198✔
75
}
232,852✔
76

77
ssize_t pwrite_sync(int fd, const void* buf, std::size_t len, off_t offset) {
65,761✔
78
    if (auto* backend = current_io_backend(); backend != nullptr) {
65,761✔
79
        return backend->submit_write_sync(fd, buf, len, offset);
32,363✔
80
    }
81
    return ::pwrite(fd, buf, len, offset);
33,398✔
82
}
65,761✔
83

84
int fsync_sync(int fd) {
29,237✔
85
    if (auto* backend = current_io_backend(); backend != nullptr) {
29,237✔
86
        return backend->submit_fsync_sync(fd);
6,657✔
87
    }
88
    return ::fsync(fd);
22,580✔
89
}
29,237✔
90

91
int ftruncate_sync(int fd, off_t length) {
360✔
92
    if (auto* backend = current_io_backend(); backend != nullptr) {
360✔
93
        return backend->submit_ftruncate_sync(fd, length);
305✔
94
    }
95
    return ::ftruncate(fd, length);
55✔
96
}
360✔
97

98
int fstat_sync(int fd, struct stat* st) {
56,419✔
99
    if (auto* backend = current_io_backend(); backend != nullptr) {
56,419✔
100
        return backend->submit_fstat_sync(fd, st);
21,175✔
101
    }
102
    return ::fstat(fd, st);
35,244✔
103
}
56,419✔
104

105
class DfTracerSequentialFile final : public ::rocksdb::FSSequentialFile {
106
   public:
107
    DfTracerSequentialFile(std::string path, int fd)
125,127✔
108
        : path_(std::move(path)), fd_(fd) {}
125,127✔
109

110
    ~DfTracerSequentialFile() override {
125,127✔
111
        if (fd_ >= 0) {
41,709!
112
            ::close(fd_);
41,709!
113
        }
41,709✔
114
    }
125,127✔
115

116
    ::rocksdb::IOStatus Read(std::size_t n, const ::rocksdb::IOOptions&,
64,630✔
117
                             ::rocksdb::Slice* result, char* scratch,
118
                             ::rocksdb::IODebugContext*) override {
119
        std::lock_guard<std::mutex> lock(mutex_);
64,630✔
120
        const ssize_t bytes =
64,630✔
121
            pread_sync(fd_, scratch, n, static_cast<off_t>(offset_));
64,630!
122
        if (bytes < 0) {
64,630!
123
            return io_error("read", path_);
×
124
        }
125
        offset_ += static_cast<std::uint64_t>(bytes);
64,630✔
126
        *result = ::rocksdb::Slice(scratch, static_cast<std::size_t>(bytes));
64,630!
127
        return ::rocksdb::IOStatus::OK();
64,630!
128
    }
64,630✔
129

130
    ::rocksdb::IOStatus Skip(std::uint64_t n) override {
×
131
        std::lock_guard<std::mutex> lock(mutex_);
×
132
        offset_ += n;
×
133
        return ::rocksdb::IOStatus::OK();
×
134
    }
×
135

136
    ::rocksdb::IOStatus InvalidateCache(std::size_t, std::size_t) override {
×
137
        return ::rocksdb::IOStatus::OK();
×
138
    }
139

140
   private:
141
    std::string path_;
142
    int fd_;
143
    std::uint64_t offset_ = 0;
41,709✔
144
    std::mutex mutex_;
145
};
146

147
class DfTracerRandomAccessFile final : public ::rocksdb::FSRandomAccessFile {
148
   public:
149
    DfTracerRandomAccessFile(DfTracerFileSystem* owner, std::string path,
93,135✔
150
                             int fd)
151
        : owner_(owner), path_(std::move(path)), fd_(fd) {}
93,135✔
152

153
    ~DfTracerRandomAccessFile() override {
139,722✔
154
        if (fd_ >= 0) {
46,574!
155
            ::close(fd_);
46,574!
156
        }
46,574✔
157
    }
139,722✔
158

159
    ::rocksdb::IOStatus Read(std::uint64_t offset, std::size_t n,
168,254✔
160
                             const ::rocksdb::IOOptions&,
161
                             ::rocksdb::Slice* result, char* scratch,
162
                             ::rocksdb::IODebugContext*) const override {
163
        const ssize_t bytes =
168,254✔
164
            pread_sync(fd_, scratch, n, static_cast<off_t>(offset));
168,254✔
165
        if (bytes < 0) {
168,254!
166
            return io_error("pread", path_);
×
167
        }
168
        *result = ::rocksdb::Slice(scratch, static_cast<std::size_t>(bytes));
168,254✔
169
        return ::rocksdb::IOStatus::OK();
168,254✔
170
    }
168,254✔
171

172
    ::rocksdb::IOStatus Prefetch(std::uint64_t, std::size_t,
24,924✔
173
                                 const ::rocksdb::IOOptions&,
174
                                 ::rocksdb::IODebugContext*) override {
175
        return ::rocksdb::IOStatus::OK();
24,924✔
176
    }
177

178
    ::rocksdb::IOStatus ReadAsync(
179
        ::rocksdb::FSReadRequest& req, const ::rocksdb::IOOptions& opts,
180
        std::function<void(::rocksdb::FSReadRequest&, void*)> cb, void* cb_arg,
181
        void** io_handle, ::rocksdb::IOHandleDeleter* del_fn,
182
        ::rocksdb::IODebugContext* dbg) override;
183

184
    ::rocksdb::IOStatus InvalidateCache(std::size_t, std::size_t) override {
×
185
        return ::rocksdb::IOStatus::OK();
×
186
    }
187

188
    ::rocksdb::IOStatus GetFileSize(std::uint64_t* result) override {
45,628✔
189
        struct stat st{};
45,628✔
190
        if (fstat_sync(fd_, &st) != 0) {
45,628!
191
            return io_error("fstat", path_);
×
192
        }
193
        *result = static_cast<std::uint64_t>(st.st_size);
45,628✔
194
        return ::rocksdb::IOStatus::OK();
45,628✔
195
    }
45,628✔
196

197
   private:
198
    DfTracerFileSystem* owner_;
199
    std::string path_;
200
    int fd_;
201
};
202

203
class DfTracerWritableFile final : public ::rocksdb::FSWritableFile {
204
   public:
205
    using ::rocksdb::FSWritableFile::Append;
206
    using ::rocksdb::FSWritableFile::PositionedAppend;
207

208
    DfTracerWritableFile(std::string path, int fd,
32,391✔
209
                         const ::rocksdb::FileOptions& options)
210
        : ::rocksdb::FSWritableFile(options), path_(std::move(path)), fd_(fd) {
21,594✔
211
        struct stat st{};
10,797✔
212
        if (fstat_sync(fd_, &st) == 0) {
10,797!
213
            size_ = static_cast<std::uint64_t>(st.st_size);
10,797✔
214
        }
10,797✔
215
    }
21,594✔
216

217
    ~DfTracerWritableFile() override {
32,391✔
218
        if (fd_ >= 0) {
10,797✔
219
            static_cast<void>(close_fd());
2,115!
220
        }
2,115✔
221
    }
32,391✔
222

223
    ::rocksdb::IOStatus Append(const ::rocksdb::Slice& data,
65,761✔
224
                               const ::rocksdb::IOOptions&,
225
                               ::rocksdb::IODebugContext*) override {
226
        std::lock_guard<std::mutex> lock(mutex_);
65,761✔
227
        return write_at(data, size_);
65,761!
228
    }
65,761✔
229

230
    ::rocksdb::IOStatus PositionedAppend(const ::rocksdb::Slice& data,
×
231
                                         std::uint64_t offset,
232
                                         const ::rocksdb::IOOptions&,
233
                                         ::rocksdb::IODebugContext*) override {
234
        std::lock_guard<std::mutex> lock(mutex_);
×
235
        return write_at(data, offset);
×
236
    }
×
237

238
    ::rocksdb::IOStatus Truncate(std::uint64_t size,
360✔
239
                                 const ::rocksdb::IOOptions&,
240
                                 ::rocksdb::IODebugContext*) override {
241
        std::lock_guard<std::mutex> lock(mutex_);
360✔
242
        if (ftruncate_sync(fd_, static_cast<off_t>(size)) != 0) {
360!
243
            return io_error("ftruncate", path_);
×
244
        }
245
        size_ = size;
360✔
246
        return ::rocksdb::IOStatus::OK();
360!
247
    }
360✔
248

249
    ::rocksdb::IOStatus Close(const ::rocksdb::IOOptions&,
8,682✔
250
                              ::rocksdb::IODebugContext*) override {
251
        std::lock_guard<std::mutex> lock(mutex_);
8,682✔
252
        return close_fd();
8,682!
253
    }
8,682✔
254

255
    ::rocksdb::IOStatus Flush(const ::rocksdb::IOOptions&,
95,717✔
256
                              ::rocksdb::IODebugContext*) override {
257
        return ::rocksdb::IOStatus::OK();
95,717✔
258
    }
259

260
    ::rocksdb::IOStatus Sync(const ::rocksdb::IOOptions&,
29,238✔
261
                             ::rocksdb::IODebugContext*) override {
262
        std::lock_guard<std::mutex> lock(mutex_);
29,238✔
263
        if (fd_ < 0) {
29,238!
264
            return ::rocksdb::IOStatus::OK();
×
265
        }
266
        if (fsync_sync(fd_) != 0) {
29,238!
267
            return io_error("fsync", path_);
×
268
        }
269
        return ::rocksdb::IOStatus::OK();
29,237✔
270
    }
29,238✔
271

272
    bool IsSyncThreadSafe() const override { return true; }
×
273

274
    std::uint64_t GetFileSize(const ::rocksdb::IOOptions&,
63,645✔
275
                              ::rocksdb::IODebugContext*) override {
276
        std::lock_guard<std::mutex> lock(mutex_);
63,645✔
277
        return size_;
63,645✔
278
    }
63,645✔
279

280
    ::rocksdb::IOStatus InvalidateCache(std::size_t, std::size_t) override {
×
281
        return ::rocksdb::IOStatus::OK();
×
282
    }
283

284
    ::rocksdb::IOStatus RangeSync(std::uint64_t, std::uint64_t,
×
285
                                  const ::rocksdb::IOOptions& options,
286
                                  ::rocksdb::IODebugContext* dbg) override {
287
        return Sync(options, dbg);
×
288
    }
289

290
   private:
291
    ::rocksdb::IOStatus write_at(const ::rocksdb::Slice& data,
65,761✔
292
                                 std::uint64_t offset) {
293
        const ssize_t bytes = pwrite_sync(fd_, data.data(), data.size(),
131,522✔
294
                                          static_cast<off_t>(offset));
65,761✔
295
        if (bytes < 0 || static_cast<std::size_t>(bytes) != data.size()) {
65,761!
UNCOV
296
            return io_error("pwrite", path_);
×
297
        }
298
        size_ = std::max(size_, offset + static_cast<std::uint64_t>(bytes));
65,761✔
299
        return ::rocksdb::IOStatus::OK();
65,761✔
300
    }
65,761✔
301

302
    ::rocksdb::IOStatus close_fd() {
10,797✔
303
        if (fd_ < 0) {
10,797!
304
            return ::rocksdb::IOStatus::OK();
×
305
        }
306
        if (::close(fd_) != 0) {
10,797!
307
            return io_error("close", path_);
×
308
        }
309
        fd_ = -1;
10,797✔
310
        return ::rocksdb::IOStatus::OK();
10,797✔
311
    }
10,797✔
312

313
    std::string path_;
314
    int fd_;
315
    std::uint64_t size_ = 0;
10,797✔
316
    mutable std::mutex mutex_;
317
};
318

319
class LocalFileSystemWrapper : public ::rocksdb::FileSystem {
320
   public:
321
    explicit LocalFileSystemWrapper(
6,282✔
322
        const std::shared_ptr<::rocksdb::FileSystem>& target)
323
        : target_(target) {}
6,282✔
324

325
    ::rocksdb::FileSystem* target() const { return target_.get(); }
326

327
    ::rocksdb::IOStatus NewSequentialFile(
×
328
        const std::string& f, const ::rocksdb::FileOptions& file_opts,
329
        std::unique_ptr<::rocksdb::FSSequentialFile>* r,
330
        ::rocksdb::IODebugContext* dbg) override {
331
        return target_->NewSequentialFile(f, file_opts, r, dbg);
×
332
    }
333

334
    ::rocksdb::IOStatus NewRandomAccessFile(
×
335
        const std::string& f, const ::rocksdb::FileOptions& file_opts,
336
        std::unique_ptr<::rocksdb::FSRandomAccessFile>* r,
337
        ::rocksdb::IODebugContext* dbg) override {
338
        return target_->NewRandomAccessFile(f, file_opts, r, dbg);
×
339
    }
340

341
    ::rocksdb::IOStatus NewWritableFile(
×
342
        const std::string& f, const ::rocksdb::FileOptions& file_opts,
343
        std::unique_ptr<::rocksdb::FSWritableFile>* r,
344
        ::rocksdb::IODebugContext* dbg) override {
345
        return target_->NewWritableFile(f, file_opts, r, dbg);
×
346
    }
347

348
    ::rocksdb::IOStatus ReopenWritableFile(
×
349
        const std::string& fname, const ::rocksdb::FileOptions& file_opts,
350
        std::unique_ptr<::rocksdb::FSWritableFile>* result,
351
        ::rocksdb::IODebugContext* dbg) override {
352
        return target_->ReopenWritableFile(fname, file_opts, result, dbg);
×
353
    }
354

355
    ::rocksdb::IOStatus ReuseWritableFile(
×
356
        const std::string& fname, const std::string& old_fname,
357
        const ::rocksdb::FileOptions& file_opts,
358
        std::unique_ptr<::rocksdb::FSWritableFile>* r,
359
        ::rocksdb::IODebugContext* dbg) override {
360
        return target_->ReuseWritableFile(fname, old_fname, file_opts, r, dbg);
×
361
    }
362

363
    ::rocksdb::IOStatus NewRandomRWFile(
×
364
        const std::string& fname, const ::rocksdb::FileOptions& file_opts,
365
        std::unique_ptr<::rocksdb::FSRandomRWFile>* result,
366
        ::rocksdb::IODebugContext* dbg) override {
367
        return target_->NewRandomRWFile(fname, file_opts, result, dbg);
×
368
    }
369

370
    ::rocksdb::IOStatus NewMemoryMappedFileBuffer(
×
371
        const std::string& fname,
372
        std::unique_ptr<::rocksdb::MemoryMappedFileBuffer>* result) override {
373
        return target_->NewMemoryMappedFileBuffer(fname, result);
×
374
    }
375

376
    ::rocksdb::IOStatus NewDirectory(
18,045✔
377
        const std::string& name, const ::rocksdb::IOOptions& io_opts,
378
        std::unique_ptr<::rocksdb::FSDirectory>* result,
379
        ::rocksdb::IODebugContext* dbg) override {
380
        return target_->NewDirectory(name, io_opts, result, dbg);
18,045✔
381
    }
382

383
    ::rocksdb::IOStatus FileExists(const std::string& f,
8,149✔
384
                                   const ::rocksdb::IOOptions& io_opts,
385
                                   ::rocksdb::IODebugContext* dbg) override {
386
        return target_->FileExists(f, io_opts, dbg);
8,149✔
387
    }
388

389
    ::rocksdb::IOStatus GetChildren(const std::string& dir,
11,936✔
390
                                    const ::rocksdb::IOOptions& io_opts,
391
                                    std::vector<std::string>* r,
392
                                    ::rocksdb::IODebugContext* dbg) override {
393
        return target_->GetChildren(dir, io_opts, r, dbg);
11,936✔
394
    }
395

396
    ::rocksdb::IOStatus GetChildrenFileAttributes(
×
397
        const std::string& dir, const ::rocksdb::IOOptions& options,
398
        std::vector<::rocksdb::FileAttributes>* result,
399
        ::rocksdb::IODebugContext* dbg) override {
400
        return target_->GetChildrenFileAttributes(dir, options, result, dbg);
×
401
    }
402

403
    ::rocksdb::IOStatus DeleteFile(const std::string& f,
1,514✔
404
                                   const ::rocksdb::IOOptions& options,
405
                                   ::rocksdb::IODebugContext* dbg) override {
406
        return target_->DeleteFile(f, options, dbg);
1,514✔
407
    }
408

409
    ::rocksdb::IOStatus Truncate(const std::string& fname, size_t size,
×
410
                                 const ::rocksdb::IOOptions& options,
411
                                 ::rocksdb::IODebugContext* dbg) override {
412
        return target_->Truncate(fname, size, options, dbg);
×
413
    }
414

415
    ::rocksdb::IOStatus CreateDir(const std::string& d,
×
416
                                  const ::rocksdb::IOOptions& options,
417
                                  ::rocksdb::IODebugContext* dbg) override {
418
        return target_->CreateDir(d, options, dbg);
×
419
    }
420

421
    ::rocksdb::IOStatus CreateDirIfMissing(
19,350✔
422
        const std::string& d, const ::rocksdb::IOOptions& options,
423
        ::rocksdb::IODebugContext* dbg) override {
424
        return target_->CreateDirIfMissing(d, options, dbg);
19,350✔
425
    }
426

427
    ::rocksdb::IOStatus DeleteDir(const std::string& d,
×
428
                                  const ::rocksdb::IOOptions& options,
429
                                  ::rocksdb::IODebugContext* dbg) override {
430
        return target_->DeleteDir(d, options, dbg);
×
431
    }
432

433
    ::rocksdb::IOStatus GetFileSize(const std::string& f,
24,409✔
434
                                    const ::rocksdb::IOOptions& options,
435
                                    uint64_t* s,
436
                                    ::rocksdb::IODebugContext* dbg) override {
437
        return target_->GetFileSize(f, options, s, dbg);
24,409✔
438
    }
439

440
    ::rocksdb::IOStatus GetFileModificationTime(
×
441
        const std::string& fname, const ::rocksdb::IOOptions& options,
442
        uint64_t* file_mtime, ::rocksdb::IODebugContext* dbg) override {
443
        return target_->GetFileModificationTime(fname, options, file_mtime,
×
444
                                                dbg);
×
445
    }
446

447
    ::rocksdb::IOStatus GetAbsolutePath(
945✔
448
        const std::string& db_path, const ::rocksdb::IOOptions& options,
449
        std::string* output_path, ::rocksdb::IODebugContext* dbg) override {
450
        return target_->GetAbsolutePath(db_path, options, output_path, dbg);
945✔
451
    }
452

453
    ::rocksdb::IOStatus RenameFile(const std::string& s, const std::string& t,
3,420✔
454
                                   const ::rocksdb::IOOptions& options,
455
                                   ::rocksdb::IODebugContext* dbg) override {
456
        return target_->RenameFile(s, t, options, dbg);
3,420✔
457
    }
458

459
    ::rocksdb::IOStatus LinkFile(const std::string& s, const std::string& t,
×
460
                                 const ::rocksdb::IOOptions& options,
461
                                 ::rocksdb::IODebugContext* dbg) override {
462
        return target_->LinkFile(s, t, options, dbg);
×
463
    }
464

465
    ::rocksdb::IOStatus NumFileLinks(const std::string& fname,
×
466
                                     const ::rocksdb::IOOptions& options,
467
                                     uint64_t* count,
468
                                     ::rocksdb::IODebugContext* dbg) override {
469
        return target_->NumFileLinks(fname, options, count, dbg);
×
470
    }
471

472
    ::rocksdb::IOStatus AreFilesSame(const std::string& first,
×
473
                                     const std::string& second,
474
                                     const ::rocksdb::IOOptions& options,
475
                                     bool* res,
476
                                     ::rocksdb::IODebugContext* dbg) override {
477
        return target_->AreFilesSame(first, second, options, res, dbg);
×
478
    }
479

480
    ::rocksdb::IOStatus LockFile(const std::string& f,
945✔
481
                                 const ::rocksdb::IOOptions& options,
482
                                 ::rocksdb::FileLock** l,
483
                                 ::rocksdb::IODebugContext* dbg) override {
484
        return target_->LockFile(f, options, l, dbg);
945✔
485
    }
486

487
    ::rocksdb::IOStatus UnlockFile(::rocksdb::FileLock* l,
945✔
488
                                   const ::rocksdb::IOOptions& options,
489
                                   ::rocksdb::IODebugContext* dbg) override {
490
        return target_->UnlockFile(l, options, dbg);
945✔
491
    }
492

493
    ::rocksdb::IOStatus GetTestDirectory(
×
494
        const ::rocksdb::IOOptions& options, std::string* path,
495
        ::rocksdb::IODebugContext* dbg) override {
496
        return target_->GetTestDirectory(options, path, dbg);
×
497
    }
498

499
    ::rocksdb::IOStatus NewLogger(const std::string& fname,
945✔
500
                                  const ::rocksdb::IOOptions& options,
501
                                  std::shared_ptr<::rocksdb::Logger>* result,
502
                                  ::rocksdb::IODebugContext* dbg) override {
503
        return target_->NewLogger(fname, options, result, dbg);
945✔
504
    }
505

506
    void SanitizeFileOptions(::rocksdb::FileOptions* opts) const override {
×
507
        target_->SanitizeFileOptions(opts);
×
508
    }
×
509

510
    ::rocksdb::FileOptions OptimizeForLogRead(
5,674✔
511
        const ::rocksdb::FileOptions& file_options) const override {
512
        return target_->OptimizeForLogRead(file_options);
5,674✔
513
    }
514

515
    ::rocksdb::FileOptions OptimizeForManifestRead(
6,259✔
516
        const ::rocksdb::FileOptions& file_options) const override {
517
        return target_->OptimizeForManifestRead(file_options);
6,259✔
518
    }
519

520
    ::rocksdb::FileOptions OptimizeForLogWrite(
1,305✔
521
        const ::rocksdb::FileOptions& file_options,
522
        const ::rocksdb::DBOptions& db_options) const override {
523
        return target_->OptimizeForLogWrite(file_options, db_options);
1,305✔
524
    }
525

526
    ::rocksdb::FileOptions OptimizeForManifestWrite(
21,289✔
527
        const ::rocksdb::FileOptions& file_options) const override {
528
        return target_->OptimizeForManifestWrite(file_options);
21,289✔
529
    }
530

531
    ::rocksdb::FileOptions OptimizeForCompactionTableWrite(
6,259✔
532
        const ::rocksdb::FileOptions& file_options,
533
        const ::rocksdb::ImmutableDBOptions& immutable_opts) const override {
534
        return target_->OptimizeForCompactionTableWrite(file_options,
12,518✔
535
                                                        immutable_opts);
6,259✔
536
    }
537

538
    ::rocksdb::FileOptions OptimizeForCompactionTableRead(
5✔
539
        const ::rocksdb::FileOptions& file_options,
540
        const ::rocksdb::ImmutableDBOptions& db_options) const override {
541
        return target_->OptimizeForCompactionTableRead(file_options,
10✔
542
                                                       db_options);
5✔
543
    }
544

545
    ::rocksdb::FileOptions OptimizeForBlobFileRead(
×
546
        const ::rocksdb::FileOptions& file_options,
547
        const ::rocksdb::ImmutableDBOptions& db_options) const override {
548
        return target_->OptimizeForBlobFileRead(file_options, db_options);
×
549
    }
550

551
    ::rocksdb::IOStatus GetFreeSpace(const std::string& path,
×
552
                                     const ::rocksdb::IOOptions& options,
553
                                     uint64_t* diskfree,
554
                                     ::rocksdb::IODebugContext* dbg) override {
555
        return target_->GetFreeSpace(path, options, diskfree, dbg);
×
556
    }
557

558
    ::rocksdb::IOStatus IsDirectory(const std::string& path,
×
559
                                    const ::rocksdb::IOOptions& options,
560
                                    bool* is_dir,
561
                                    ::rocksdb::IODebugContext* dbg) override {
562
        return target_->IsDirectory(path, options, is_dir, dbg);
×
563
    }
564

565
    const ::rocksdb::Customizable* Inner() const override {
×
566
        return target_.get();
×
567
    }
568

569
    ::rocksdb::Status PrepareOptions(
×
570
        const ::rocksdb::ConfigOptions& options) override {
571
        return target_->PrepareOptions(options);
×
572
    }
573

574
    std::string SerializeOptions(const ::rocksdb::ConfigOptions& config_options,
×
575
                                 const std::string& header) const override {
576
        return ::rocksdb::FileSystem::SerializeOptions(config_options, header);
×
577
    }
578

579
    ::rocksdb::IOStatus Poll(std::vector<void*>& io_handles,
×
580
                             size_t min_completions) override {
581
        return target_->Poll(io_handles, min_completions);
×
582
    }
583

584
    ::rocksdb::IOStatus AbortIO(std::vector<void*>& io_handles) override {
×
585
        return target_->AbortIO(io_handles);
×
586
    }
587

588
    void DiscardCacheForDirectory(const std::string& path) override {
×
589
        target_->DiscardCacheForDirectory(path);
×
590
    }
×
591

592
    void SupportedOps(int64_t& supported_ops) override {
×
593
        target_->SupportedOps(supported_ops);
×
594
    }
×
595

596
   protected:
597
    std::shared_ptr<::rocksdb::FileSystem> target_;
598
};
599

600
class DfTracerFileSystem final : public LocalFileSystemWrapper {
601
   public:
602
    explicit DfTracerFileSystem(
12,564✔
603
        const std::shared_ptr<::rocksdb::FileSystem>& target)
604
        : LocalFileSystemWrapper(target), fallback_pool_(4) {
12,564!
605
        fallback_pool_.start();
6,282!
606
    }
12,564✔
607

608
    ~DfTracerFileSystem() override { fallback_pool_.stop(); }
12,564!
609

610
    static const char* class_name() { return "DfTracerFileSystem"; }
6,258✔
611

612
    const char* Name() const override { return class_name(); }
6,258✔
613

614
    bool IsInstanceOf(const std::string& name) const override {
×
615
        return name == class_name() ||
×
616
               LocalFileSystemWrapper::IsInstanceOf(name);
×
617
    }
618

619
    void SupportedOps(int64_t& supported_ops) override {
763,945✔
620
        supported_ops = 0;
763,945✔
621
        supported_ops |= (1 << ::rocksdb::FSSupportedOps::kAsyncIO);
763,945✔
622
        supported_ops |= (1 << ::rocksdb::FSSupportedOps::kFSPrefetch);
763,945✔
623
    }
763,945✔
624

625
    ::rocksdb::IOStatus NewSequentialFile(
42,316✔
626
        const std::string& fname, const ::rocksdb::FileOptions&,
627
        std::unique_ptr<::rocksdb::FSSequentialFile>* result,
628
        ::rocksdb::IODebugContext*) override {
629
        int fd = ::open(fname.c_str(), O_RDONLY | O_CLOEXEC);
42,316✔
630
        if (fd < 0) {
42,316✔
631
            return io_error("open", fname);
607✔
632
        }
633
        result->reset(new DfTracerSequentialFile(fname, fd));
41,709!
634
        return ::rocksdb::IOStatus::OK();
41,709✔
635
    }
42,316✔
636

637
    ::rocksdb::IOStatus NewRandomAccessFile(
46,563✔
638
        const std::string& fname, const ::rocksdb::FileOptions&,
639
        std::unique_ptr<::rocksdb::FSRandomAccessFile>* result,
640
        ::rocksdb::IODebugContext*) override {
641
        int fd = ::open(fname.c_str(), O_RDONLY | O_CLOEXEC);
46,563✔
642
        if (fd < 0) {
46,563!
643
            return io_error("open", fname);
×
644
        }
645
        result->reset(new DfTracerRandomAccessFile(this, fname, fd));
46,563!
646
        return ::rocksdb::IOStatus::OK();
46,563✔
647
    }
46,563✔
648

649
    ::rocksdb::IOStatus NewWritableFile(
10,457✔
650
        const std::string& fname, const ::rocksdb::FileOptions& file_opts,
651
        std::unique_ptr<::rocksdb::FSWritableFile>* result,
652
        ::rocksdb::IODebugContext*) override {
653
        int fd =
10,457✔
654
            ::open(fname.c_str(), O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0644);
10,457✔
655
        if (fd < 0) {
10,457✔
656
            return io_error("open", fname);
20✔
657
        }
658
        result->reset(new DfTracerWritableFile(fname, fd, file_opts));
10,437!
659
        return ::rocksdb::IOStatus::OK();
10,437✔
660
    }
10,457✔
661

662
    ::rocksdb::IOStatus ReopenWritableFile(
360✔
663
        const std::string& fname, const ::rocksdb::FileOptions& file_opts,
664
        std::unique_ptr<::rocksdb::FSWritableFile>* result,
665
        ::rocksdb::IODebugContext*) override {
666
        int fd = ::open(fname.c_str(), O_CREAT | O_RDWR | O_CLOEXEC, 0644);
360✔
667
        if (fd < 0) {
360!
668
            return io_error("open", fname);
×
669
        }
670
        result->reset(new DfTracerWritableFile(fname, fd, file_opts));
360!
671
        return ::rocksdb::IOStatus::OK();
360✔
672
    }
360✔
673

674
    ::rocksdb::IOStatus ReuseWritableFile(
×
675
        const std::string& fname, const std::string& old_fname,
676
        const ::rocksdb::FileOptions& file_opts,
677
        std::unique_ptr<::rocksdb::FSWritableFile>* result,
678
        ::rocksdb::IODebugContext*) override {
679
        ::unlink(fname.c_str());
×
680
        if (::rename(old_fname.c_str(), fname.c_str()) != 0) {
×
681
            return io_error("rename", old_fname);
×
682
        }
683
        return ReopenWritableFile(fname, file_opts, result, nullptr);
×
UNCOV
684
    }
×
685

686
    ::rocksdb::IOStatus Poll(std::vector<void*>& io_handles,
1✔
687
                             size_t min_completions) override {
688
        const size_t target = std::min(min_completions, io_handles.size());
1✔
689
        if (target == 0) {
1!
690
            return ::rocksdb::IOStatus::OK();
×
691
        }
692
        std::unique_lock<std::mutex> lock(completions_mutex_);
1✔
693
        completions_cv_.wait(lock, [&] {
3!
694
            size_t completed = 0;
2✔
695
            for (void* io_handle : io_handles) {
4✔
696
                auto* handle = static_cast<AsyncReadHandle*>(io_handle);
2✔
697
                std::lock_guard<std::mutex> handle_lock(handle->mutex);
2✔
698
                if (handle->finished && !handle->callback_delivered) {
2!
699
                    ++completed;
1✔
700
                }
1✔
701
            }
2✔
702
            return completed >= target;
2✔
703
        });
704
        lock.unlock();
1!
705

706
        for (void* io_handle : io_handles) {
2✔
707
            auto* handle = static_cast<AsyncReadHandle*>(io_handle);
1✔
708
            std::unique_lock<std::mutex> handle_lock(handle->mutex);
1!
709
            if (!handle->finished || handle->callback_delivered ||
1!
710
                handle->aborted) {
1✔
711
                continue;
×
712
            }
713
            handle->callback_delivered = true;
1✔
714
            auto callback = handle->callback;
1!
715
            auto callback_arg = handle->callback_arg;
1✔
716
            ::rocksdb::FSReadRequest req;
1!
717
            req.offset = handle->offset;
1✔
718
            req.len = handle->len;
1✔
719
            req.scratch = handle->scratch;
1✔
720
            req.result = handle->result;
1✔
721
            req.status = handle->status;
1!
722
            handle_lock.unlock();
1!
723
            callback(req, callback_arg);
1!
724
        }
1!
725
        return ::rocksdb::IOStatus::OK();
1!
726
    }
1✔
727

728
    ::rocksdb::IOStatus AbortIO(std::vector<void*>& io_handles) override {
×
729
        for (void* io_handle : io_handles) {
×
730
            auto* handle = static_cast<AsyncReadHandle*>(io_handle);
×
731
            std::lock_guard<std::mutex> lock(handle->mutex);
×
732
            handle->aborted = true;
×
733
        }
×
734

735
        for (void* io_handle : io_handles) {
×
736
            auto* handle = static_cast<AsyncReadHandle*>(io_handle);
×
737
            std::unique_lock<std::mutex> lock(handle->mutex);
×
738
            handle->cv.wait(lock, [&] { return handle->finished; });
×
739
            handle->callback_delivered = true;
×
740
        }
×
741

742
        return ::rocksdb::IOStatus::OK();
×
UNCOV
743
    }
×
744

745
    void submit_async_read(AsyncReadHandle* handle, int fd, std::string path,
1✔
746
                           ::rocksdb::IODebugContext* dbg) {
747
        {
748
            std::lock_guard<std::mutex> lock(handle->mutex);
1✔
749
            handle->running = true;
1✔
750
            handle->path = path;
1!
751
        }
1✔
752
        if (auto* backend = current_io_backend(); backend != nullptr) {
1!
753
            backend->submit_pread_callback(fd, handle->scratch, handle->len,
×
754
                                           static_cast<off_t>(handle->offset),
×
755
                                           &DfTracerFileSystem::on_pread_done,
UNCOV
756
                                           handle);
×
757
            return;
×
758
        }
759

760
        fallback_pool_.submit([this, handle, fd, path = std::move(path), dbg] {
2!
761
            ::rocksdb::Slice result;
1✔
762
            auto status = read_async_impl(fd, path, handle->offset, handle->len,
2✔
763
                                          &result, handle->scratch, dbg);
1✔
764
            complete_async_read(handle, status, result);
1!
765
        });
1✔
766
    }
1✔
767

768
    static ::rocksdb::IOStatus read_async_impl(
1✔
769
        int fd, std::string_view path, std::uint64_t offset, std::size_t n,
770
        ::rocksdb::Slice* result, char* scratch, ::rocksdb::IODebugContext*) {
771
        const ssize_t bytes =
1✔
772
            ::pread(fd, scratch, n, static_cast<off_t>(offset));
1✔
773
        if (bytes < 0) {
1!
774
            return io_error("pread", path);
×
775
        }
776
        *result = ::rocksdb::Slice(scratch, static_cast<std::size_t>(bytes));
1✔
777
        return ::rocksdb::IOStatus::OK();
1✔
778
    }
1✔
779

780
    static void delete_async_read_handle(void* io_handle) {
1✔
781
        delete static_cast<AsyncReadHandle*>(io_handle);
1!
782
    }
1✔
783

784
   private:
785
    void complete_async_read(AsyncReadHandle* handle,
1✔
786
                             const ::rocksdb::IOStatus& status,
787
                             const ::rocksdb::Slice& result) {
788
        {
789
            std::lock_guard<std::mutex> lock(handle->mutex);
1✔
790
            handle->result = result;
1✔
791
            handle->status = status;
1!
792
            handle->running = false;
1✔
793
            handle->finished = true;
1✔
794
        }
1✔
795
        handle->cv.notify_all();
1✔
796

797
        std::lock_guard<std::mutex> lock(completions_mutex_);
1✔
798
        completions_cv_.notify_all();
1✔
799
    }
1✔
800

801
    static void on_pread_done(void* context, ssize_t result) noexcept {
×
802
        auto* handle = static_cast<AsyncReadHandle*>(context);
×
803
        ::rocksdb::IOStatus status = ::rocksdb::IOStatus::OK();
×
804
        ::rocksdb::Slice slice;
×
805
        if (result < 0) {
×
806
            errno = static_cast<int>(-result);
×
807
            status = io_error("pread", handle->path);
×
UNCOV
808
        } else {
×
809
            slice = ::rocksdb::Slice(handle->scratch,
×
UNCOV
810
                                     static_cast<std::size_t>(result));
×
811
        }
812
        handle->owner->complete_async_read(handle, status, slice);
×
813
    }
×
814

815
    io::IoThreadPool fallback_pool_;
816
    std::mutex completions_mutex_;
817
    std::condition_variable completions_cv_;
818
};
819

820
::rocksdb::IOStatus DfTracerRandomAccessFile::ReadAsync(
1✔
821
    ::rocksdb::FSReadRequest& req, const ::rocksdb::IOOptions&,
822
    std::function<void(::rocksdb::FSReadRequest&, void*)> cb, void* cb_arg,
823
    void** io_handle, ::rocksdb::IOHandleDeleter* del_fn,
824
    ::rocksdb::IODebugContext* dbg) {
825
    auto* handle = new AsyncReadHandle(owner_);
1!
826
    handle->offset = req.offset;
1✔
827
    handle->len = req.len;
1✔
828
    handle->scratch = req.scratch;
1✔
829
    handle->callback = std::move(cb);
1✔
830
    handle->callback_arg = cb_arg;
1✔
831
    *io_handle = static_cast<void*>(handle);
1✔
832
    *del_fn = &DfTracerFileSystem::delete_async_read_handle;
1✔
833
    owner_->submit_async_read(handle, fd_, path_, dbg);
1!
834
    return ::rocksdb::IOStatus::OK();
1✔
UNCOV
835
}
×
836

837
}  // namespace
838

839
std::shared_ptr<::rocksdb::FileSystem> make_dftracer_file_system() {
6,282✔
840
    return std::make_shared<DfTracerFileSystem>(
6,282!
841
        ::rocksdb::FileSystem::Default());
6,282✔
UNCOV
842
}
×
843

844
std::unique_ptr<::rocksdb::Env> make_dftracer_env(
6,281✔
845
    const std::shared_ptr<::rocksdb::FileSystem>& file_system) {
846
    return ::rocksdb::NewCompositeEnv(file_system);
6,281✔
847
}
848

849
}  // namespace dftracer::utils::rocksdb
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc