YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/rocksdb/db/comparator_db_test.cc
Line
Count
Source (jump to first uncovered line)
1
// Use of this source code is governed by a BSD-style license that can be
2
// found in the LICENSE file. See the AUTHORS file for names of contributors.
3
//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
4
//  This source code is licensed under the BSD-style license found in the
5
//  LICENSE file in the root directory of this source tree. An additional grant
6
//  of patent rights can be found in the PATENTS file in the same directory.
7
//
8
// The following only applies to changes made to this file as part of YugaByte development.
9
//
10
// Portions Copyright (c) YugaByte, Inc.
11
//
12
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
13
// in compliance with the License.  You may obtain a copy of the License at
14
//
15
// http://www.apache.org/licenses/LICENSE-2.0
16
//
17
// Unless required by applicable law or agreed to in writing, software distributed under the License
18
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
19
// or implied.  See the License for the specific language governing permissions and limitations
20
// under the License.
21
//
22
23
#include <map>
24
#include <string>
25
26
#include <gtest/gtest.h>
27
28
#include "yb/rocksdb/db.h"
29
#include "yb/rocksdb/env.h"
30
#include "yb/rocksdb/util/hash.h"
31
#include "yb/rocksdb/util/kv_map.h"
32
#include "yb/rocksdb/util/testharness.h"
33
#include "yb/rocksdb/util/testutil.h"
34
35
#include "yb/util/string_util.h"
36
#include "yb/util/test_macros.h"
37
38
using std::unique_ptr;
39
40
namespace rocksdb {
41
namespace {
42
43
static const Comparator* comparator;
44
45
class KVIter : public Iterator {
46
 public:
47
  explicit KVIter(const stl_wrappers::KVMap* map)
48
80
      : map_(map), iter_(map_->end()) {}
49
65.6k
  bool Valid() const override { return iter_ != map_->end(); }
50
11.3k
  void SeekToFirst() override { iter_ = map_->begin(); }
51
11.3k
  void SeekToLast() override {
52
11.3k
    if (map_->empty()) {
53
0
      iter_ = map_->end();
54
11.3k
    } else {
55
11.3k
      iter_ = map_->find(map_->rbegin()->first);
56
11.3k
    }
57
11.3k
  }
58
11.7k
  void Seek(const Slice& k) override {
59
11.7k
    iter_ = map_->lower_bound(k.ToString());
60
11.7k
  }
61
9.88k
  void Next() override { ++iter_; }
62
9.65k
  void Prev() override {
63
9.65k
    if (iter_ == map_->begin()) {
64
2.43k
      iter_ = map_->end();
65
2.43k
      return;
66
2.43k
    }
67
7.21k
    --iter_;
68
7.21k
  }
69
70
58.3k
  Slice key() const override { return iter_->first; }
71
58.3k
  Slice value() const override { return iter_->second; }
72
0
  Status status() const override { return Status::OK(); }
73
74
 private:
75
  const stl_wrappers::KVMap* const map_;
76
  stl_wrappers::KVMap::const_iterator iter_;
77
};
78
79
65.6k
void AssertItersEqual(Iterator* iter1, Iterator* iter2) {
80
65.6k
  ASSERT_EQ(iter1->Valid(), iter2->Valid());
81
65.6k
  if (iter1->Valid()) {
82
58.3k
    auto key1 = iter1->key().ToBuffer();
83
58.3k
    auto key2 = iter2->key().ToBuffer();
84
58.3k
    auto value1 = iter1->value().ToBuffer();
85
58.3k
    auto value2 = iter2->value().ToBuffer();
86
58.3k
    ASSERT_EQ(key1, key2);
87
58.3k
    ASSERT_EQ(value1, value2);
88
58.3k
  }
89
65.6k
}
90
91
// Measuring operations on DB (expect to be empty).
92
// source_strings are candidate keys
93
void DoRandomIteraratorTest(DB* db, std::vector<std::string> source_strings,
94
                            Random* rnd, int num_writes, int num_iter_ops,
95
80
                            int num_trigger_flush) {
96
80
  stl_wrappers::KVMap map((stl_wrappers::LessOfComparator(comparator)));
97
98
12.5k
  for (int i = 0; i < num_writes; i++) {
99
12.4k
    if (num_trigger_flush > 0 && i != 0 && i % num_trigger_flush == 0) {
100
190
      ASSERT_OK(db->Flush(FlushOptions()));
101
190
    }
102
103
12.4k
    int type = rnd->Uniform(2);
104
12.4k
    int index = rnd->Uniform(static_cast<int>(source_strings.size()));
105
12.4k
    auto& key = source_strings[index];
106
12.4k
    switch (type) {
107
6.22k
      case 0:
108
        // put
109
6.22k
        map[key] = key;
110
6.22k
        ASSERT_OK(db->Put(WriteOptions(), key, key));
111
6.22k
        break;
112
6.27k
      case 1:
113
        // delete
114
6.27k
        if (map.find(key) != map.end()) {
115
1.77k
          map.erase(key);
116
1.77k
        }
117
6.27k
        ASSERT_OK(db->Delete(WriteOptions(), key));
118
6.27k
        break;
119
0
      default:
120
0
        assert(false);
121
12.4k
    }
122
12.4k
  }
123
124
80
  std::unique_ptr<Iterator> iter(db->NewIterator(ReadOptions()));
125
80
  std::unique_ptr<Iterator> result_iter(new KVIter(&map));
126
127
80
  bool is_valid = false;
128
69.5k
  for (int i = 0; i < num_iter_ops; i++) {
129
    // Random walk and make sure iter and result_iter returns the
130
    // same key and value
131
69.5k
    int type = rnd->Uniform(6);
132
69.5k
    ASSERT_OK(iter->status());
133
69.5k
    switch (type) {
134
11.3k
      case 0:
135
        // Seek to First
136
11.3k
        iter->SeekToFirst();
137
11.3k
        result_iter->SeekToFirst();
138
11.3k
        break;
139
11.3k
      case 1:
140
        // Seek to last
141
11.3k
        iter->SeekToLast();
142
11.3k
        result_iter->SeekToLast();
143
11.3k
        break;
144
11.7k
      case 2: {
145
        // Seek to random key
146
11.7k
        auto key_idx = rnd->Uniform(static_cast<int>(source_strings.size()));
147
11.7k
        auto key = source_strings[key_idx];
148
11.7k
        iter->Seek(key);
149
11.7k
        result_iter->Seek(key);
150
11.7k
        break;
151
0
      }
152
11.8k
      case 3:
153
        // Next
154
11.8k
        if (is_valid) {
155
9.88k
          iter->Next();
156
9.88k
          result_iter->Next();
157
1.93k
        } else {
158
1.93k
          continue;
159
1.93k
        }
160
9.88k
        break;
161
11.5k
      case 4:
162
        // Prev
163
11.5k
        if (is_valid) {
164
9.65k
          iter->Prev();
165
9.65k
          result_iter->Prev();
166
1.87k
        } else {
167
1.87k
          continue;
168
1.87k
        }
169
9.65k
        break;
170
11.7k
      default: {
171
11.7k
        assert(type == 5);
172
11.7k
        auto key_idx = rnd->Uniform(static_cast<int>(source_strings.size()));
173
11.7k
        auto key = source_strings[key_idx];
174
11.7k
        std::string result;
175
11.7k
        auto status = db->Get(ReadOptions(), key, &result);
176
11.7k
        if (map.find(key) == map.end()) {
177
6.82k
          ASSERT_TRUE(status.IsNotFound());
178
4.88k
        } else {
179
4.88k
          ASSERT_EQ(map[key], result);
180
4.88k
        }
181
11.7k
        break;
182
65.6k
      }
183
65.6k
    }
184
65.6k
    AssertItersEqual(iter.get(), result_iter.get());
185
65.6k
    is_valid = iter->Valid();
186
65.6k
  }
187
80
}
188
189
class DoubleComparator : public Comparator {
190
 public:
191
1
  DoubleComparator() {}
192
193
76
  const char* Name() const override { return "DoubleComparator"; }
194
195
568k
  int Compare(const Slice& a, const Slice& b) const override {
196
568k
#ifndef CYGWIN
197
568k
    double da = std::stod(a.ToString());
198
568k
    double db = std::stod(b.ToString());
199
#else
200
    double da = std::strtod(a.ToString().c_str(), 0 /* endptr */);
201
    double db = std::strtod(a.ToString().c_str(), 0 /* endptr */);
202
#endif
203
568k
    if (da == db) {
204
104k
      return a.compare(b);
205
464k
    } else if (da > db) {
206
143k
      return 1;
207
320k
    } else {
208
320k
      return -1;
209
320k
    }
210
568k
  }
211
  virtual void FindShortestSeparator(std::string* start,
212
0
                                     const Slice& limit) const override {}
213
214
45
  void FindShortSuccessor(std::string* key) const override {}
215
};
216
217
class HashComparator : public Comparator {
218
 public:
219
1
  HashComparator() {}
220
221
76
  const char* Name() const override { return "HashComparator"; }
222
223
569k
  int Compare(const Slice& a, const Slice& b) const override {
224
569k
    uint32_t ha = Hash(a.data(), a.size(), 66);
225
569k
    uint32_t hb = Hash(b.data(), b.size(), 66);
226
569k
    if (ha == hb) {
227
105k
      return a.compare(b);
228
464k
    } else if (ha > hb) {
229
141k
      return 1;
230
322k
    } else {
231
322k
      return -1;
232
322k
    }
233
569k
  }
234
  virtual void FindShortestSeparator(std::string* start,
235
0
                                     const Slice& limit) const override {}
236
237
45
  void FindShortSuccessor(std::string* key) const override {}
238
};
239
240
class TwoStrComparator : public Comparator {
241
 public:
242
1
  TwoStrComparator() {}
243
244
76
  const char* Name() const override { return "TwoStrComparator"; }
245
246
544k
  int Compare(const Slice& a, const Slice& b) const override {
247
544k
    assert(a.size() >= 2);
248
544k
    assert(b.size() >= 2);
249
544k
    size_t size_a1 = static_cast<size_t>(a[0]);
250
544k
    size_t size_b1 = static_cast<size_t>(b[0]);
251
544k
    size_t size_a2 = static_cast<size_t>(a[1]);
252
544k
    size_t size_b2 = static_cast<size_t>(b[1]);
253
544k
    assert(size_a1 + size_a2 + 2 == a.size());
254
544k
    assert(size_b1 + size_b2 + 2 == b.size());
255
256
544k
    Slice a1 = Slice(a.data() + 2, size_a1);
257
544k
    Slice b1 = Slice(b.data() + 2, size_b1);
258
544k
    Slice a2 = Slice(a.data() + 2 + size_a1, size_a2);
259
544k
    Slice b2 = Slice(b.data() + 2 + size_b1, size_b2);
260
261
544k
    if (a1 != b1) {
262
403k
      return a1.compare(b1);
263
403k
    }
264
140k
    return a2.compare(b2);
265
140k
  }
266
  virtual void FindShortestSeparator(std::string* start,
267
0
                                     const Slice& limit) const override {}
268
269
45
  void FindShortSuccessor(std::string* key) const override {}
270
};
271
}  // namespace
272
273
class ComparatorDBTest : public RocksDBTest {
274
 private:
275
  std::string dbname_;
276
  Env* env_;
277
  DB* db_;
278
  Options last_options_;
279
  std::unique_ptr<const Comparator> comparator_guard;
280
281
 public:
282
6
  ComparatorDBTest() : env_(Env::Default()), db_(nullptr) {
283
6
    comparator = BytewiseComparator();
284
6
    dbname_ = test::TmpDir() + "/comparator_db_test";
285
6
    EXPECT_OK(DestroyDB(dbname_, last_options_));
286
6
  }
287
288
6
  ~ComparatorDBTest() {
289
6
    delete db_;
290
6
    EXPECT_OK(DestroyDB(dbname_, last_options_));
291
6
    comparator = BytewiseComparator();
292
6
  }
293
294
80
  DB* GetDB() { return db_; }
295
296
4
  void SetOwnedComparator(const Comparator* cmp) {
297
4
    comparator_guard.reset(cmp);
298
4
    SetComparator(cmp);
299
4
  }
300
301
5
  void SetComparator(const Comparator* cmp) {
302
5
    comparator = cmp;
303
5
    last_options_.comparator = cmp;
304
5
  }
305
306
  // Return the current option configuration.
307
75
  Options* GetOptions() { return &last_options_; }
308
309
80
  void DestroyAndReopen() {
310
    // Destroy using last options
311
80
    Destroy();
312
80
    ASSERT_OK(TryReopen());
313
80
  }
314
315
80
  void Destroy() {
316
80
    delete db_;
317
80
    db_ = nullptr;
318
80
    ASSERT_OK(DestroyDB(dbname_, last_options_));
319
80
  }
320
321
80
  Status TryReopen() {
322
80
    delete db_;
323
80
    db_ = nullptr;
324
80
    last_options_.create_if_missing = true;
325
326
80
    return DB::Open(last_options_, dbname_, &db_);
327
80
  }
328
};
329
330
1
TEST_F(ComparatorDBTest, Bytewise) {
331
6
  for (int rand_seed = 301; rand_seed < 306; rand_seed++) {
332
5
    DestroyAndReopen();
333
5
    Random rnd(rand_seed);
334
5
    DoRandomIteraratorTest(GetDB(),
335
5
                           {"a", "b", "c", "d", "e", "f", "g", "h", "i"}, &rnd,
336
5
                           8, 100, 3);
337
5
  }
338
1
}
339
340
1
TEST_F(ComparatorDBTest, SimpleSuffixReverseComparator) {
341
1
  SetOwnedComparator(new test::SimpleSuffixReverseComparator());
342
343
16
  for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) {
344
15
    Options* opt = GetOptions();
345
15
    opt->comparator = comparator;
346
15
    DestroyAndReopen();
347
15
    Random rnd(rnd_seed);
348
349
15
    std::vector<std::string> source_strings;
350
15
    std::vector<std::string> source_prefixes;
351
    // Randomly generate 5 prefixes
352
90
    for (int i = 0; i < 5; i++) {
353
75
      source_prefixes.push_back(test::RandomHumanReadableString(&rnd, 8));
354
75
    }
355
315
    for (int j = 0; j < 20; j++) {
356
300
      int prefix_index = rnd.Uniform(static_cast<int>(source_prefixes.size()));
357
300
      std::string key = source_prefixes[prefix_index] +
358
300
                        test::RandomHumanReadableString(&rnd, rnd.Uniform(8));
359
300
      source_strings.push_back(key);
360
300
    }
361
362
15
    DoRandomIteraratorTest(GetDB(), source_strings, &rnd, 30, 600, 66);
363
15
  }
364
1
}
365
366
1
TEST_F(ComparatorDBTest, Uint64Comparator) {
367
1
  SetComparator(Uint64Comparator());
368
369
16
  for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) {
370
15
    Options* opt = GetOptions();
371
15
    opt->comparator = comparator;
372
15
    DestroyAndReopen();
373
15
    Random rnd(rnd_seed);
374
15
    Random64 rnd64(rnd_seed);
375
376
15
    std::vector<std::string> source_strings;
377
    // Randomly generate source keys
378
1.51k
    for (int i = 0; i < 100; i++) {
379
1.50k
      uint64_t r = rnd64.Next();
380
1.50k
      std::string str;
381
1.50k
      str.resize(8);
382
1.50k
      memcpy(&str[0], static_cast<void*>(&r), 8);
383
1.50k
      source_strings.push_back(str);
384
1.50k
    }
385
386
15
    DoRandomIteraratorTest(GetDB(), source_strings, &rnd, 200, 1000, 66);
387
15
  }
