1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
5 //
6 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7 // Use of this source code is governed by a BSD-style license that can be
8 // found in the LICENSE file. See the AUTHORS file for names of contributors.
9
10 #pragma once
11 #include <algorithm>
12 #include <deque>
13 #include <string>
14 #include <vector>
15
16 #include "env/composite_env_wrapper.h"
17 #include "file/writable_file_writer.h"
18 #include "rocksdb/compaction_filter.h"
19 #include "rocksdb/env.h"
20 #include "rocksdb/iterator.h"
21 #include "rocksdb/merge_operator.h"
22 #include "rocksdb/options.h"
23 #include "rocksdb/slice.h"
24 #include "rocksdb/table.h"
25 #include "table/block_based/block_based_table_factory.h"
26 #include "table/internal_iterator.h"
27 #include "table/plain/plain_table_factory.h"
28 #include "util/mutexlock.h"
29 #include "util/random.h"
30
31 namespace ROCKSDB_NAMESPACE {
32 class SequentialFile;
33 class SequentialFileReader;
34
35 namespace test {
36
37 extern const uint32_t kDefaultFormatVersion;
38 extern const uint32_t kLatestFormatVersion;
39
40 // Store in *dst a random string of length "len" and return a Slice that
41 // references the generated data.
42 extern Slice RandomString(Random* rnd, int len, std::string* dst);
43
44 extern std::string RandomHumanReadableString(Random* rnd, int len);
45
46 // Return a random key with the specified length that may contain interesting
47 // characters (e.g. \x00, \xff, etc.).
48 enum RandomKeyType : char { RANDOM, LARGEST, SMALLEST, MIDDLE };
49 extern std::string RandomKey(Random* rnd, int len,
50 RandomKeyType type = RandomKeyType::RANDOM);
51
52 // Store in *dst a string of length "len" that will compress to
53 // "N*compressed_fraction" bytes and return a Slice that references
54 // the generated data.
55 extern Slice CompressibleString(Random* rnd, double compressed_fraction,
56 int len, std::string* dst);
57
58 // A wrapper that allows injection of errors.
59 class ErrorEnv : public EnvWrapper {
60 public:
61 bool writable_file_error_;
62 int num_writable_file_errors_;
63
ErrorEnv()64 ErrorEnv() : EnvWrapper(Env::Default()),
65 writable_file_error_(false),
66 num_writable_file_errors_(0) { }
67
NewWritableFile(const std::string & fname,std::unique_ptr<WritableFile> * result,const EnvOptions & soptions)68 virtual Status NewWritableFile(const std::string& fname,
69 std::unique_ptr<WritableFile>* result,
70 const EnvOptions& soptions) override {
71 result->reset();
72 if (writable_file_error_) {
73 ++num_writable_file_errors_;
74 return Status::IOError(fname, "fake error");
75 }
76 return target()->NewWritableFile(fname, result, soptions);
77 }
78 };
79
80 #ifndef NDEBUG
81 // An internal comparator that just forward comparing results from the
82 // user comparator in it. Can be used to test entities that have no dependency
83 // on internal key structure but consumes InternalKeyComparator, like
84 // BlockBasedTable.
85 class PlainInternalKeyComparator : public InternalKeyComparator {
86 public:
PlainInternalKeyComparator(const Comparator * c)87 explicit PlainInternalKeyComparator(const Comparator* c)
88 : InternalKeyComparator(c) {}
89
~PlainInternalKeyComparator()90 virtual ~PlainInternalKeyComparator() {}
91
Compare(const Slice & a,const Slice & b)92 virtual int Compare(const Slice& a, const Slice& b) const override {
93 return user_comparator()->Compare(a, b);
94 }
95 };
96 #endif
97
98 // A test comparator which compare two strings in this way:
99 // (1) first compare prefix of 8 bytes in alphabet order,
100 // (2) if two strings share the same prefix, sort the other part of the string
101 // in the reverse alphabet order.
102 // This helps simulate the case of compounded key of [entity][timestamp] and
103 // latest timestamp first.
104 class SimpleSuffixReverseComparator : public Comparator {
105 public:
SimpleSuffixReverseComparator()106 SimpleSuffixReverseComparator() {}
107
Name()108 virtual const char* Name() const override {
109 return "SimpleSuffixReverseComparator";
110 }
111
Compare(const Slice & a,const Slice & b)112 virtual int Compare(const Slice& a, const Slice& b) const override {
113 Slice prefix_a = Slice(a.data(), 8);
114 Slice prefix_b = Slice(b.data(), 8);
115 int prefix_comp = prefix_a.compare(prefix_b);
116 if (prefix_comp != 0) {
117 return prefix_comp;
118 } else {
119 Slice suffix_a = Slice(a.data() + 8, a.size() - 8);
120 Slice suffix_b = Slice(b.data() + 8, b.size() - 8);
121 return -(suffix_a.compare(suffix_b));
122 }
123 }
FindShortestSeparator(std::string *,const Slice &)124 virtual void FindShortestSeparator(std::string* /*start*/,
125 const Slice& /*limit*/) const override {}
126
FindShortSuccessor(std::string *)127 virtual void FindShortSuccessor(std::string* /*key*/) const override {}
128 };
129
130 // Returns a user key comparator that can be used for comparing two uint64_t
131 // slices. Instead of comparing slices byte-wise, it compares all the 8 bytes
132 // at once. Assumes same endian-ness is used though the database's lifetime.
133 // Symantics of comparison would differ from Bytewise comparator in little
134 // endian machines.
135 extern const Comparator* Uint64Comparator();
136
137 // Iterator over a vector of keys/values
138 class VectorIterator : public InternalIterator {
139 public:
VectorIterator(const std::vector<std::string> & keys)140 explicit VectorIterator(const std::vector<std::string>& keys)
141 : keys_(keys), current_(keys.size()) {
142 std::sort(keys_.begin(), keys_.end());
143 values_.resize(keys.size());
144 }
145
VectorIterator(const std::vector<std::string> & keys,const std::vector<std::string> & values)146 VectorIterator(const std::vector<std::string>& keys,
147 const std::vector<std::string>& values)
148 : keys_(keys), values_(values), current_(keys.size()) {
149 assert(keys_.size() == values_.size());
150 }
151
Valid()152 virtual bool Valid() const override { return current_ < keys_.size(); }
153
SeekToFirst()154 virtual void SeekToFirst() override { current_ = 0; }
SeekToLast()155 virtual void SeekToLast() override { current_ = keys_.size() - 1; }
156
Seek(const Slice & target)157 virtual void Seek(const Slice& target) override {
158 current_ = std::lower_bound(keys_.begin(), keys_.end(), target.ToString()) -
159 keys_.begin();
160 }
161
SeekForPrev(const Slice & target)162 virtual void SeekForPrev(const Slice& target) override {
163 current_ = std::upper_bound(keys_.begin(), keys_.end(), target.ToString()) -
164 keys_.begin();
165 if (!Valid()) {
166 SeekToLast();
167 } else {
168 Prev();
169 }
170 }
171
Next()172 virtual void Next() override { current_++; }
Prev()173 virtual void Prev() override { current_--; }
174
key()175 virtual Slice key() const override { return Slice(keys_[current_]); }
value()176 virtual Slice value() const override { return Slice(values_[current_]); }
177
status()178 virtual Status status() const override { return Status::OK(); }
179
IsKeyPinned()180 virtual bool IsKeyPinned() const override { return true; }
IsValuePinned()181 virtual bool IsValuePinned() const override { return true; }
182
183 private:
184 std::vector<std::string> keys_;
185 std::vector<std::string> values_;
186 size_t current_;
187 };
188 extern WritableFileWriter* GetWritableFileWriter(WritableFile* wf,
189 const std::string& fname);
190
191 extern RandomAccessFileReader* GetRandomAccessFileReader(RandomAccessFile* raf);
192
193 extern SequentialFileReader* GetSequentialFileReader(SequentialFile* se,
194 const std::string& fname);
195
196 class StringSink: public WritableFile {
197 public:
198 std::string contents_;
199
200 explicit StringSink(Slice* reader_contents = nullptr) :
WritableFile()201 WritableFile(),
202 contents_(""),
203 reader_contents_(reader_contents),
204 last_flush_(0) {
205 if (reader_contents_ != nullptr) {
206 *reader_contents_ = Slice(contents_.data(), 0);
207 }
208 }
209
contents()210 const std::string& contents() const { return contents_; }
211
Truncate(uint64_t size)212 virtual Status Truncate(uint64_t size) override {
213 contents_.resize(static_cast<size_t>(size));
214 return Status::OK();
215 }
Close()216 virtual Status Close() override { return Status::OK(); }
Flush()217 virtual Status Flush() override {
218 if (reader_contents_ != nullptr) {
219 assert(reader_contents_->size() <= last_flush_);
220 size_t offset = last_flush_ - reader_contents_->size();
221 *reader_contents_ = Slice(
222 contents_.data() + offset,
223 contents_.size() - offset);
224 last_flush_ = contents_.size();
225 }
226
227 return Status::OK();
228 }
Sync()229 virtual Status Sync() override { return Status::OK(); }
Append(const Slice & slice)230 virtual Status Append(const Slice& slice) override {
231 contents_.append(slice.data(), slice.size());
232 return Status::OK();
233 }
Drop(size_t bytes)234 void Drop(size_t bytes) {
235 if (reader_contents_ != nullptr) {
236 contents_.resize(contents_.size() - bytes);
237 *reader_contents_ = Slice(
238 reader_contents_->data(), reader_contents_->size() - bytes);
239 last_flush_ = contents_.size();
240 }
241 }
242
243 private:
244 Slice* reader_contents_;
245 size_t last_flush_;
246 };
247
248 // A wrapper around a StringSink to give it a RandomRWFile interface
249 class RandomRWStringSink : public RandomRWFile {
250 public:
RandomRWStringSink(StringSink * ss)251 explicit RandomRWStringSink(StringSink* ss) : ss_(ss) {}
252
Write(uint64_t offset,const Slice & data)253 Status Write(uint64_t offset, const Slice& data) override {
254 if (offset + data.size() > ss_->contents_.size()) {
255 ss_->contents_.resize(static_cast<size_t>(offset) + data.size(), '\0');
256 }
257
258 char* pos = const_cast<char*>(ss_->contents_.data() + offset);
259 memcpy(pos, data.data(), data.size());
260 return Status::OK();
261 }
262
Read(uint64_t offset,size_t n,Slice * result,char *)263 Status Read(uint64_t offset, size_t n, Slice* result,
264 char* /*scratch*/) const override {
265 *result = Slice(nullptr, 0);
266 if (offset < ss_->contents_.size()) {
267 size_t str_res_sz =
268 std::min(static_cast<size_t>(ss_->contents_.size() - offset), n);
269 *result = Slice(ss_->contents_.data() + offset, str_res_sz);
270 }
271 return Status::OK();
272 }
273
Flush()274 Status Flush() override { return Status::OK(); }
275
Sync()276 Status Sync() override { return Status::OK(); }
277
Close()278 Status Close() override { return Status::OK(); }
279
contents()280 const std::string& contents() const { return ss_->contents(); }
281
282 private:
283 StringSink* ss_;
284 };
285
286 // Like StringSink, this writes into a string. Unlink StringSink, it
287 // has some initial content and overwrites it, just like a recycled
288 // log file.
289 class OverwritingStringSink : public WritableFile {
290 public:
OverwritingStringSink(Slice * reader_contents)291 explicit OverwritingStringSink(Slice* reader_contents)
292 : WritableFile(),
293 contents_(""),
294 reader_contents_(reader_contents),
295 last_flush_(0) {}
296
contents()297 const std::string& contents() const { return contents_; }
298
Truncate(uint64_t size)299 virtual Status Truncate(uint64_t size) override {
300 contents_.resize(static_cast<size_t>(size));
301 return Status::OK();
302 }
Close()303 virtual Status Close() override { return Status::OK(); }
Flush()304 virtual Status Flush() override {
305 if (last_flush_ < contents_.size()) {
306 assert(reader_contents_->size() >= contents_.size());
307 memcpy((char*)reader_contents_->data() + last_flush_,
308 contents_.data() + last_flush_, contents_.size() - last_flush_);
309 last_flush_ = contents_.size();
310 }
311 return Status::OK();
312 }
Sync()313 virtual Status Sync() override { return Status::OK(); }
Append(const Slice & slice)314 virtual Status Append(const Slice& slice) override {
315 contents_.append(slice.data(), slice.size());
316 return Status::OK();
317 }
Drop(size_t bytes)318 void Drop(size_t bytes) {
319 contents_.resize(contents_.size() - bytes);
320 if (last_flush_ > contents_.size()) last_flush_ = contents_.size();
321 }
322
323 private:
324 std::string contents_;
325 Slice* reader_contents_;
326 size_t last_flush_;
327 };
328
329 class StringSource: public RandomAccessFile {
330 public:
331 explicit StringSource(const Slice& contents, uint64_t uniq_id = 0,
332 bool mmap = false)
333 : contents_(contents.data(), contents.size()),
334 uniq_id_(uniq_id),
335 mmap_(mmap),
336 total_reads_(0) {}
337
~StringSource()338 virtual ~StringSource() { }
339
Size()340 uint64_t Size() const { return contents_.size(); }
341
Read(uint64_t offset,size_t n,Slice * result,char * scratch)342 virtual Status Read(uint64_t offset, size_t n, Slice* result,
343 char* scratch) const override {
344 total_reads_++;
345 if (offset > contents_.size()) {
346 return Status::InvalidArgument("invalid Read offset");
347 }
348 if (offset + n > contents_.size()) {
349 n = contents_.size() - static_cast<size_t>(offset);
350 }
351 if (!mmap_) {
352 memcpy(scratch, &contents_[static_cast<size_t>(offset)], n);
353 *result = Slice(scratch, n);
354 } else {
355 *result = Slice(&contents_[static_cast<size_t>(offset)], n);
356 }
357 return Status::OK();
358 }
359
GetUniqueId(char * id,size_t max_size)360 virtual size_t GetUniqueId(char* id, size_t max_size) const override {
361 if (max_size < 20) {
362 return 0;
363 }
364
365 char* rid = id;
366 rid = EncodeVarint64(rid, uniq_id_);
367 rid = EncodeVarint64(rid, 0);
368 return static_cast<size_t>(rid-id);
369 }
370
total_reads()371 int total_reads() const { return total_reads_; }
372
set_total_reads(int tr)373 void set_total_reads(int tr) { total_reads_ = tr; }
374
375 private:
376 std::string contents_;
377 uint64_t uniq_id_;
378 bool mmap_;
379 mutable int total_reads_;
380 };
381
GetStringSinkFromLegacyWriter(const WritableFileWriter * writer)382 inline StringSink* GetStringSinkFromLegacyWriter(
383 const WritableFileWriter* writer) {
384 LegacyWritableFileWrapper* file =
385 static_cast<LegacyWritableFileWrapper*>(writer->writable_file());
386 return static_cast<StringSink*>(file->target());
387 }
388
389 class NullLogger : public Logger {
390 public:
391 using Logger::Logv;
Logv(const char *,va_list)392 virtual void Logv(const char* /*format*/, va_list /*ap*/) override {}
GetLogFileSize()393 virtual size_t GetLogFileSize() const override { return 0; }
394 };
395
396 // Corrupts key by changing the type
397 extern void CorruptKeyType(InternalKey* ikey);
398
399 extern std::string KeyStr(const std::string& user_key,
400 const SequenceNumber& seq, const ValueType& t,
401 bool corrupt = false);
402
403 class SleepingBackgroundTask {
404 public:
SleepingBackgroundTask()405 SleepingBackgroundTask()
406 : bg_cv_(&mutex_),
407 should_sleep_(true),
408 done_with_sleep_(false),
409 sleeping_(false) {}
410
IsSleeping()411 bool IsSleeping() {
412 MutexLock l(&mutex_);
413 return sleeping_;
414 }
DoSleep()415 void DoSleep() {
416 MutexLock l(&mutex_);
417 sleeping_ = true;
418 bg_cv_.SignalAll();
419 while (should_sleep_) {
420 bg_cv_.Wait();
421 }
422 sleeping_ = false;
423 done_with_sleep_ = true;
424 bg_cv_.SignalAll();
425 }
WaitUntilSleeping()426 void WaitUntilSleeping() {
427 MutexLock l(&mutex_);
428 while (!sleeping_ || !should_sleep_) {
429 bg_cv_.Wait();
430 }
431 }
432 // Waits for the status to change to sleeping,
433 // otherwise times out.
434 // wait_time is in microseconds.
435 // Returns true when times out, false otherwise.
TimedWaitUntilSleeping(uint64_t wait_time)436 bool TimedWaitUntilSleeping(uint64_t wait_time) {
437 auto abs_time = Env::Default()->NowMicros() + wait_time;
438 MutexLock l(&mutex_);
439 while (!sleeping_ || !should_sleep_) {
440 if (bg_cv_.TimedWait(abs_time)) {
441 return true;
442 }
443 }
444 return false;
445 }
WakeUp()446 void WakeUp() {
447 MutexLock l(&mutex_);
448 should_sleep_ = false;
449 bg_cv_.SignalAll();
450 }
WaitUntilDone()451 void WaitUntilDone() {
452 MutexLock l(&mutex_);
453 while (!done_with_sleep_) {
454 bg_cv_.Wait();
455 }
456 }
457 // Similar to TimedWaitUntilSleeping.
458 // Waits until the task is done.
TimedWaitUntilDone(uint64_t wait_time)459 bool TimedWaitUntilDone(uint64_t wait_time) {
460 auto abs_time = Env::Default()->NowMicros() + wait_time;
461 MutexLock l(&mutex_);
462 while (!done_with_sleep_) {
463 if (bg_cv_.TimedWait(abs_time)) {
464 return true;
465 }
466 }
467 return false;
468 }
WokenUp()469 bool WokenUp() {
470 MutexLock l(&mutex_);
471 return should_sleep_ == false;
472 }
473
Reset()474 void Reset() {
475 MutexLock l(&mutex_);
476 should_sleep_ = true;
477 done_with_sleep_ = false;
478 }
479
DoSleepTask(void * arg)480 static void DoSleepTask(void* arg) {
481 reinterpret_cast<SleepingBackgroundTask*>(arg)->DoSleep();
482 }
483
484 private:
485 port::Mutex mutex_;
486 port::CondVar bg_cv_; // Signalled when background work finishes
487 bool should_sleep_;
488 bool done_with_sleep_;
489 bool sleeping_;
490 };
491
492 // Filters merge operands and values that are equal to `num`.
493 class FilterNumber : public CompactionFilter {
494 public:
FilterNumber(uint64_t num)495 explicit FilterNumber(uint64_t num) : num_(num) {}
496
last_merge_operand_key()497 std::string last_merge_operand_key() { return last_merge_operand_key_; }
498
Filter(int,const ROCKSDB_NAMESPACE::Slice &,const ROCKSDB_NAMESPACE::Slice & value,std::string *,bool *)499 bool Filter(int /*level*/, const ROCKSDB_NAMESPACE::Slice& /*key*/,
500 const ROCKSDB_NAMESPACE::Slice& value, std::string* /*new_value*/,
501 bool* /*value_changed*/) const override {
502 if (value.size() == sizeof(uint64_t)) {
503 return num_ == DecodeFixed64(value.data());
504 }
505 return true;
506 }
507
FilterMergeOperand(int,const ROCKSDB_NAMESPACE::Slice & key,const ROCKSDB_NAMESPACE::Slice & value)508 bool FilterMergeOperand(
509 int /*level*/, const ROCKSDB_NAMESPACE::Slice& key,
510 const ROCKSDB_NAMESPACE::Slice& value) const override {
511 last_merge_operand_key_ = key.ToString();
512 if (value.size() == sizeof(uint64_t)) {
513 return num_ == DecodeFixed64(value.data());
514 }
515 return true;
516 }
517
Name()518 const char* Name() const override { return "FilterBadMergeOperand"; }
519
520 private:
521 mutable std::string last_merge_operand_key_;
522 uint64_t num_;
523 };
524
EncodeInt(uint64_t x)525 inline std::string EncodeInt(uint64_t x) {
526 std::string result;
527 PutFixed64(&result, x);
528 return result;
529 }
530
531 class SeqStringSource : public SequentialFile {
532 public:
SeqStringSource(const std::string & data,std::atomic<int> * read_count)533 SeqStringSource(const std::string& data, std::atomic<int>* read_count)
534 : data_(data), offset_(0), read_count_(read_count) {}
~SeqStringSource()535 ~SeqStringSource() override {}
Read(size_t n,Slice * result,char * scratch)536 Status Read(size_t n, Slice* result, char* scratch) override {
537 std::string output;
538 if (offset_ < data_.size()) {
539 n = std::min(data_.size() - offset_, n);
540 memcpy(scratch, data_.data() + offset_, n);
541 offset_ += n;
542 *result = Slice(scratch, n);
543 } else {
544 return Status::InvalidArgument(
545 "Attemp to read when it already reached eof.");
546 }
547 (*read_count_)++;
548 return Status::OK();
549 }
Skip(uint64_t n)550 Status Skip(uint64_t n) override {
551 if (offset_ >= data_.size()) {
552 return Status::InvalidArgument(
553 "Attemp to read when it already reached eof.");
554 }
555 // TODO(yhchiang): Currently doesn't handle the overflow case.
556 offset_ += static_cast<size_t>(n);
557 return Status::OK();
558 }
559
560 private:
561 std::string data_;
562 size_t offset_;
563 std::atomic<int>* read_count_;
564 };
565
566 class StringEnv : public EnvWrapper {
567 public:
568 class StringSink : public WritableFile {
569 public:
StringSink(std::string * contents)570 explicit StringSink(std::string* contents)
571 : WritableFile(), contents_(contents) {}
Truncate(uint64_t size)572 virtual Status Truncate(uint64_t size) override {
573 contents_->resize(static_cast<size_t>(size));
574 return Status::OK();
575 }
Close()576 virtual Status Close() override { return Status::OK(); }
Flush()577 virtual Status Flush() override { return Status::OK(); }
Sync()578 virtual Status Sync() override { return Status::OK(); }
Append(const Slice & slice)579 virtual Status Append(const Slice& slice) override {
580 contents_->append(slice.data(), slice.size());
581 return Status::OK();
582 }
583
584 private:
585 std::string* contents_;
586 };
587
StringEnv(Env * t)588 explicit StringEnv(Env* t) : EnvWrapper(t) {}
~StringEnv()589 ~StringEnv() override {}
590
GetContent(const std::string & f)591 const std::string& GetContent(const std::string& f) { return files_[f]; }
592
WriteToNewFile(const std::string & file_name,const std::string & content)593 const Status WriteToNewFile(const std::string& file_name,
594 const std::string& content) {
595 std::unique_ptr<WritableFile> r;
596 auto s = NewWritableFile(file_name, &r, EnvOptions());
597 if (!s.ok()) {
598 return s;
599 }
600 r->Append(content);
601 r->Flush();
602 r->Close();
603 assert(files_[file_name] == content);
604 return Status::OK();
605 }
606
607 // The following text is boilerplate that forwards all methods to target()
NewSequentialFile(const std::string & f,std::unique_ptr<SequentialFile> * r,const EnvOptions &)608 Status NewSequentialFile(const std::string& f,
609 std::unique_ptr<SequentialFile>* r,
610 const EnvOptions& /*options*/) override {
611 auto iter = files_.find(f);
612 if (iter == files_.end()) {
613 return Status::NotFound("The specified file does not exist", f);
614 }
615 r->reset(new SeqStringSource(iter->second, &num_seq_file_read_));
616 return Status::OK();
617 }
NewRandomAccessFile(const std::string &,std::unique_ptr<RandomAccessFile> *,const EnvOptions &)618 Status NewRandomAccessFile(const std::string& /*f*/,
619 std::unique_ptr<RandomAccessFile>* /*r*/,
620 const EnvOptions& /*options*/) override {
621 return Status::NotSupported();
622 }
NewWritableFile(const std::string & f,std::unique_ptr<WritableFile> * r,const EnvOptions &)623 Status NewWritableFile(const std::string& f,
624 std::unique_ptr<WritableFile>* r,
625 const EnvOptions& /*options*/) override {
626 auto iter = files_.find(f);
627 if (iter != files_.end()) {
628 return Status::IOError("The specified file already exists", f);
629 }
630 r->reset(new StringSink(&files_[f]));
631 return Status::OK();
632 }
NewDirectory(const std::string &,std::unique_ptr<Directory> *)633 virtual Status NewDirectory(
634 const std::string& /*name*/,
635 std::unique_ptr<Directory>* /*result*/) override {
636 return Status::NotSupported();
637 }
FileExists(const std::string & f)638 Status FileExists(const std::string& f) override {
639 if (files_.find(f) == files_.end()) {
640 return Status::NotFound();
641 }
642 return Status::OK();
643 }
GetChildren(const std::string &,std::vector<std::string> *)644 Status GetChildren(const std::string& /*dir*/,
645 std::vector<std::string>* /*r*/) override {
646 return Status::NotSupported();
647 }
DeleteFile(const std::string & f)648 Status DeleteFile(const std::string& f) override {
649 files_.erase(f);
650 return Status::OK();
651 }
CreateDir(const std::string &)652 Status CreateDir(const std::string& /*d*/) override {
653 return Status::NotSupported();
654 }
CreateDirIfMissing(const std::string &)655 Status CreateDirIfMissing(const std::string& /*d*/) override {
656 return Status::NotSupported();
657 }
DeleteDir(const std::string &)658 Status DeleteDir(const std::string& /*d*/) override {
659 return Status::NotSupported();
660 }
GetFileSize(const std::string & f,uint64_t * s)661 Status GetFileSize(const std::string& f, uint64_t* s) override {
662 auto iter = files_.find(f);
663 if (iter == files_.end()) {
664 return Status::NotFound("The specified file does not exist:", f);
665 }
666 *s = iter->second.size();
667 return Status::OK();
668 }
669
GetFileModificationTime(const std::string &,uint64_t *)670 Status GetFileModificationTime(const std::string& /*fname*/,
671 uint64_t* /*file_mtime*/) override {
672 return Status::NotSupported();
673 }
674
RenameFile(const std::string &,const std::string &)675 Status RenameFile(const std::string& /*s*/,
676 const std::string& /*t*/) override {
677 return Status::NotSupported();
678 }
679
LinkFile(const std::string &,const std::string &)680 Status LinkFile(const std::string& /*s*/,
681 const std::string& /*t*/) override {
682 return Status::NotSupported();
683 }
684
LockFile(const std::string &,FileLock **)685 Status LockFile(const std::string& /*f*/, FileLock** /*l*/) override {
686 return Status::NotSupported();
687 }
688
UnlockFile(FileLock *)689 Status UnlockFile(FileLock* /*l*/) override {
690 return Status::NotSupported();
691 }
692
693 std::atomic<int> num_seq_file_read_;
694
695 protected:
696 std::unordered_map<std::string, std::string> files_;
697 };
698
699 // Randomly initialize the given DBOptions
700 void RandomInitDBOptions(DBOptions* db_opt, Random* rnd);
701
702 // Randomly initialize the given ColumnFamilyOptions
703 // Note that the caller is responsible for releasing non-null
704 // cf_opt->compaction_filter.
705 void RandomInitCFOptions(ColumnFamilyOptions* cf_opt, DBOptions&, Random* rnd);
706
707 // A dummy merge operator which can change its name
708 class ChanglingMergeOperator : public MergeOperator {
709 public:
ChanglingMergeOperator(const std::string & name)710 explicit ChanglingMergeOperator(const std::string& name)
711 : name_(name + "MergeOperator") {}
~ChanglingMergeOperator()712 ~ChanglingMergeOperator() {}
713
SetName(const std::string & name)714 void SetName(const std::string& name) { name_ = name; }
715
FullMergeV2(const MergeOperationInput &,MergeOperationOutput *)716 virtual bool FullMergeV2(const MergeOperationInput& /*merge_in*/,
717 MergeOperationOutput* /*merge_out*/) const override {
718 return false;
719 }
PartialMergeMulti(const Slice &,const std::deque<Slice> &,std::string *,Logger *)720 virtual bool PartialMergeMulti(const Slice& /*key*/,
721 const std::deque<Slice>& /*operand_list*/,
722 std::string* /*new_value*/,
723 Logger* /*logger*/) const override {
724 return false;
725 }
Name()726 virtual const char* Name() const override { return name_.c_str(); }
727
728 protected:
729 std::string name_;
730 };
731
732 // Returns a dummy merge operator with random name.
733 MergeOperator* RandomMergeOperator(Random* rnd);
734
735 // A dummy compaction filter which can change its name
736 class ChanglingCompactionFilter : public CompactionFilter {
737 public:
ChanglingCompactionFilter(const std::string & name)738 explicit ChanglingCompactionFilter(const std::string& name)
739 : name_(name + "CompactionFilter") {}
~ChanglingCompactionFilter()740 ~ChanglingCompactionFilter() {}
741
SetName(const std::string & name)742 void SetName(const std::string& name) { name_ = name; }
743
Filter(int,const Slice &,const Slice &,std::string *,bool *)744 bool Filter(int /*level*/, const Slice& /*key*/,
745 const Slice& /*existing_value*/, std::string* /*new_value*/,
746 bool* /*value_changed*/) const override {
747 return false;
748 }
749
Name()750 const char* Name() const override { return name_.c_str(); }
751
752 private:
753 std::string name_;
754 };
755
756 // Returns a dummy compaction filter with a random name.
757 CompactionFilter* RandomCompactionFilter(Random* rnd);
758
759 // A dummy compaction filter factory which can change its name
760 class ChanglingCompactionFilterFactory : public CompactionFilterFactory {
761 public:
ChanglingCompactionFilterFactory(const std::string & name)762 explicit ChanglingCompactionFilterFactory(const std::string& name)
763 : name_(name + "CompactionFilterFactory") {}
~ChanglingCompactionFilterFactory()764 ~ChanglingCompactionFilterFactory() {}
765
SetName(const std::string & name)766 void SetName(const std::string& name) { name_ = name; }
767
CreateCompactionFilter(const CompactionFilter::Context &)768 std::unique_ptr<CompactionFilter> CreateCompactionFilter(
769 const CompactionFilter::Context& /*context*/) override {
770 return std::unique_ptr<CompactionFilter>();
771 }
772
773 // Returns a name that identifies this compaction filter factory.
Name()774 const char* Name() const override { return name_.c_str(); }
775
776 protected:
777 std::string name_;
778 };
779
780 CompressionType RandomCompressionType(Random* rnd);
781
782 void RandomCompressionTypeVector(const size_t count,
783 std::vector<CompressionType>* types,
784 Random* rnd);
785
786 CompactionFilterFactory* RandomCompactionFilterFactory(Random* rnd);
787
788 const SliceTransform* RandomSliceTransform(Random* rnd, int pre_defined = -1);
789
790 TableFactory* RandomTableFactory(Random* rnd, int pre_defined = -1);
791
792 std::string RandomName(Random* rnd, const size_t len);
793
794 Status DestroyDir(Env* env, const std::string& dir);
795
796 bool IsDirectIOSupported(Env* env, const std::string& dir);
797
798 // Return the number of lines where a given pattern was found in a file.
799 size_t GetLinesCount(const std::string& fname, const std::string& pattern);
800
801 } // namespace test
802 } // namespace ROCKSDB_NAMESPACE
803