YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

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