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