|
|
|
// Copyright (c) Facebook, Inc. and its affiliates. 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
|
|
|
|
|
|
|
|
#ifndef ROCKSDB_LITE
|
|
|
|
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
#include "rocksdb/file_system.h"
|
|
|
|
|
|
|
|
namespace ROCKSDB_NAMESPACE {
|
|
|
|
|
|
|
|
// A FileSystem simulates hybrid file system by ingesting latency and limit
|
|
|
|
// IOPs.
|
|
|
|
// This class is only used for development purpose and should not be used
|
|
|
|
// in production.
|
|
|
|
// Right now we ingest 15ms latency and allow 100 requests per second when
|
|
|
|
// the file is for warm temperature.
|
|
|
|
// When the object is destroyed, the list of warm files are written to a
|
|
|
|
// file, which can be used to reopen a FileSystem and still recover the
|
|
|
|
// list. This is to allow the information to preserve between db_bench
|
|
|
|
// runs.
|
|
|
|
class SimulatedHybridFileSystem : public FileSystemWrapper {
|
|
|
|
public:
|
|
|
|
// metadata_file_name stores metadata of the files, so that it can be
|
|
|
|
// loaded after process restarts. If the file doesn't exist, create
|
|
|
|
// one. The file is written when the class is destroyed.
|
|
|
|
// throughput_multiplier: multiplier of throughput. For example, 1 is to
|
|
|
|
// simulate single disk spindle. 4 is to simualte 4 disk spindles.
|
|
|
|
// is_full_fs_warm: if true, all files are all included in slow I/O
|
|
|
|
// simulation.
|
|
|
|
SimulatedHybridFileSystem(const std::shared_ptr<FileSystem>& base,
|
|
|
|
const std::string& metadata_file_name,
|
|
|
|
int throughput_multiplier, bool is_full_fs_warm);
|
|
|
|
|
|
|
|
~SimulatedHybridFileSystem() override;
|
|
|
|
|
|
|
|
public:
|
|
|
|
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 DeleteFile(const std::string& fname, const IOOptions& options,
|
|
|
|
IODebugContext* dbg) override;
|
|
|
|
|
|
|
|
const char* Name() const override { return name_.c_str(); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
// Limit 100 requests per second. Rate limiter is designed to byte but
|
|
|
|
// we use it as fixed bytes is one request.
|
|
|
|
std::shared_ptr<RateLimiter> rate_limiter_;
|
|
|
|
std::mutex mutex_;
|
|
|
|
std::unordered_set<std::string> warm_file_set_;
|
|
|
|
std::string metadata_file_name_;
|
|
|
|
std::string name_;
|
|
|
|
bool is_full_fs_warm_;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Simulated random access file that can control IOPs and latency to simulate
|
|
|
|
// specific storage media
|
|
|
|
class SimulatedHybridRaf : public FSRandomAccessFileOwnerWrapper {
|
|
|
|
public:
|
|
|
|
SimulatedHybridRaf(std::unique_ptr<FSRandomAccessFile>&& t,
|
|
|
|
std::shared_ptr<RateLimiter> rate_limiter,
|
|
|
|
Temperature temperature)
|
|
|
|
: FSRandomAccessFileOwnerWrapper(std::move(t)),
|
|
|
|
rate_limiter_(rate_limiter),
|
|
|
|
temperature_(temperature) {}
|
|
|
|
|
|
|
|
~SimulatedHybridRaf() 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;
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::shared_ptr<RateLimiter> rate_limiter_;
|
|
|
|
Temperature temperature_;
|
|
|
|
|
|
|
|
void SimulateIOWait(int64_t num_requests) const;
|
|
|
|
};
|
|
|
|
|
|
|
|
class SimulatedWritableFile : public FSWritableFileWrapper {
|
|
|
|
public:
|
|
|
|
SimulatedWritableFile(std::unique_ptr<FSWritableFile>&& t,
|
|
|
|
std::shared_ptr<RateLimiter> rate_limiter)
|
|
|
|
: FSWritableFileWrapper(t.get()),
|
|
|
|
file_guard_(std::move(t)),
|
|
|
|
rate_limiter_(rate_limiter) {}
|
|
|
|
IOStatus Append(const Slice& data, const IOOptions&,
|
|
|
|
IODebugContext*) override;
|
|
|
|
IOStatus Append(const Slice& data, const IOOptions& options,
|
|
|
|
const DataVerificationInfo& verification_info,
|
|
|
|
IODebugContext* dbg) override;
|
|
|
|
IOStatus Sync(const IOOptions& options, IODebugContext* dbg) override;
|
|
|
|
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;
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::unique_ptr<FSWritableFile> file_guard_;
|
|
|
|
std::shared_ptr<RateLimiter> rate_limiter_;
|
|
|
|
size_t unsynced_bytes = 0;
|
|
|
|
|
|
|
|
void SimulateIOWait(int64_t num_requests) const;
|
|
|
|
};
|
|
|
|
} // namespace ROCKSDB_NAMESPACE
|
|
|
|
|
|
|
|
#endif // ROCKSDB_LITE
|