// Copyright (c) 2011-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). #include "utilities/counted_fs.h" #include #include "rocksdb/file_system.h" #include "rocksdb/utilities/options_type.h" namespace ROCKSDB_NAMESPACE { namespace { class CountedSequentialFile : public FSSequentialFileOwnerWrapper { private: CountedFileSystem* fs_; public: CountedSequentialFile(std::unique_ptr&& f, CountedFileSystem* fs) : FSSequentialFileOwnerWrapper(std::move(f)), fs_(fs) {} ~CountedSequentialFile() override { fs_->counters()->closes++; } IOStatus Read(size_t n, const IOOptions& options, Slice* result, char* scratch, IODebugContext* dbg) override { IOStatus rv = target()->Read(n, options, result, scratch, dbg); fs_->counters()->reads.RecordOp(rv, result->size()); return rv; } IOStatus PositionedRead(uint64_t offset, size_t n, const IOOptions& options, Slice* result, char* scratch, IODebugContext* dbg) override { IOStatus rv = target()->PositionedRead(offset, n, options, result, scratch, dbg); fs_->counters()->reads.RecordOp(rv, result->size()); return rv; } }; class CountedRandomAccessFile : public FSRandomAccessFileOwnerWrapper { private: CountedFileSystem* fs_; public: CountedRandomAccessFile(std::unique_ptr&& f, CountedFileSystem* fs) : FSRandomAccessFileOwnerWrapper(std::move(f)), fs_(fs) {} ~CountedRandomAccessFile() override { fs_->counters()->closes++; } IOStatus Read(uint64_t offset, size_t n, const IOOptions& options, Slice* result, char* scratch, IODebugContext* dbg) const override { IOStatus rv = target()->Read(offset, n, options, result, scratch, dbg); fs_->counters()->reads.RecordOp(rv, result->size()); return rv; } IOStatus MultiRead(FSReadRequest* reqs, size_t num_reqs, const IOOptions& options, IODebugContext* dbg) override { IOStatus rv = target()->MultiRead(reqs, num_reqs, options, dbg); for (size_t r = 0; r < num_reqs; r++) { fs_->counters()->reads.RecordOp(reqs[r].status, reqs[r].result.size()); } return rv; } }; class CountedWritableFile : public FSWritableFileOwnerWrapper { private: CountedFileSystem* fs_; public: CountedWritableFile(std::unique_ptr&& f, CountedFileSystem* fs) : FSWritableFileOwnerWrapper(std::move(f)), fs_(fs) {} IOStatus Append(const Slice& data, const IOOptions& options, IODebugContext* dbg) override { IOStatus rv = target()->Append(data, options, dbg); fs_->counters()->writes.RecordOp(rv, data.size()); return rv; } IOStatus Append(const Slice& data, const IOOptions& options, const DataVerificationInfo& info, IODebugContext* dbg) override { IOStatus rv = target()->Append(data, options, info, dbg); fs_->counters()->writes.RecordOp(rv, data.size()); return rv; } IOStatus PositionedAppend(const Slice& data, uint64_t offset, const IOOptions& options, IODebugContext* dbg) override { IOStatus rv = target()->PositionedAppend(data, offset, options, dbg); fs_->counters()->writes.RecordOp(rv, data.size()); return rv; } IOStatus PositionedAppend(const Slice& data, uint64_t offset, const IOOptions& options, const DataVerificationInfo& info, IODebugContext* dbg) override { IOStatus rv = target()->PositionedAppend(data, offset, options, info, dbg); fs_->counters()->writes.RecordOp(rv, data.size()); return rv; } IOStatus Close(const IOOptions& options, IODebugContext* dbg) override { IOStatus rv = target()->Close(options, dbg); if (rv.ok()) { fs_->counters()->closes++; } return rv; } IOStatus Flush(const IOOptions& options, IODebugContext* dbg) override { IOStatus rv = target()->Flush(options, dbg); if (rv.ok()) { fs_->counters()->flushes++; } return rv; } IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override { IOStatus rv = target()->Sync(options, dbg); if (rv.ok()) { fs_->counters()->syncs++; } return rv; } IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override { IOStatus rv = target()->Fsync(options, dbg); if (rv.ok()) { fs_->counters()->fsyncs++; } return rv; } IOStatus RangeSync(uint64_t offset, uint64_t nbytes, const IOOptions& options, IODebugContext* dbg) override { IOStatus rv = target()->RangeSync(offset, nbytes, options, dbg); if (rv.ok()) { fs_->counters()->syncs++; } return rv; } }; class CountedRandomRWFile : public FSRandomRWFileOwnerWrapper { private: mutable CountedFileSystem* fs_; public: CountedRandomRWFile(std::unique_ptr&& f, CountedFileSystem* fs) : FSRandomRWFileOwnerWrapper(std::move(f)), fs_(fs) {} IOStatus Write(uint64_t offset, const Slice& data, const IOOptions& options, IODebugContext* dbg) override { IOStatus rv = target()->Write(offset, data, options, dbg); fs_->counters()->writes.RecordOp(rv, data.size()); return rv; } IOStatus Read(uint64_t offset, size_t n, const IOOptions& options, Slice* result, char* scratch, IODebugContext* dbg) const override { IOStatus rv = target()->Read(offset, n, options, result, scratch, dbg); fs_->counters()->reads.RecordOp(rv, result->size()); return rv; } IOStatus Flush(const IOOptions& options, IODebugContext* dbg) override { IOStatus rv = target()->Flush(options, dbg); if (rv.ok()) { fs_->counters()->flushes++; } return rv; } IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override { IOStatus rv = target()->Sync(options, dbg); if (rv.ok()) { fs_->counters()->syncs++; } return rv; } IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override { IOStatus rv = target()->Fsync(options, dbg); if (rv.ok()) { fs_->counters()->fsyncs++; } return rv; } IOStatus Close(const IOOptions& options, IODebugContext* dbg) override { IOStatus rv = target()->Close(options, dbg); if (rv.ok()) { fs_->counters()->closes++; } return rv; } }; class CountedDirectory : public FSDirectoryWrapper { private: mutable CountedFileSystem* fs_; bool closed_ = false; public: CountedDirectory(std::unique_ptr&& f, CountedFileSystem* fs) : FSDirectoryWrapper(std::move(f)), fs_(fs) {} IOStatus Fsync(const IOOptions& options, IODebugContext* dbg) override { IOStatus rv = FSDirectoryWrapper::Fsync(options, dbg); if (rv.ok()) { fs_->counters()->dsyncs++; } return rv; } IOStatus Close(const IOOptions& options, IODebugContext* dbg) override { IOStatus rv = FSDirectoryWrapper::Close(options, dbg); if (rv.ok()) { fs_->counters()->closes++; fs_->counters()->dir_closes++; closed_ = true; } return rv; } IOStatus FsyncWithDirOptions(const IOOptions& options, IODebugContext* dbg, const DirFsyncOptions& dir_options) override { IOStatus rv = FSDirectoryWrapper::FsyncWithDirOptions(options, dbg, dir_options); if (rv.ok()) { fs_->counters()->dsyncs++; } return rv; } ~CountedDirectory() { if (!closed_) { // TODO: fix DB+CF code to use explicit Close, not rely on destructor fs_->counters()->closes++; fs_->counters()->dir_closes++; } } }; } // anonymous namespace std::string FileOpCounters::PrintCounters() const { std::stringstream ss; ss << "Num files opened: " << opens.load(std::memory_order_relaxed) << std::endl; ss << "Num files deleted: " << deletes.load(std::memory_order_relaxed) << std::endl; ss << "Num files renamed: " << renames.load(std::memory_order_relaxed) << std::endl; ss << "Num Flush(): " << flushes.load(std::memory_order_relaxed) << std::endl; ss << "Num Sync(): " << syncs.load(std::memory_order_relaxed) << std::endl; ss << "Num Fsync(): " << fsyncs.load(std::memory_order_relaxed) << std::endl; ss << "Num Dir Fsync(): " << dsyncs.load(std::memory_order_relaxed) << std::endl; ss << "Num Close(): " << closes.load(std::memory_order_relaxed) << std::endl; ss << "Num Dir Open(): " << dir_opens.load(std::memory_order_relaxed) << std::endl; ss << "Num Dir Close(): " << dir_closes.load(std::memory_order_relaxed) << std::endl; ss << "Num Read(): " << reads.ops.load(std::memory_order_relaxed) << std::endl; ss << "Num Append(): " << writes.ops.load(std::memory_order_relaxed) << std::endl; ss << "Num bytes read: " << reads.bytes.load(std::memory_order_relaxed) << std::endl; ss << "Num bytes written: " << writes.bytes.load(std::memory_order_relaxed) << std::endl; return ss.str(); } CountedFileSystem::CountedFileSystem(const std::shared_ptr& base) : FileSystemWrapper(base) {} IOStatus CountedFileSystem::NewSequentialFile( const std::string& f, const FileOptions& options, std::unique_ptr* r, IODebugContext* dbg) { std::unique_ptr base; IOStatus s = target()->NewSequentialFile(f, options, &base, dbg); if (s.ok()) { counters_.opens++; r->reset(new CountedSequentialFile(std::move(base), this)); } return s; } IOStatus CountedFileSystem::NewRandomAccessFile( const std::string& f, const FileOptions& options, std::unique_ptr* r, IODebugContext* dbg) { std::unique_ptr base; IOStatus s = target()->NewRandomAccessFile(f, options, &base, dbg); if (s.ok()) { counters_.opens++; r->reset(new CountedRandomAccessFile(std::move(base), this)); } return s; } IOStatus CountedFileSystem::NewWritableFile(const std::string& f, const FileOptions& options, std::unique_ptr* r, IODebugContext* dbg) { std::unique_ptr base; IOStatus s = target()->NewWritableFile(f, options, &base, dbg); if (s.ok()) { counters_.opens++; r->reset(new CountedWritableFile(std::move(base), this)); } return s; } IOStatus CountedFileSystem::ReopenWritableFile( const std::string& fname, const FileOptions& options, std::unique_ptr* result, IODebugContext* dbg) { std::unique_ptr base; IOStatus s = target()->ReopenWritableFile(fname, options, &base, dbg); if (s.ok()) { counters_.opens++; result->reset(new CountedWritableFile(std::move(base), this)); } return s; } IOStatus CountedFileSystem::ReuseWritableFile( const std::string& fname, const std::string& old_fname, const FileOptions& options, std::unique_ptr* result, IODebugContext* dbg) { std::unique_ptr base; IOStatus s = target()->ReuseWritableFile(fname, old_fname, options, &base, dbg); if (s.ok()) { counters_.opens++; result->reset(new CountedWritableFile(std::move(base), this)); } return s; } IOStatus CountedFileSystem::NewRandomRWFile( const std::string& name, const FileOptions& options, std::unique_ptr* result, IODebugContext* dbg) { std::unique_ptr base; IOStatus s = target()->NewRandomRWFile(name, options, &base, dbg); if (s.ok()) { counters_.opens++; result->reset(new CountedRandomRWFile(std::move(base), this)); } return s; } IOStatus CountedFileSystem::NewDirectory(const std::string& name, const IOOptions& options, std::unique_ptr* result, IODebugContext* dbg) { std::unique_ptr base; IOStatus s = target()->NewDirectory(name, options, &base, dbg); if (s.ok()) { counters_.opens++; counters_.dir_opens++; result->reset(new CountedDirectory(std::move(base), this)); } return s; } } // namespace ROCKSDB_NAMESPACE