388
1
}
389
390
1
TEST_F(ComparatorDBTest, DoubleComparator) {
391
1
  SetOwnedComparator(new DoubleComparator());
392
393
16
  for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) {
394
15
    Options* opt = GetOptions();
395
15
    opt->comparator = comparator;
396
15
    DestroyAndReopen();
397
15
    Random rnd(rnd_seed);
398
399
15
    std::vector<std::string> source_strings;
400
    // Randomly generate source keys
401
1.51k
    for (int i = 0; i < 100; i++) {
402
1.50k
      uint32_t r = rnd.Next();
403
1.50k
      uint32_t divide_order = rnd.Uniform(8);
404
1.50k
      double to_divide = 1.0;
405
6.78k
      for (uint32_t j = 0; j < divide_order; j++) {
406
5.28k
        to_divide *= 10.0;
407
5.28k
      }
408
1.50k
      source_strings.push_back(ToString(r / to_divide));
409
1.50k
    }
410
411
15
    DoRandomIteraratorTest(GetDB(), source_strings, &rnd, 200, 1000, 66);
412
15
  }
413
1
}
414
415
1
TEST_F(ComparatorDBTest, HashComparator) {
416
1
  SetOwnedComparator(new HashComparator());
417
418
16
  for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) {
419
15
    Options* opt = GetOptions();
420
15
    opt->comparator = comparator;
421
15
    DestroyAndReopen();
422
15
    Random rnd(rnd_seed);
423
424
15
    std::vector<std::string> source_strings;
425
    // Randomly generate source keys
426
1.51k
    for (int i = 0; i < 100; i++) {
427
1.50k
      source_strings.push_back(test::RandomKey(&rnd, 8));
428
1.50k
    }
429
430
15
    DoRandomIteraratorTest(GetDB(), source_strings, &rnd, 200, 1000, 66);
431
15
  }
