rocksdb/env/file_system_tracer.h
Akanksha Mahajan c8bae6e29c Provide support for IOTracing for ReadAsync API (#9833)
Summary:
Same as title

Pull Request resolved: https://github.com/facebook/rocksdb/pull/9833

Test Plan:
Add unit test and manually check the output of tracing logs
For fixed readahead_size it logs as:
```
Access Time : 193352113447923     , File Name: 000026.sst          , File Operation: ReadAsync         , Latency: 15075     , IO Status: OK, Length: 12288, Offset: 659456
Access Time : 193352113465232     , File Name: 000026.sst          , File Operation: ReadAsync         , Latency: 14425     , IO Status: OK, Length: 12288, Offset: 671744
Access Time : 193352113481539     , File Name: 000026.sst          , File Operation: ReadAsync         , Latency: 13062     , IO Status: OK, Length: 12288, Offset: 684032
Access Time : 193352113497692     , File Name: 000026.sst          , File Operation: ReadAsync         , Latency: 13649     , IO Status: OK, Length: 12288, Offset: 696320
Access Time : 193352113520043     , File Name: 000026.sst          , File Operation: ReadAsync         , Latency: 19384     , IO Status: OK, Length: 12288, Offset: 708608
Access Time : 193352113538401     , File Name: 000026.sst          , File Operation: ReadAsync         , Latency: 15406     , IO Status: OK, Length: 12288, Offset: 720896
Access Time : 193352113554855     , File Name: 000026.sst          , File Operation: ReadAsync         , Latency: 13670     , IO Status: OK, Length: 12288, Offset: 733184
Access Time : 193352113571624     , File Name: 000026.sst          , File Operation: ReadAsync         , Latency: 13855     , IO Status: OK, Length: 12288, Offset: 745472
Access Time : 193352113587924     , File Name: 000026.sst          , File Operation: ReadAsync         , Latency: 13953     , IO Status: OK, Length: 12288, Offset: 757760
Access Time : 193352113603285     , File Name: 000026.sst          , File Operation: Prefetch          , Latency: 59        , IO Status: Not implemented: Prefetch not supported, Length: 8868, Offset: 898349
```

For implicit readahead:
```
Access Time : 193351865156587     , File Name: 000026.sst          , File Operation: Prefetch          , Latency: 48        , IO Status: Not implemented: Prefetch not supported, Length: 12266, Offset: 391174
Access Time : 193351865160354     , File Name: 000026.sst          , File Operation: Prefetch          , Latency: 51        , IO Status: Not implemented: Prefetch not supported, Length: 12266, Offset: 395248
Access Time : 193351865164253     , File Name: 000026.sst          , File Operation: Prefetch          , Latency: 49        , IO Status: Not implemented: Prefetch not supported, Length: 12266, Offset: 399322
Access Time : 193351865165461     , File Name: 000026.sst          , File Operation: ReadAsync         , Latency: 222871    , IO Status: OK, Length: 135168, Offset: 401408
```

Reviewed By: anand1976

Differential Revision: D35601634

Pulled By: akankshamahajan15

fbshipit-source-id: 5a4f32a850af878efa0767bd5706380152a1f26e
2022-05-25 20:31:45 -07:00

462 lines
18 KiB
C++

// Copyright (c) 2019-present, Facebook, Inc. All rights reserved.
// This source code is licensed under both the GPLv2 (found in the
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).
#pragma once
#include "rocksdb/file_system.h"
#include "rocksdb/system_clock.h"
#include "trace_replay/io_tracer.h"
namespace ROCKSDB_NAMESPACE {
// FileSystemTracingWrapper is a wrapper class above FileSystem that forwards
// the call to the underlying storage system. It then invokes IOTracer to record
// file operations and other contextual information in a binary format for
// tracing. It overrides methods we are interested in tracing and extends
// FileSystemWrapper, which forwards all methods that are not explicitly
// overridden.
class FileSystemTracingWrapper : public FileSystemWrapper {
public:
FileSystemTracingWrapper(const std::shared_ptr<FileSystem>& t,
const std::shared_ptr<IOTracer>& io_tracer)
: FileSystemWrapper(t),
io_tracer_(io_tracer),
clock_(SystemClock::Default().get()) {}
~FileSystemTracingWrapper() override {}
static const char* kClassName() { return "FileSystemTracing"; }
const char* Name() const override { return kClassName(); }
IOStatus NewSequentialFile(const std::string& fname,
const FileOptions& file_opts,
std::unique_ptr<FSSequentialFile>* result,
IODebugContext* dbg) override;
IOStatus NewRandomAccessFile(const std::string& fname,
const FileOptions& file_opts,
std::unique_ptr<FSRandomAccessFile>* result,
IODebugContext* dbg) override;
IOStatus NewWritableFile(const std::string& fname,
const FileOptions& file_opts,
std::unique_ptr<FSWritableFile>* result,
IODebugContext* dbg) override;
IOStatus ReopenWritableFile(const std::string& fname,
const FileOptions& file_opts,
std::unique_ptr<FSWritableFile>* result,
IODebugContext* dbg) override;
IOStatus ReuseWritableFile(const std::string& fname,
const std::string& old_fname,
const FileOptions& file_opts,
std::unique_ptr<FSWritableFile>* result,
IODebugContext* dbg) override;
IOStatus NewRandomRWFile(const std::string& fname, const FileOptions& options,
std::unique_ptr<FSRandomRWFile>* result,
IODebugContext* dbg) override;
IOStatus NewDirectory(const std::string& name, const IOOptions& io_opts,
std::unique_ptr<FSDirectory>* result,
IODebugContext* dbg) override;
IOStatus GetChildren(const std::string& dir, const IOOptions& io_opts,
std::vector<std::string>* r,
IODebugContext* dbg) override;
IOStatus DeleteFile(const std::string& fname, const IOOptions& options,
IODebugContext* dbg) override;
IOStatus CreateDir(const std::string& dirname, const IOOptions& options,
IODebugContext* dbg) override;
IOStatus CreateDirIfMissing(const std::string& dirname,
const IOOptions& options,
IODebugContext* dbg) override;
IOStatus DeleteDir(const std::string& dirname, const IOOptions& options,
IODebugContext* dbg) override;
IOStatus GetFileSize(const std::string& fname, const IOOptions& options,
uint64_t* file_size, IODebugContext* dbg) override;
IOStatus Truncate(const std::string& fname, size_t size,
const IOOptions& options, IODebugContext* dbg) override;
private:
std::shared_ptr<IOTracer> io_tracer_;
SystemClock* clock_;
};
// The FileSystemPtr is a wrapper class that takes pointer to storage systems
// (such as posix filesystems). It overloads operator -> and returns a pointer
// of either FileSystem or FileSystemTracingWrapper based on whether tracing is
// enabled or not. It is added to bypass FileSystemTracingWrapper when tracing
// is disabled.
class FileSystemPtr {
public:
FileSystemPtr(std::shared_ptr<FileSystem> fs,
const std::shared_ptr<IOTracer>& io_tracer)
: fs_(fs), io_tracer_(io_tracer) {
fs_tracer_ = std::make_shared<FileSystemTracingWrapper>(fs_, io_tracer_);
}
std::shared_ptr<FileSystem> operator->() const {
if (io_tracer_ && io_tracer_->is_tracing_enabled()) {
return fs_tracer_;
} else {
return fs_;
}
}
/* Returns the underlying File System pointer */
FileSystem* get() const {
if (io_tracer_ && io_tracer_->is_tracing_enabled()) {
return fs_tracer_.get();
} else {
return fs_.get();
}
}
private:
std::shared_ptr<FileSystem> fs_;
std::shared_ptr<IOTracer> io_tracer_;
std::shared_ptr<FileSystemTracingWrapper> fs_tracer_;
};
// FSSequentialFileTracingWrapper is a wrapper class above FSSequentialFile that
// forwards the call to the underlying storage system. It then invokes IOTracer
// to record file operations and other contextual information in a binary format
// for tracing. It overrides methods we are interested in tracing and extends
// FSSequentialFileWrapper, which forwards all methods that are not explicitly
// overridden.
class FSSequentialFileTracingWrapper : public FSSequentialFileOwnerWrapper {
public:
FSSequentialFileTracingWrapper(std::unique_ptr<FSSequentialFile>&& t,
std::shared_ptr<IOTracer> io_tracer,
const std::string& file_name)
: FSSequentialFileOwnerWrapper(std::move(t)),
io_tracer_(io_tracer),
clock_(SystemClock::Default().get()),
file_name_(file_name) {}
~FSSequentialFileTracingWrapper() override {}
IOStatus Read(size_t n, const IOOptions& options, Slice* result,
char* scratch, IODebugContext* dbg) override;
IOStatus InvalidateCache(size_t offset, size_t length) override;
IOStatus PositionedRead(uint64_t offset, size_t n, const IOOptions& options,
Slice* result, char* scratch,
IODebugContext* dbg) override;
private:
std::shared_ptr<IOTracer> io_tracer_;
SystemClock* clock_;
std::string file_name_;
};
// The FSSequentialFilePtr is a wrapper class that takes pointer to storage
// systems (such as posix filesystems). It overloads operator -> and returns a
// pointer of either FSSequentialFile or FSSequentialFileTracingWrapper based on
// whether tracing is enabled or not. It is added to bypass
// FSSequentialFileTracingWrapper when tracing is disabled.
class FSSequentialFilePtr {
public:
FSSequentialFilePtr() = delete;
FSSequentialFilePtr(std::unique_ptr<FSSequentialFile>&& fs,
const std::shared_ptr<IOTracer>& io_tracer,
const std::string& file_name)
: io_tracer_(io_tracer),
fs_tracer_(std::move(fs), io_tracer_,
file_name.substr(file_name.find_last_of("/\\") +
1) /* pass file name */) {}
FSSequentialFile* operator->() const {
if (io_tracer_ && io_tracer_->is_tracing_enabled()) {
return const_cast<FSSequentialFileTracingWrapper*>(&fs_tracer_);
} else {
return fs_tracer_.target();
}
}
FSSequentialFile* get() const {
if (io_tracer_ && io_tracer_->is_tracing_enabled()) {
return const_cast<FSSequentialFileTracingWrapper*>(&fs_tracer_);
} else {
return fs_tracer_.target();
}
}
private:
std::shared_ptr<IOTracer> io_tracer_;
FSSequentialFileTracingWrapper fs_tracer_;
};
// FSRandomAccessFileTracingWrapper is a wrapper class above FSRandomAccessFile
// that forwards the call to the underlying storage system. It then invokes
// IOTracer to record file operations and other contextual information in a
// binary format for tracing. It overrides methods we are interested in tracing
// and extends FSRandomAccessFileWrapper, which forwards all methods that are
// not explicitly overridden.
class FSRandomAccessFileTracingWrapper : public FSRandomAccessFileOwnerWrapper {
public:
FSRandomAccessFileTracingWrapper(std::unique_ptr<FSRandomAccessFile>&& t,
std::shared_ptr<IOTracer> io_tracer,
const std::string& file_name)
: FSRandomAccessFileOwnerWrapper(std::move(t)),
io_tracer_(io_tracer),
clock_(SystemClock::Default().get()),
file_name_(file_name) {}
~FSRandomAccessFileTracingWrapper() override {}
IOStatus Read(uint64_t offset, size_t n, const IOOptions& options,
Slice* result, char* scratch,
IODebugContext* dbg) const override;
IOStatus MultiRead(FSReadRequest* reqs, size_t num_reqs,
const IOOptions& options, IODebugContext* dbg) override;
IOStatus Prefetch(uint64_t offset, size_t n, const IOOptions& options,
IODebugContext* dbg) override;
IOStatus InvalidateCache(size_t offset, size_t length) override;
IOStatus ReadAsync(FSReadRequest& req, const IOOptions& opts,
std::function<void(const FSReadRequest&, void*)> cb,
void* cb_arg, void** io_handle, IOHandleDeleter* del_fn,
IODebugContext* dbg) override;
void ReadAsyncCallback(const FSReadRequest& req, void* cb_arg);
private:
std::shared_ptr<IOTracer> io_tracer_;
SystemClock* clock_;
// Stores file name instead of full path.
std::string file_name_;
struct ReadAsyncCallbackInfo {
uint64_t start_time_;
std::function<void(const FSReadRequest&, void*)> cb_;
void* cb_arg_;
std::string file_op_;
};
};
// The FSRandomAccessFilePtr is a wrapper class that takes pointer to storage
// systems (such as posix filesystems). It overloads operator -> and returns a
// pointer of either FSRandomAccessFile or FSRandomAccessFileTracingWrapper
// based on whether tracing is enabled or not. It is added to bypass
// FSRandomAccessFileTracingWrapper when tracing is disabled.
class FSRandomAccessFilePtr {
public:
FSRandomAccessFilePtr(std::unique_ptr<FSRandomAccessFile>&& fs,
const std::shared_ptr<IOTracer>& io_tracer,
const std::string& file_name)
: io_tracer_(io_tracer),
fs_tracer_(std::move(fs), io_tracer_,
file_name.substr(file_name.find_last_of("/\\") +
1) /* pass file name */) {}
FSRandomAccessFile* operator->() const {
if (io_tracer_ && io_tracer_->is_tracing_enabled()) {
return const_cast<FSRandomAccessFileTracingWrapper*>(&fs_tracer_);
} else {
return fs_tracer_.target();
}
}
FSRandomAccessFile* get() const {
if (io_tracer_ && io_tracer_->is_tracing_enabled()) {
return const_cast<FSRandomAccessFileTracingWrapper*>(&fs_tracer_);
} else {
return fs_tracer_.target();
}
}
private:
std::shared_ptr<IOTracer> io_tracer_;
FSRandomAccessFileTracingWrapper fs_tracer_;
};
// FSWritableFileTracingWrapper is a wrapper class above FSWritableFile that
// forwards the call to the underlying storage system. It then invokes IOTracer
// to record file operations and other contextual information in a binary format
// for tracing. It overrides methods we are interested in tracing and extends
// FSWritableFileWrapper, which forwards all methods that are not explicitly
// overridden.
class FSWritableFileTracingWrapper : public FSWritableFileOwnerWrapper {
public:
FSWritableFileTracingWrapper(std::unique_ptr<FSWritableFile>&& t,
std::shared_ptr<IOTracer> io_tracer,
const std::string& file_name)
: FSWritableFileOwnerWrapper(std::move(t)),
io_tracer_(io_tracer),
clock_(SystemClock::Default().get()),
file_name_(file_name) {}
~FSWritableFileTracingWrapper() override {}
IOStatus Append(const Slice& data, const IOOptions& options,
IODebugContext* dbg) override;
IOStatus Append(const Slice& data, const IOOptions& options,
const DataVerificationInfo& /*verification_info*/,
IODebugContext* dbg) override {
return Append(data, options, dbg);
}
IOStatus PositionedAppend(const Slice& data, uint64_t offset,
const IOOptions& options,
IODebugContext* dbg) override;
IOStatus PositionedAppend(const Slice& data, uint64_t offset,
const IOOptions& options,
const DataVerificationInfo& /*verification_info*/,
IODebugContext* dbg) override {
return PositionedAppend(data, offset, options, dbg);
}
IOStatus Truncate(uint64_t size, const IOOptions& options,
IODebugContext* dbg) override;
IOStatus Close(const IOOptions& options, IODebugContext* dbg) override;
uint64_t GetFileSize(const IOOptions& options, IODebugContext* dbg) override;
IOStatus InvalidateCache(size_t offset, size_t length) override;
private:
std::shared_ptr<IOTracer> io_tracer_;
SystemClock* clock_;
// Stores file name instead of full path.
std::string file_name_;
};
// The FSWritableFilePtr is a wrapper class that takes pointer to storage
// systems (such as posix filesystems). It overloads operator -> and returns a
// pointer of either FSWritableFile or FSWritableFileTracingWrapper based on
// whether tracing is enabled or not. It is added to bypass
// FSWritableFileTracingWrapper when tracing is disabled.
class FSWritableFilePtr {
public:
FSWritableFilePtr(std::unique_ptr<FSWritableFile>&& fs,
const std::shared_ptr<IOTracer>& io_tracer,
const std::string& file_name)
: io_tracer_(io_tracer) {
fs_tracer_.reset(new FSWritableFileTracingWrapper(
std::move(fs), io_tracer_,
file_name.substr(file_name.find_last_of("/\\") +
1) /* pass file name */));
}
FSWritableFile* operator->() const {
if (io_tracer_ && io_tracer_->is_tracing_enabled()) {
return fs_tracer_.get();
} else {
return fs_tracer_->target();
}
}
FSWritableFile* get() const {
if (io_tracer_ && io_tracer_->is_tracing_enabled()) {
return fs_tracer_.get();
} else if (fs_tracer_) {
return fs_tracer_->target();
} else {
return nullptr;
}
}
void reset() {
fs_tracer_.reset();
io_tracer_ = nullptr;
}
private:
std::shared_ptr<IOTracer> io_tracer_;
std::unique_ptr<FSWritableFileTracingWrapper> fs_tracer_;
};
// FSRandomRWFileTracingWrapper is a wrapper class above FSRandomRWFile that
// forwards the call to the underlying storage system. It then invokes IOTracer
// to record file operations and other contextual information in a binary format
// for tracing. It overrides methods we are interested in tracing and extends
// FSRandomRWFileWrapper, which forwards all methods that are not explicitly
// overridden.
class FSRandomRWFileTracingWrapper : public FSRandomRWFileOwnerWrapper {
public:
FSRandomRWFileTracingWrapper(std::unique_ptr<FSRandomRWFile>&& t,
std::shared_ptr<IOTracer> io_tracer,
const std::string& file_name)
: FSRandomRWFileOwnerWrapper(std::move(t)),
io_tracer_(io_tracer),
clock_(SystemClock::Default().get()),
file_name_(file_name) {}
~FSRandomRWFileTracingWrapper() override {}
IOStatus Write(uint64_t offset, const Slice& data, const IOOptions& options,
IODebugContext* dbg) override;
IOStatus Read(uint64_t offset, size_t n, const IOOptions& options,
Slice* result, char* scratch,
IODebugContext* dbg) const override;
IOStatus Flush(const IOOptions& options, IODebugContext* dbg) override;
IOStatus Close(const IOOptions& options, IODebugContext* dbg) override;
IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override;
IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override;
private:
std::shared_ptr<IOTracer> io_tracer_;
SystemClock* clock_;
// Stores file name instead of full path.
std::string file_name_;
};
// The FSRandomRWFilePtr is a wrapper class that takes pointer to storage
// systems (such as posix filesystems). It overloads operator -> and returns a
// pointer of either FSRandomRWFile or FSRandomRWFileTracingWrapper based on
// whether tracing is enabled or not. It is added to bypass
// FSRandomRWFileTracingWrapper when tracing is disabled.
class FSRandomRWFilePtr {
public:
FSRandomRWFilePtr(std::unique_ptr<FSRandomRWFile>&& fs,
std::shared_ptr<IOTracer> io_tracer,
const std::string& file_name)
: io_tracer_(io_tracer),
fs_tracer_(std::move(fs), io_tracer_,
file_name.substr(file_name.find_last_of("/\\") +
1) /* pass file name */) {}
FSRandomRWFile* operator->() const {
if (io_tracer_ && io_tracer_->is_tracing_enabled()) {
return const_cast<FSRandomRWFileTracingWrapper*>(&fs_tracer_);
} else {
return fs_tracer_.target();
}
}
FSRandomRWFile* get() const {
if (io_tracer_ && io_tracer_->is_tracing_enabled()) {
return const_cast<FSRandomRWFileTracingWrapper*>(&fs_tracer_);
} else {
return fs_tracer_.target();
}
}
private:
std::shared_ptr<IOTracer> io_tracer_;
FSRandomRWFileTracingWrapper fs_tracer_;
};
} // namespace ROCKSDB_NAMESPACE