| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802 | //  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).//// Copyright (c) 2011 The LevelDB Authors. All rights reserved.// Use of this source code is governed by a BSD-style license that can be// found in the LICENSE file. See the AUTHORS file for names of contributors.#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/block_based/block_based_table_factory.h"#include "table/internal_iterator.h"#include "table/plain/plain_table_factory.h"#include "util/mutexlock.h"#include "util/random.h"namespace ROCKSDB_NAMESPACE {class SequentialFile;class SequentialFileReader;namespace test {extern const uint32_t kDefaultFormatVersion;extern const uint32_t kLatestFormatVersion;// Store in *dst a random string of length "len" and return a Slice that// references the generated data.extern Slice RandomString(Random* rnd, int len, std::string* dst);extern std::string RandomHumanReadableString(Random* rnd, int len);// Return a random key with the specified length that may contain interesting// characters (e.g. \x00, \xff, etc.).enum RandomKeyType : char { RANDOM, LARGEST, SMALLEST, MIDDLE };extern std::string RandomKey(Random* rnd, int len,                             RandomKeyType type = RandomKeyType::RANDOM);// Store in *dst a string of length "len" that will compress to// "N*compressed_fraction" bytes and return a Slice that references// the generated data.extern Slice CompressibleString(Random* rnd, double compressed_fraction,                                int len, std::string* dst);// A wrapper that allows injection of errors.class ErrorEnv : public EnvWrapper { public:  bool writable_file_error_;  int num_writable_file_errors_;  ErrorEnv() : EnvWrapper(Env::Default()),               writable_file_error_(false),               num_writable_file_errors_(0) { }  virtual Status NewWritableFile(const std::string& fname,                                 std::unique_ptr<WritableFile>* result,                                 const EnvOptions& soptions) override {    result->reset();    if (writable_file_error_) {      ++num_writable_file_errors_;      return Status::IOError(fname, "fake error");    }    return target()->NewWritableFile(fname, result, soptions);  }};#ifndef NDEBUG// An internal comparator that just forward comparing results from the// user comparator in it. Can be used to test entities that have no dependency// on internal key structure but consumes InternalKeyComparator, like// BlockBasedTable.class PlainInternalKeyComparator : public InternalKeyComparator { public:  explicit PlainInternalKeyComparator(const Comparator* c)      : InternalKeyComparator(c) {}  virtual ~PlainInternalKeyComparator() {}  virtual int Compare(const Slice& a, const Slice& b) const override {    return user_comparator()->Compare(a, b);  }};#endif// A test comparator which compare two strings in this way:// (1) first compare prefix of 8 bytes in alphabet order,// (2) if two strings share the same prefix, sort the other part of the string//     in the reverse alphabet order.// This helps simulate the case of compounded key of [entity][timestamp] and// latest timestamp first.class SimpleSuffixReverseComparator : public Comparator { public:  SimpleSuffixReverseComparator() {}  virtual const char* Name() const override {    return "SimpleSuffixReverseComparator";  }  virtual 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));    }  }  virtual void FindShortestSeparator(std::string* /*start*/,                                     const Slice& /*limit*/) const override {}  virtual void FindShortSuccessor(std::string* /*key*/) const override {}};// Returns a user key comparator that can be used for comparing two uint64_t// slices. Instead of comparing slices byte-wise, it compares all the 8 bytes// at once. Assumes same endian-ness is used though the database's lifetime.// Symantics of comparison would differ from Bytewise comparator in little// endian machines.extern const Comparator* Uint64Comparator();// Iterator over a vector of keys/valuesclass VectorIterator : public InternalIterator { public:  explicit VectorIterator(const std::vector<std::string>& keys)      : keys_(keys), current_(keys.size()) {    std::sort(keys_.begin(), keys_.end());    values_.resize(keys.size());  }  VectorIterator(const std::vector<std::string>& keys,      const std::vector<std::string>& values)    : keys_(keys), values_(values), current_(keys.size()) {    assert(keys_.size() == values_.size());  }  virtual bool Valid() const override { return current_ < keys_.size(); }  virtual void SeekToFirst() override { current_ = 0; }  virtual void SeekToLast() override { current_ = keys_.size() - 1; }  virtual void Seek(const Slice& target) override {    current_ = std::lower_bound(keys_.begin(), keys_.end(), target.ToString()) -               keys_.begin();  }  virtual void SeekForPrev(const Slice& target) override {    current_ = std::upper_bound(keys_.begin(), keys_.end(), target.ToString()) -               keys_.begin();    if (!Valid()) {      SeekToLast();    } else {      Prev();    }  }  virtual void Next() override { current_++; }  virtual void Prev() override { current_--; }  virtual Slice key() const override { return Slice(keys_[current_]); }  virtual Slice value() const override { return Slice(values_[current_]); }  virtual Status status() const override { return Status::OK(); }  virtual bool IsKeyPinned() const override { return true; }  virtual bool IsValuePinned() const override { return true; } private:  std::vector<std::string> keys_;  std::vector<std::string> values_;  size_t current_;};extern WritableFileWriter* GetWritableFileWriter(WritableFile* wf,                                                 const std::string& fname);extern RandomAccessFileReader* GetRandomAccessFileReader(RandomAccessFile* raf);extern SequentialFileReader* GetSequentialFileReader(SequentialFile* se,                                                     const std::string& fname);class StringSink: public WritableFile { public:  std::string contents_;  explicit StringSink(Slice* reader_contents = nullptr) :      WritableFile(),      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_; }  virtual Status Truncate(uint64_t size) override {    contents_.resize(static_cast<size_t>(size));    return Status::OK();  }  virtual Status Close() override { return Status::OK(); }  virtual Status Flush() 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 Status::OK();  }  virtual Status Sync() override { return Status::OK(); }  virtual Status Append(const Slice& slice) override {    contents_.append(slice.data(), slice.size());    return Status::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();    }  } private:  Slice* reader_contents_;  size_t last_flush_;};// A wrapper around a StringSink to give it a RandomRWFile interfaceclass RandomRWStringSink : public RandomRWFile { public:  explicit RandomRWStringSink(StringSink* ss) : ss_(ss) {}  Status Write(uint64_t offset, const Slice& data) 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 Status::OK();  }  Status Read(uint64_t offset, size_t n, Slice* result,              char* /*scratch*/) 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 Status::OK();  }  Status Flush() override { return Status::OK(); }  Status Sync() override { return Status::OK(); }  Status Close() override { return Status::OK(); }  const std::string& contents() const { return ss_->contents(); } private:  StringSink* ss_;};// Like StringSink, this writes into a string.  Unlink StringSink, it// has some initial content and overwrites it, just like a recycled// log file.class OverwritingStringSink : public WritableFile { public:  explicit OverwritingStringSink(Slice* reader_contents)      : WritableFile(),        contents_(""),        reader_contents_(reader_contents),        last_flush_(0) {}  const std::string& contents() const { return contents_; }  virtual Status Truncate(uint64_t size) override {    contents_.resize(static_cast<size_t>(size));    return Status::OK();  }  virtual Status Close() override { return Status::OK(); }  virtual Status Flush() 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 Status::OK();  }  virtual Status Sync() override { return Status::OK(); }  virtual Status Append(const Slice& slice) override {    contents_.append(slice.data(), slice.size());    return Status::OK();  }  void Drop(size_t bytes) {    contents_.resize(contents_.size() - bytes);    if (last_flush_ > contents_.size()) last_flush_ = contents_.size();  } private:  std::string contents_;  Slice* reader_contents_;  size_t last_flush_;};class StringSource: public RandomAccessFile { 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(); }  virtual Status Read(uint64_t offset, size_t n, Slice* result,      char* scratch) const override {    total_reads_++;    if (offset > contents_.size()) {      return Status::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 Status::OK();  }  virtual 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; } private:  std::string contents_;  uint64_t uniq_id_;  bool mmap_;  mutable int total_reads_;};inline StringSink* GetStringSinkFromLegacyWriter(    const WritableFileWriter* writer) {  LegacyWritableFileWrapper* file =      static_cast<LegacyWritableFileWrapper*>(writer->writable_file());  return static_cast<StringSink*>(file->target());}class NullLogger : public Logger { public:  using Logger::Logv;  virtual void Logv(const char* /*format*/, va_list /*ap*/) override {}  virtual size_t GetLogFileSize() const override { return 0; }};// Corrupts key by changing the typeextern void CorruptKeyType(InternalKey* ikey);extern std::string KeyStr(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) {}  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();    }  }  // Waits for the status to change to sleeping,  // otherwise times out.  // wait_time is in microseconds.  // Returns true when times out, false otherwise.  bool TimedWaitUntilSleeping(uint64_t wait_time) {    auto abs_time = Env::Default()->NowMicros() + wait_time;    MutexLock l(&mutex_);    while (!sleeping_ || !should_sleep_) {      if (bg_cv_.TimedWait(abs_time)) {        return true;      }    }    return false;  }  void WakeUp() {    MutexLock l(&mutex_);    should_sleep_ = false;    bg_cv_.SignalAll();  }  void WaitUntilDone() {    MutexLock l(&mutex_);    while (!done_with_sleep_) {      bg_cv_.Wait();    }  }  // Similar to TimedWaitUntilSleeping.  // Waits until the task is done.  bool TimedWaitUntilDone(uint64_t wait_time) {    auto abs_time = Env::Default()->NowMicros() + wait_time;    MutexLock l(&mutex_);    while (!done_with_sleep_) {      if (bg_cv_.TimedWait(abs_time)) {        return true;      }    }    return false;  }  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) {    reinterpret_cast<SleepingBackgroundTask*>(arg)->DoSleep();  } private:  port::Mutex mutex_;  port::CondVar bg_cv_;  // Signalled when background work finishes  bool should_sleep_;  bool done_with_sleep_;  bool sleeping_;};// Filters merge operands and values that are equal to `num`.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 /*level*/, const ROCKSDB_NAMESPACE::Slice& /*key*/,              const ROCKSDB_NAMESPACE::Slice& value, std::string* /*new_value*/,              bool* /*value_changed*/) const override {    if (value.size() == sizeof(uint64_t)) {      return num_ == DecodeFixed64(value.data());    }    return true;  }  bool FilterMergeOperand(      int /*level*/, 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 SequentialFile {   public:    SeqStringSource(const std::string& data, std::atomic<int>* read_count)        : data_(data), offset_(0), read_count_(read_count) {}    ~SeqStringSource() override {}    Status Read(size_t n, Slice* result, char* scratch) 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 Status::InvalidArgument(            "Attemp to read when it already reached eof.");      }      (*read_count_)++;      return Status::OK();    }    Status Skip(uint64_t n) override {      if (offset_ >= data_.size()) {        return Status::InvalidArgument(            "Attemp to read when it already reached eof.");      }      // TODO(yhchiang): Currently doesn't handle the overflow case.      offset_ += static_cast<size_t>(n);      return Status::OK();    }   private:    std::string data_;    size_t offset_;    std::atomic<int>* read_count_;  };  class StringEnv : public EnvWrapper {   public:    class StringSink : public WritableFile {     public:      explicit StringSink(std::string* contents)          : WritableFile(), contents_(contents) {}      virtual Status Truncate(uint64_t size) override {        contents_->resize(static_cast<size_t>(size));        return Status::OK();      }      virtual Status Close() override { return Status::OK(); }      virtual Status Flush() override { return Status::OK(); }      virtual Status Sync() override { return Status::OK(); }      virtual Status Append(const Slice& slice) override {        contents_->append(slice.data(), slice.size());        return Status::OK();      }     private:      std::string* contents_;    };    explicit StringEnv(Env* t) : EnvWrapper(t) {}    ~StringEnv() override {}    const std::string& GetContent(const std::string& f) { return files_[f]; }    const Status WriteToNewFile(const std::string& file_name,                                const std::string& content) {      std::unique_ptr<WritableFile> r;      auto s = NewWritableFile(file_name, &r, EnvOptions());      if (!s.ok()) {        return s;      }      r->Append(content);      r->Flush();      r->Close();      assert(files_[file_name] == content);      return Status::OK();    }    // The following text is boilerplate that forwards all methods to target()    Status NewSequentialFile(const std::string& f,                             std::unique_ptr<SequentialFile>* r,                             const EnvOptions& /*options*/) override {      auto iter = files_.find(f);      if (iter == files_.end()) {        return Status::NotFound("The specified file does not exist", f);      }      r->reset(new SeqStringSource(iter->second, &num_seq_file_read_));      return Status::OK();    }    Status NewRandomAccessFile(const std::string& /*f*/,                               std::unique_ptr<RandomAccessFile>* /*r*/,                               const EnvOptions& /*options*/) override {      return Status::NotSupported();    }    Status NewWritableFile(const std::string& f,                           std::unique_ptr<WritableFile>* r,                           const EnvOptions& /*options*/) override {      auto iter = files_.find(f);      if (iter != files_.end()) {        return Status::IOError("The specified file already exists", f);      }      r->reset(new StringSink(&files_[f]));      return Status::OK();    }    virtual Status NewDirectory(        const std::string& /*name*/,        std::unique_ptr<Directory>* /*result*/) override {      return Status::NotSupported();    }    Status FileExists(const std::string& f) override {      if (files_.find(f) == files_.end()) {        return Status::NotFound();      }      return Status::OK();    }    Status GetChildren(const std::string& /*dir*/,                       std::vector<std::string>* /*r*/) override {      return Status::NotSupported();    }    Status DeleteFile(const std::string& f) override {      files_.erase(f);      return Status::OK();    }    Status CreateDir(const std::string& /*d*/) override {      return Status::NotSupported();    }    Status CreateDirIfMissing(const std::string& /*d*/) override {      return Status::NotSupported();    }    Status DeleteDir(const std::string& /*d*/) override {      return Status::NotSupported();    }    Status GetFileSize(const std::string& f, uint64_t* s) override {      auto iter = files_.find(f);      if (iter == files_.end()) {        return Status::NotFound("The specified file does not exist:", f);      }      *s = iter->second.size();      return Status::OK();    }    Status GetFileModificationTime(const std::string& /*fname*/,                                   uint64_t* /*file_mtime*/) override {      return Status::NotSupported();    }    Status RenameFile(const std::string& /*s*/,                      const std::string& /*t*/) override {      return Status::NotSupported();    }    Status LinkFile(const std::string& /*s*/,                    const std::string& /*t*/) override {      return Status::NotSupported();    }    Status LockFile(const std::string& /*f*/, FileLock** /*l*/) override {      return Status::NotSupported();    }    Status UnlockFile(FileLock* /*l*/) override {      return Status::NotSupported();    }    std::atomic<int> num_seq_file_read_;   protected:    std::unordered_map<std::string, std::string> files_;  };// Randomly initialize the given DBOptionsvoid RandomInitDBOptions(DBOptions* db_opt, Random* rnd);// Randomly initialize the given ColumnFamilyOptions// Note that the caller is responsible for releasing non-null// cf_opt->compaction_filter.void RandomInitCFOptions(ColumnFamilyOptions* cf_opt, DBOptions&, Random* rnd);// A dummy merge operator which can change its nameclass ChanglingMergeOperator : public MergeOperator { public:  explicit ChanglingMergeOperator(const std::string& name)      : name_(name + "MergeOperator") {}  ~ChanglingMergeOperator() {}  void SetName(const std::string& name) { name_ = name; }  virtual bool FullMergeV2(const MergeOperationInput& /*merge_in*/,                           MergeOperationOutput* /*merge_out*/) const override {    return false;  }  virtual bool PartialMergeMulti(const Slice& /*key*/,                                 const std::deque<Slice>& /*operand_list*/,                                 std::string* /*new_value*/,                                 Logger* /*logger*/) const override {    return false;  }  virtual const char* Name() const override { return name_.c_str(); } protected:  std::string name_;};// Returns a dummy merge operator with random name.MergeOperator* RandomMergeOperator(Random* rnd);// A dummy compaction filter which can change its nameclass 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 /*level*/, const Slice& /*key*/,              const Slice& /*existing_value*/, std::string* /*new_value*/,              bool* /*value_changed*/) const override {    return false;  }  const char* Name() const override { return name_.c_str(); } private:  std::string name_;};// Returns a dummy compaction filter with a random name.CompactionFilter* RandomCompactionFilter(Random* rnd);// A dummy compaction filter factory which can change its nameclass 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& /*context*/) override {    return std::unique_ptr<CompactionFilter>();  }  // Returns a name that identifies this compaction filter factory.  const char* Name() const override { return name_.c_str(); } protected:  std::string name_;};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);Status DestroyDir(Env* env, const std::string& dir);bool IsDirectIOSupported(Env* env, const std::string& dir);// Return the number of lines where a given pattern was found in a file.size_t GetLinesCount(const std::string& fname, const std::string& pattern);}  // namespace test}  // namespace ROCKSDB_NAMESPACE
 |