#pragma once
#include <algorithm>
#include <deque>
#include <string>
#include <vector>
#include "env/composite_env_wrapper.h"
#include "file/writable_file_writer.h"
#include "rocksdb/compaction_filter.h"
#include "rocksdb/env.h"
#include "rocksdb/iterator.h"
#include "rocksdb/merge_operator.h"
#include "rocksdb/options.h"
#include "rocksdb/slice.h"
#include "rocksdb/table.h"
#include "table/internal_iterator.h"
#include "util/defer.h"
#include "util/mutexlock.h"
#ifdef ROCKSDB_UNITTESTS_WITH_CUSTOM_OBJECTS_FROM_STATIC_LIBS
extern "C" {
void RegisterCustomObjects(int argc, char** argv);
}
#else
void RegisterCustomObjects(int argc, char** argv);
#endif
namespace ROCKSDB_NAMESPACE {
class FileSystem;
class MemTableRepFactory;
class ObjectLibrary;
class Random;
class SequentialFile;
class SequentialFileReader;
namespace test {
extern const uint32_t kDefaultFormatVersion;
extern const std::set<uint32_t> kFooterFormatVersionsToTest;
enum RandomKeyType : char { RANDOM, LARGEST, SMALLEST, MIDDLE };
std::string RandomKey(Random* rnd, int len,
RandomKeyType type = RandomKeyType::RANDOM);
enum class UserDefinedTimestampTestMode {
kNone,
kNormal,
kStripUserDefinedTimestamp,
};
const std::vector<UserDefinedTimestampTestMode>& GetUDTTestModes();
bool IsUDTEnabled(const UserDefinedTimestampTestMode& test_mode);
bool ShouldPersistUDT(const UserDefinedTimestampTestMode& test_mode);
Slice CompressibleString(Random* rnd, double compressed_to_fraction, int len,
std::string* dst);
inline std::string CompressibleString(Random* rnd,
double compressed_to_fraction, int len) {
std::string dst;
CompressibleString(rnd, compressed_to_fraction, len, &dst);
return dst;
}
#ifndef NDEBUG
class PlainInternalKeyComparator : public InternalKeyComparator {
public:
explicit PlainInternalKeyComparator(const Comparator* c)
: InternalKeyComparator(c) {}
virtual ~PlainInternalKeyComparator() {}
int Compare(const Slice& a, const Slice& b) const override {
return user_comparator()->Compare(a, b);
}
};
#endif
class SimpleSuffixReverseComparator : public Comparator {
public:
SimpleSuffixReverseComparator() {}
static const char* kClassName() { return "SimpleSuffixReverseComparator"; }
const char* Name() const override { return kClassName(); }
int Compare(const Slice& a, const Slice& b) const override {
Slice prefix_a = Slice(a.data(), 8);
Slice prefix_b = Slice(b.data(), 8);
int prefix_comp = prefix_a.compare(prefix_b);
if (prefix_comp != 0) {
return prefix_comp;
} else {
Slice suffix_a = Slice(a.data() + 8, a.size() - 8);
Slice suffix_b = Slice(b.data() + 8, b.size() - 8);
return -(suffix_a.compare(suffix_b));
}
}
void FindShortestSeparator(std::string* ,
const Slice& ) const override {}
void FindShortSuccessor(std::string* ) const override {}
};
const Comparator* Uint64Comparator();
const Comparator* BytewiseComparatorWithU64TsWrapper();
const Comparator* ReverseBytewiseComparatorWithU64TsWrapper();
class StringSink : public FSWritableFile {
public:
std::string contents_;
explicit StringSink(Slice* reader_contents = nullptr)
: FSWritableFile(),
contents_(""),
reader_contents_(reader_contents),
last_flush_(0) {
if (reader_contents_ != nullptr) {
*reader_contents_ = Slice(contents_.data(), 0);
}
}
const std::string& contents() const { return contents_; }
IOStatus Truncate(uint64_t size, const IOOptions& ,
IODebugContext* ) override {
contents_.resize(static_cast<size_t>(size));
return IOStatus::OK();
}
IOStatus Close(const IOOptions& , IODebugContext* ) override {
return IOStatus::OK();
}
IOStatus Flush(const IOOptions& , IODebugContext* ) override {
if (reader_contents_ != nullptr) {
assert(reader_contents_->size() <= last_flush_);
size_t offset = last_flush_ - reader_contents_->size();
*reader_contents_ =
Slice(contents_.data() + offset, contents_.size() - offset);
last_flush_ = contents_.size();
}
return IOStatus::OK();
}
IOStatus Sync(const IOOptions& , IODebugContext* ) override {
return IOStatus::OK();
}
using FSWritableFile::Append;
IOStatus Append(const Slice& slice, const IOOptions& ,
IODebugContext* ) override {
contents_.append(slice.data(), slice.size());
return IOStatus::OK();
}
void Drop(size_t bytes) {
if (reader_contents_ != nullptr) {
contents_.resize(contents_.size() - bytes);
*reader_contents_ =
Slice(reader_contents_->data(), reader_contents_->size() - bytes);
last_flush_ = contents_.size();
}
}
uint64_t GetFileSize(const IOOptions& ,
IODebugContext* ) override {
return contents_.size();
}
private:
Slice* reader_contents_;
size_t last_flush_;
};
class RandomRWStringSink : public FSRandomRWFile {
public:
explicit RandomRWStringSink(StringSink* ss) : ss_(ss) {}
IOStatus Write(uint64_t offset, const Slice& data, const IOOptions& ,
IODebugContext* ) override {
if (offset + data.size() > ss_->contents_.size()) {
ss_->contents_.resize(static_cast<size_t>(offset) + data.size(), '\0');
}
char* pos = const_cast<char*>(ss_->contents_.data() + offset);
memcpy(pos, data.data(), data.size());
return IOStatus::OK();
}
IOStatus Read(uint64_t offset, size_t n, const IOOptions& ,
Slice* result, char* ,
IODebugContext* ) const override {
*result = Slice(nullptr, 0);
if (offset < ss_->contents_.size()) {
size_t str_res_sz =
std::min(static_cast<size_t>(ss_->contents_.size() - offset), n);
*result = Slice(ss_->contents_.data() + offset, str_res_sz);
}
return IOStatus::OK();
}
IOStatus Flush(const IOOptions& , IODebugContext* ) override {
return IOStatus::OK();
}
IOStatus Sync(const IOOptions& , IODebugContext* ) override {
return IOStatus::OK();
}
IOStatus Close(const IOOptions& , IODebugContext* ) override {
return IOStatus::OK();
}
const std::string& contents() const { return ss_->contents(); }
private:
StringSink* ss_;
};
class OverwritingStringSink : public FSWritableFile {
public:
explicit OverwritingStringSink(Slice* reader_contents)
: FSWritableFile(),
contents_(""),
reader_contents_(reader_contents),
last_flush_(0) {}
const std::string& contents() const { return contents_; }
IOStatus Truncate(uint64_t size, const IOOptions& ,
IODebugContext* ) override {
contents_.resize(static_cast<size_t>(size));
return IOStatus::OK();
}
IOStatus Close(const IOOptions& , IODebugContext* ) override {
return IOStatus::OK();
}
IOStatus Flush(const IOOptions& , IODebugContext* ) override {
if (last_flush_ < contents_.size()) {
assert(reader_contents_->size() >= contents_.size());
memcpy((char*)reader_contents_->data() + last_flush_,
contents_.data() + last_flush_, contents_.size() - last_flush_);
last_flush_ = contents_.size();
}
return IOStatus::OK();
}
IOStatus Sync(const IOOptions& , IODebugContext* ) override {
return IOStatus::OK();
}
using FSWritableFile::Append;
IOStatus Append(const Slice& slice, const IOOptions& ,
IODebugContext* ) override {
contents_.append(slice.data(), slice.size());
return IOStatus::OK();
}
void Drop(size_t bytes) {
contents_.resize(contents_.size() - bytes);
if (last_flush_ > contents_.size()) last_flush_ = contents_.size();
}
uint64_t GetFileSize(const IOOptions& ,
IODebugContext* ) override {
return contents_.size();
}
private:
std::string contents_;
Slice* reader_contents_;
size_t last_flush_;
};
class StringSource : public FSRandomAccessFile {
public:
explicit StringSource(const Slice& contents, uint64_t uniq_id = 0,
bool mmap = false)
: contents_(contents.data(), contents.size()),
uniq_id_(uniq_id),
mmap_(mmap),
total_reads_(0) {}
virtual ~StringSource() {}
uint64_t Size() const { return contents_.size(); }
IOStatus Prefetch(uint64_t , size_t ,
const IOOptions& ,
IODebugContext* ) override {
if (mmap_) {
return IOStatus::OK();
} else {
return IOStatus::NotSupported("Prefetch not supported");
}
}
IOStatus Read(uint64_t offset, size_t n, const IOOptions& ,
Slice* result, char* scratch,
IODebugContext* ) const override {
total_reads_++;
if (offset > contents_.size()) {
return IOStatus::InvalidArgument("invalid Read offset");
}
if (offset + n > contents_.size()) {
n = contents_.size() - static_cast<size_t>(offset);
}
if (!mmap_) {
memcpy(scratch, &contents_[static_cast<size_t>(offset)], n);
*result = Slice(scratch, n);
} else {
*result = Slice(&contents_[static_cast<size_t>(offset)], n);
}
return IOStatus::OK();
}
size_t GetUniqueId(char* id, size_t max_size) const override {
if (max_size < 20) {
return 0;
}
char* rid = id;
rid = EncodeVarint64(rid, uniq_id_);
rid = EncodeVarint64(rid, 0);
return static_cast<size_t>(rid - id);
}
int total_reads() const { return total_reads_; }
void set_total_reads(int tr) { total_reads_ = tr; }
IOStatus GetFileSize(uint64_t* file_size) override {
*file_size = contents_.size();
return IOStatus::OK();
}
private:
std::string contents_;
uint64_t uniq_id_;
bool mmap_;
mutable int total_reads_;
};
class NullLogger : public Logger {
public:
using Logger::Logv;
void Logv(const char* , va_list ) override {}
size_t GetLogFileSize() const override { return 0; }
};
void CorruptKeyType(InternalKey* ikey);
std::string KeyStr(const std::string& user_key, const SequenceNumber& seq,
const ValueType& t, bool corrupt = false);
std::string KeyStr(uint64_t ts, const std::string& user_key,
const SequenceNumber& seq, const ValueType& t,
bool corrupt = false);
class SleepingBackgroundTask {
public:
SleepingBackgroundTask()
: bg_cv_(&mutex_),
should_sleep_(true),
done_with_sleep_(false),
sleeping_(false) {}
~SleepingBackgroundTask() {
MutexLock l(&mutex_);
should_sleep_ = false;
while (sleeping_) {
assert(!should_sleep_);
bg_cv_.SignalAll();
bg_cv_.Wait();
}
}
bool IsSleeping() {
MutexLock l(&mutex_);
return sleeping_;
}
void DoSleep() {
MutexLock l(&mutex_);
sleeping_ = true;
bg_cv_.SignalAll();
while (should_sleep_) {
bg_cv_.Wait();
}
sleeping_ = false;
done_with_sleep_ = true;
bg_cv_.SignalAll();
}
void WaitUntilSleeping() {
MutexLock l(&mutex_);
while (!sleeping_ || !should_sleep_) {
bg_cv_.Wait();
}
}
bool TimedWaitUntilSleeping(uint64_t wait_time);
void WakeUp() {
MutexLock l(&mutex_);
should_sleep_ = false;
bg_cv_.SignalAll();
}
void WaitUntilDone() {
MutexLock l(&mutex_);
while (!done_with_sleep_) {
bg_cv_.Wait();
}
}
bool TimedWaitUntilDone(uint64_t wait_time);
bool WokenUp() {
MutexLock l(&mutex_);
return should_sleep_ == false;
}
void Reset() {
MutexLock l(&mutex_);
should_sleep_ = true;
done_with_sleep_ = false;
}
static void DoSleepTask(void* arg) {
static_cast<SleepingBackgroundTask*>(arg)->DoSleep();
}
private:
port::Mutex mutex_;
port::CondVar bg_cv_; bool should_sleep_;
bool done_with_sleep_;
bool sleeping_;
};
class FilterNumber : public CompactionFilter {
public:
explicit FilterNumber(uint64_t num) : num_(num) {}
std::string last_merge_operand_key() { return last_merge_operand_key_; }
bool Filter(int , const ROCKSDB_NAMESPACE::Slice& ,
const ROCKSDB_NAMESPACE::Slice& value, std::string* ,
bool* ) const override {
if (value.size() == sizeof(uint64_t)) {
return num_ == DecodeFixed64(value.data());
}
return true;
}
bool FilterMergeOperand(
int , const ROCKSDB_NAMESPACE::Slice& key,
const ROCKSDB_NAMESPACE::Slice& value) const override {
last_merge_operand_key_ = key.ToString();
if (value.size() == sizeof(uint64_t)) {
return num_ == DecodeFixed64(value.data());
}
return true;
}
const char* Name() const override { return "FilterBadMergeOperand"; }
private:
mutable std::string last_merge_operand_key_;
uint64_t num_;
};
inline std::string EncodeInt(uint64_t x) {
std::string result;
PutFixed64(&result, x);
return result;
}
class SeqStringSource : public FSSequentialFile {
public:
SeqStringSource(const std::string& data, std::atomic<int>* read_count)
: data_(data), offset_(0), read_count_(read_count) {}
~SeqStringSource() override {}
IOStatus Read(size_t n, const IOOptions& , Slice* result,
char* scratch, IODebugContext* ) override {
std::string output;
if (offset_ < data_.size()) {
n = std::min(data_.size() - offset_, n);
memcpy(scratch, data_.data() + offset_, n);
offset_ += n;
*result = Slice(scratch, n);
} else {
return IOStatus::InvalidArgument(
"Attempt to read when it already reached eof.");
}
(*read_count_)++;
return IOStatus::OK();
}
IOStatus Skip(uint64_t n) override {
if (offset_ >= data_.size()) {
return IOStatus::InvalidArgument(
"Attempt to read when it already reached eof.");
}
offset_ += static_cast<size_t>(n);
return IOStatus::OK();
}
private:
std::string data_;
size_t offset_;
std::atomic<int>* read_count_;
};
class StringFS : public FileSystemWrapper {
public:
class StringSink : public FSWritableFile {
public:
explicit StringSink(std::string* contents)
: FSWritableFile(), contents_(contents) {}
IOStatus Truncate(uint64_t size, const IOOptions& ,
IODebugContext* ) override {
contents_->resize(static_cast<size_t>(size));
return IOStatus::OK();
}
IOStatus Close(const IOOptions& ,
IODebugContext* ) override {
return IOStatus::OK();
}
IOStatus Flush(const IOOptions& ,
IODebugContext* ) override {
return IOStatus::OK();
}
IOStatus Sync(const IOOptions& , IODebugContext* ) override {
return IOStatus::OK();
}
using FSWritableFile::Append;
IOStatus Append(const Slice& slice, const IOOptions& ,
IODebugContext* ) override {
contents_->append(slice.data(), slice.size());
return IOStatus::OK();
}
uint64_t GetFileSize(const IOOptions& ,
IODebugContext* ) override {
if (contents_ != nullptr) {
return contents_->size();
}
return 0;
}
private:
std::string* contents_;
};
explicit StringFS(const std::shared_ptr<FileSystem>& t)
: FileSystemWrapper(t) {}
~StringFS() override {}
static const char* kClassName() { return "StringFS"; }
const char* Name() const override { return kClassName(); }
const std::string& GetContent(const std::string& f) { return files_[f]; }
const IOStatus WriteToNewFile(const std::string& file_name,
const std::string& content) {
std::unique_ptr<FSWritableFile> r;
FileOptions file_opts;
IOOptions io_opts;
auto s = NewWritableFile(file_name, file_opts, &r, nullptr);
if (s.ok()) {
s = r->Append(content, io_opts, nullptr);
}
if (s.ok()) {
s = r->Flush(io_opts, nullptr);
}
if (s.ok()) {
s = r->Close(io_opts, nullptr);
}
assert(!s.ok() || files_[file_name] == content);
return s;
}
IOStatus NewSequentialFile(const std::string& f,
const FileOptions& ,
std::unique_ptr<FSSequentialFile>* r,
IODebugContext* ) override {
auto iter = files_.find(f);
if (iter == files_.end()) {
return IOStatus::NotFound("The specified file does not exist", f);
}
r->reset(new SeqStringSource(iter->second, &num_seq_file_read_));
return IOStatus::OK();
}
IOStatus NewRandomAccessFile(const std::string& ,
const FileOptions& ,
std::unique_ptr<FSRandomAccessFile>* ,
IODebugContext* ) override {
return IOStatus::NotSupported();
}
IOStatus NewWritableFile(const std::string& f, const FileOptions& ,
std::unique_ptr<FSWritableFile>* r,
IODebugContext* ) override {
auto iter = files_.find(f);
if (iter != files_.end()) {
return IOStatus::IOError("The specified file already exists", f);
}
r->reset(new StringSink(&files_[f]));
return IOStatus::OK();
}
IOStatus NewDirectory(const std::string& ,
const IOOptions& ,
std::unique_ptr<FSDirectory>* ,
IODebugContext* ) override {
return IOStatus::NotSupported();
}
IOStatus FileExists(const std::string& f, const IOOptions& ,
IODebugContext* ) override {
if (files_.find(f) == files_.end()) {
return IOStatus::NotFound();
}
return IOStatus::OK();
}
IOStatus GetChildren(const std::string& , const IOOptions& ,
std::vector<std::string>* ,
IODebugContext* ) override {
return IOStatus::NotSupported();
}
IOStatus DeleteFile(const std::string& f, const IOOptions& ,
IODebugContext* ) override {
files_.erase(f);
return IOStatus::OK();
}
IOStatus CreateDir(const std::string& , const IOOptions& ,
IODebugContext* ) override {
return IOStatus::NotSupported();
}
IOStatus CreateDirIfMissing(const std::string& ,
const IOOptions& ,
IODebugContext* ) override {
return IOStatus::NotSupported();
}
IOStatus DeleteDir(const std::string& , const IOOptions& ,
IODebugContext* ) override {
return IOStatus::NotSupported();
}
IOStatus GetFileSize(const std::string& f, const IOOptions& ,
uint64_t* s, IODebugContext* ) override {
auto iter = files_.find(f);
if (iter == files_.end()) {
return IOStatus::NotFound("The specified file does not exist:", f);
}
*s = iter->second.size();
return IOStatus::OK();
}
IOStatus GetFileModificationTime(const std::string& ,
const IOOptions& ,
uint64_t* ,
IODebugContext* ) override {
return IOStatus::NotSupported();
}
IOStatus RenameFile(const std::string& , const std::string& ,
const IOOptions& ,
IODebugContext* ) override {
return IOStatus::NotSupported();
}
IOStatus LinkFile(const std::string& , const std::string& ,
const IOOptions& ,
IODebugContext* ) override {
return IOStatus::NotSupported();
}
IOStatus LockFile(const std::string& , const IOOptions& ,
FileLock** , IODebugContext* ) override {
return IOStatus::NotSupported();
}
IOStatus UnlockFile(FileLock* , const IOOptions& ,
IODebugContext* ) override {
return IOStatus::NotSupported();
}
std::atomic<int> num_seq_file_read_;
protected:
std::unordered_map<std::string, std::string> files_;
};
template <CompressionType kCompression>
struct CompressorCustomAlg : public CompressorWrapper {
static bool Supported() { return LZ4_Supported(); }
explicit CompressorCustomAlg(
std::unique_ptr<Compressor> wrapped =
GetBuiltinV2CompressionManager()->GetCompressor({}, kLZ4Compression))
: CompressorWrapper(std::move(wrapped)),
dictionary_hash_(GetSliceHash(wrapped_->GetSerializedDict())) {
static_assert(kCompression > kLastBuiltinCompression);
}
const char* Name() const override { return "CompressorCustomAlg"; }
CompressionType GetPreferredCompressionType() const override {
return kCompression;
}
std::unique_ptr<Compressor> Clone() const override {
return std::make_unique<CompressorCustomAlg>(wrapped_->Clone());
}
Status CompressBlock(Slice uncompressed_data, char* compressed_output,
size_t* compressed_output_size,
CompressionType* out_compression_type,
ManagedWorkingArea* working_area) override {
size_t allowed_output_size = *compressed_output_size;
Status s = wrapped_->CompressBlock(uncompressed_data, compressed_output,
compressed_output_size,
out_compression_type, working_area);
if (s.ok() && *out_compression_type != kNoCompression) {
assert(*out_compression_type == kLZ4Compression);
if (*compressed_output_size + 5 > allowed_output_size) {
*out_compression_type = kNoCompression;
return Status::OK();
}
std::memmove(compressed_output + 5, compressed_output,
*compressed_output_size);
compressed_output[0] = lossless_cast<char>(kCompression);
EncodeFixed32(&compressed_output[1], dictionary_hash_);
*compressed_output_size += 5;
*out_compression_type = kCompression;
}
return s;
}
std::unique_ptr<Compressor> MaybeCloneSpecialized(
CacheEntryRole block_type, DictConfigArgs&& dict_config) const override {
auto clone =
wrapped_->CloneMaybeSpecialized(block_type, std::move(dict_config));
return std::make_unique<CompressorCustomAlg>(std::move(clone));
}
protected:
uint32_t dictionary_hash_;
};
struct DecompressorCustomAlg : public DecompressorWrapper {
using TypeSet = SmallEnumSet<CompressionType, kDisableCompressionOption>;
DecompressorCustomAlg(std::shared_ptr<Decompressor> wrapped =
GetBuiltinV2CompressionManager()->GetDecompressor())
: DecompressorWrapper(std::move(wrapped)),
dictionary_hash_(GetSliceHash(wrapped_->GetSerializedDict())),
allowed_types_(TypeSet::All()) {}
const char* Name() const override { return "DecompressorCustomAlg"; }
Status MaybeCloneForDict(const Slice& serialized_dict,
std::unique_ptr<Decompressor>* out) override {
Status s = wrapped_->MaybeCloneForDict(serialized_dict, out);
if (s.ok()) {
assert(*out != nullptr);
auto clone = std::make_unique<DecompressorCustomAlg>(std::move(*out));
clone->SetAllowedTypes(allowed_types_);
*out = std::move(clone);
assert(out->get()->GetSerializedDict() == serialized_dict);
} else {
assert(*out == nullptr);
}
return s;
}
Status ExtractUncompressedSize(Args& args) override {
if (args.compression_type >= kFirstCustomCompression &&
args.compression_type <= kLastCustomCompression) {
assert(args.compressed_data.size() > 0);
assert(args.compressed_data[0] ==
lossless_cast<char>(args.compression_type));
assert(DecodeFixed32(args.compressed_data.data() + 1) ==
dictionary_hash_);
args.compressed_data.remove_prefix(5);
SaveAndRestore<CompressionType> save_compression_type(
&args.compression_type, kLZ4Compression);
return wrapped_->ExtractUncompressedSize(args);
} else {
return wrapped_->ExtractUncompressedSize(args);
}
}
Status DecompressBlock(const Args& args, char* uncompressed_output) override {
if (args.compression_type >= kFirstCustomCompression &&
args.compression_type <= kLastCustomCompression) {
Args modified_args = args;
modified_args.compression_type = kLZ4Compression;
return wrapped_->DecompressBlock(modified_args, uncompressed_output);
} else {
return wrapped_->DecompressBlock(args, uncompressed_output);
}
}
void SetAllowedTypes(const CompressionType* types_begin,
const CompressionType* types_end) {
TypeSet allowed_types;
for (auto type = types_begin; type != types_end; ++type) {
allowed_types.Add(*type);
}
allowed_types_ = std::move(allowed_types);
}
void SetAllowedTypes(TypeSet allowed_types) {
allowed_types_ = std::move(allowed_types);
}
protected:
uint32_t dictionary_hash_;
SmallEnumSet<CompressionType, kDisableCompressionOption> allowed_types_;
};
void RandomInitDBOptions(DBOptions* db_opt, Random* rnd);
void RandomInitCFOptions(ColumnFamilyOptions* cf_opt, DBOptions&, Random* rnd);
class ChanglingMergeOperator : public MergeOperator {
public:
explicit ChanglingMergeOperator(const std::string& name)
: name_(name + "MergeOperator") {}
~ChanglingMergeOperator() {}
void SetName(const std::string& name) { name_ = name; }
bool FullMergeV2(const MergeOperationInput& ,
MergeOperationOutput* ) const override {
return false;
}
bool PartialMergeMulti(const Slice& ,
const std::deque<Slice>& ,
std::string* ,
Logger* ) const override {
return false;
}
static const char* kClassName() { return "ChanglingMergeOperator"; }
const char* NickName() const override { return kNickName(); }
static const char* kNickName() { return "Changling"; }
bool IsInstanceOf(const std::string& id) const override {
if (id == kClassName()) {
return true;
} else {
return MergeOperator::IsInstanceOf(id);
}
}
const char* Name() const override { return name_.c_str(); }
protected:
std::string name_;
};
MergeOperator* RandomMergeOperator(Random* rnd);
class ChanglingCompactionFilter : public CompactionFilter {
public:
explicit ChanglingCompactionFilter(const std::string& name)
: name_(name + "CompactionFilter") {}
~ChanglingCompactionFilter() {}
void SetName(const std::string& name) { name_ = name; }
bool Filter(int , const Slice& ,
const Slice& , std::string* ,
bool* ) const override {
return false;
}
static const char* kClassName() { return "ChanglingCompactionFilter"; }
const char* NickName() const override { return kNickName(); }
static const char* kNickName() { return "Changling"; }
bool IsInstanceOf(const std::string& id) const override {
if (id == kClassName()) {
return true;
} else {
return CompactionFilter::IsInstanceOf(id);
}
}
const char* Name() const override { return name_.c_str(); }
private:
std::string name_;
};
CompactionFilter* RandomCompactionFilter(Random* rnd);
class ChanglingCompactionFilterFactory : public CompactionFilterFactory {
public:
explicit ChanglingCompactionFilterFactory(const std::string& name)
: name_(name + "CompactionFilterFactory") {}
~ChanglingCompactionFilterFactory() {}
void SetName(const std::string& name) { name_ = name; }
std::unique_ptr<CompactionFilter> CreateCompactionFilter(
const CompactionFilter::Context& ) override {
return std::unique_ptr<CompactionFilter>();
}
const char* Name() const override { return name_.c_str(); }
static const char* kClassName() { return "ChanglingCompactionFilterFactory"; }
const char* NickName() const override { return kNickName(); }
static const char* kNickName() { return "Changling"; }
bool IsInstanceOf(const std::string& id) const override {
if (id == kClassName()) {
return true;
} else {
return CompactionFilterFactory::IsInstanceOf(id);
}
}
protected:
std::string name_;
};
MemTableRepFactory* NewSpecialSkipListFactory(int num_entries_per_flush);
CompressionType RandomCompressionType(Random* rnd);
void RandomCompressionTypeVector(const size_t count,
std::vector<CompressionType>* types,
Random* rnd);
CompactionFilterFactory* RandomCompactionFilterFactory(Random* rnd);
const SliceTransform* RandomSliceTransform(Random* rnd, int pre_defined = -1);
TableFactory* RandomTableFactory(Random* rnd, int pre_defined = -1);
std::string RandomName(Random* rnd, const size_t len);
bool IsDirectIOSupported(Env* env, const std::string& dir);
bool IsPrefetchSupported(const std::shared_ptr<FileSystem>& fs,
const std::string& dir);
size_t GetLinesCount(const std::string& fname, const std::string& pattern);
Status CorruptFile(Env* env, const std::string& fname, int offset,
int bytes_to_corrupt, bool verify_checksum = true);
Status TruncateFile(Env* env, const std::string& fname, uint64_t length);
Status TryDeleteDir(Env* env, const std::string& dirname);
void DeleteDir(Env* env, const std::string& dirname);
FileType GetFileType(const std::string& path);
uint64_t GetFileNumber(const std::string& path);
Status CreateEnvFromSystem(const ConfigOptions& options, Env** result,
std::shared_ptr<Env>* guard);
int RegisterTestObjects(ObjectLibrary& library, const std::string& );
void RegisterTestLibrary(const std::string& arg = "");
struct ReadOptionsNoIo : public ReadOptions {
ReadOptionsNoIo() { read_tier = ReadTier::kBlockCacheTier; }
};
extern const ReadOptionsNoIo kReadOptionsNoIo;
extern const std::string kUnitTestDbId;
} }