432
1
}
433
434
1
TEST_F(ComparatorDBTest, TwoStrComparator) {
435
1
  SetOwnedComparator(new TwoStrComparator());
436
437
16
  for (int rnd_seed = 301; rnd_seed < 316; rnd_seed++) {
438
15
    Options* opt = GetOptions();
439
15
    opt->comparator = comparator;
440
15
    DestroyAndReopen();
441
15
    Random rnd(rnd_seed);
442
443
15
    std::vector<std::string> source_strings;
444
    // Randomly generate source keys
445
1.51k
    for (int i = 0; i < 100; i++) {
446
1.50k
      std::string str;
447
1.50k
      uint32_t size1 = rnd.Uniform(8);
448
1.50k
      uint32_t size2 = rnd.Uniform(8);
449
1.50k
      str.append(1, static_cast<char>(size1));
450
1.50k
      str.append(1, static_cast<char>(size2));
451
1.50k
      str.append(test::RandomKey(&rnd, size1));
452
1.50k
      str.append(test::RandomKey(&rnd, size2));
453
1.50k
      source_strings.push_back(str);
454
1.50k
    }
455
456
15
    DoRandomIteraratorTest(GetDB(), source_strings, &rnd, 200, 1000, 66);
457
15
  }
458
1
}
459
460
}  // namespace rocksdb
461
462
13.2k
int main(int argc, char** argv) {
463
13.2k
  ::testing::InitGoogleTest(&argc, argv);
464
13.2k
  return RUN_ALL_TESTS();
465
13.2k
}