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.
10 #include "memtable/stl_wrappers.h"
11 #include "rocksdb/db.h"
12 #include "rocksdb/env.h"
13 #include "util/hash.h"
14 #include "util/kv_map.h"
15 #include "util/string_util.h"
16 #include "util/testharness.h"
17 #include "util/testutil.h"
18 #include "utilities/merge_operators.h"
20 using std::unique_ptr
;
25 static const Comparator
* comparator
;
27 class KVIter
: public Iterator
{
29 explicit KVIter(const stl_wrappers::KVMap
* map
)
30 : map_(map
), iter_(map_
->end()) {}
31 virtual bool Valid() const override
{ return iter_
!= map_
->end(); }
32 virtual void SeekToFirst() override
{ iter_
= map_
->begin(); }
33 virtual void SeekToLast() override
{
37 iter_
= map_
->find(map_
->rbegin()->first
);
40 virtual void Seek(const Slice
& k
) override
{
41 iter_
= map_
->lower_bound(k
.ToString());
43 virtual void SeekForPrev(const Slice
& k
) override
{
44 iter_
= map_
->upper_bound(k
.ToString());
47 virtual void Next() override
{ ++iter_
; }
48 virtual void Prev() override
{
49 if (iter_
== map_
->begin()) {
56 virtual Slice
key() const override
{ return iter_
->first
; }
57 virtual Slice
value() const override
{ return iter_
->second
; }
58 virtual Status
status() const override
{ return Status::OK(); }
61 const stl_wrappers::KVMap
* const map_
;
62 stl_wrappers::KVMap::const_iterator iter_
;
65 void AssertItersEqual(Iterator
* iter1
, Iterator
* iter2
) {
66 ASSERT_EQ(iter1
->Valid(), iter2
->Valid());
68 ASSERT_EQ(iter1
->key().ToString(), iter2
->key().ToString());
69 ASSERT_EQ(iter1
->value().ToString(), iter2
->value().ToString());
73 // Measuring operations on DB (expect to be empty).
74 // source_strings are candidate keys
75 void DoRandomIteraratorTest(DB
* db
, std::vector
<std::string
> source_strings
,
76 Random
* rnd
, int num_writes
, int num_iter_ops
,
77 int num_trigger_flush
) {
78 stl_wrappers::KVMap
map((stl_wrappers::LessOfComparator(comparator
)));
80 for (int i
= 0; i
< num_writes
; i
++) {
81 if (num_trigger_flush
> 0 && i
!= 0 && i
% num_trigger_flush
== 0) {
82 db
->Flush(FlushOptions());
85 int type
= rnd
->Uniform(2);
86 int index
= rnd
->Uniform(static_cast<int>(source_strings
.size()));
87 auto& key
= source_strings
[index
];
92 ASSERT_OK(db
->Put(WriteOptions(), key
, key
));
96 if (map
.find(key
) != map
.end()) {
99 ASSERT_OK(db
->Delete(WriteOptions(), key
));
106 std::unique_ptr
<Iterator
> iter(db
->NewIterator(ReadOptions()));
107 std::unique_ptr
<Iterator
> result_iter(new KVIter(&map
));
109 bool is_valid
= false;
110 for (int i
= 0; i
< num_iter_ops
; i
++) {
111 // Random walk and make sure iter and result_iter returns the
112 // same key and value
113 int type
= rnd
->Uniform(6);
114 ASSERT_OK(iter
->status());
119 result_iter
->SeekToFirst();
124 result_iter
->SeekToLast();
127 // Seek to random key
128 auto key_idx
= rnd
->Uniform(static_cast<int>(source_strings
.size()));
129 auto key
= source_strings
[key_idx
];
131 result_iter
->Seek(key
);
154 auto key_idx
= rnd
->Uniform(static_cast<int>(source_strings
.size()));
155 auto key
= source_strings
[key_idx
];
157 auto status
= db
->Get(ReadOptions(), key
, &result
);
158 if (map
.find(key
) == map
.end()) {
159 ASSERT_TRUE(status
.IsNotFound());
161 ASSERT_EQ(map
[key
], result
);
166 AssertItersEqual(iter
.get(), result_iter
.get());
167 is_valid
= iter
->Valid();
171 class DoubleComparator
: public Comparator
{
173 DoubleComparator() {}
175 virtual const char* Name() const override
{ return "DoubleComparator"; }
177 virtual int Compare(const Slice
& a
, const Slice
& b
) const override
{
179 double da
= std::stod(a
.ToString());
180 double db
= std::stod(b
.ToString());
182 double da
= std::strtod(a
.ToString().c_str(), 0 /* endptr */);
183 double db
= std::strtod(a
.ToString().c_str(), 0 /* endptr */);
187 } else if (da
> db
) {
193 virtual void FindShortestSeparator(std::string
* start
,
194 const Slice
& limit
) const override
{}
196 virtual void FindShortSuccessor(std::string
* key
) const override
{}
199 class HashComparator
: public Comparator
{
203 virtual const char* Name() const override
{ return "HashComparator"; }
205 virtual int Compare(const Slice
& a
, const Slice
& b
) const override
{
206 uint32_t ha
= Hash(a
.data(), a
.size(), 66);
207 uint32_t hb
= Hash(b
.data(), b
.size(), 66);
210 } else if (ha
> hb
) {
216 virtual void FindShortestSeparator(std::string
* start
,
217 const Slice
& limit
) const override
{}
219 virtual void FindShortSuccessor(std::string
* key
) const override
{}
222 class TwoStrComparator
: public Comparator
{
224 TwoStrComparator() {}
226 virtual const char* Name() const override
{ return "TwoStrComparator"; }
228 virtual int Compare(const Slice
& a
, const Slice
& b
) const override
{
229 assert(a
.size() >= 2);
230 assert(b
.size() >= 2);
231 size_t size_a1
= static_cast<size_t>(a
[0]);
232 size_t size_b1
= static_cast<size_t>(b
[0]);
233 size_t size_a2
= static_cast<size_t>(a
[1]);
234 size_t size_b2
= static_cast<size_t>(b
[1]);
235 assert(size_a1
+ size_a2
+ 2 == a
.size());
236 assert(size_b1
+ size_b2
+ 2 == b
.size());
238 Slice a1
= Slice(a
.data() + 2, size_a1
);
239 Slice b1
= Slice(b
.data() + 2, size_b1
);
240 Slice a2
= Slice(a
.data() + 2 + size_a1
, size_a2
);
241 Slice b2
= Slice(b
.data() + 2 + size_b1
, size_b2
);
244 return a1
.compare(b1
);
246 return a2
.compare(b2
);
248 virtual void FindShortestSeparator(std::string
* start
,
249 const Slice
& limit
) const override
{}
251 virtual void FindShortSuccessor(std::string
* key
) const override
{}
255 class ComparatorDBTest
: public testing::Test
{
260 Options last_options_
;
261 std::unique_ptr
<const Comparator
> comparator_guard
;
264 ComparatorDBTest() : env_(Env::Default()), db_(nullptr) {
265 comparator
= BytewiseComparator();
266 dbname_
= test::TmpDir() + "/comparator_db_test";
267 EXPECT_OK(DestroyDB(dbname_
, last_options_
));
270 ~ComparatorDBTest() {
272 EXPECT_OK(DestroyDB(dbname_
, last_options_
));
273 comparator
= BytewiseComparator();
276 DB
* GetDB() { return db_
; }
278 void SetOwnedComparator(const Comparator
* cmp
) {
279 comparator_guard
.reset(cmp
);
281 last_options_
.comparator
= cmp
;
284 // Return the current option configuration.
285 Options
* GetOptions() { return &last_options_
; }
287 void DestroyAndReopen() {
288 // Destroy using last options
290 ASSERT_OK(TryReopen());
296 ASSERT_OK(DestroyDB(dbname_
, last_options_
));
302 last_options_
.create_if_missing
= true;
304 return DB::Open(last_options_
, dbname_
, &db_
);
308 TEST_F(ComparatorDBTest
, Bytewise
) {
309 for (int rand_seed
= 301; rand_seed
< 306; rand_seed
++) {
311 Random
rnd(rand_seed
);
312 DoRandomIteraratorTest(GetDB(),
313 {"a", "b", "c", "d", "e", "f", "g", "h", "i"}, &rnd
,
318 TEST_F(ComparatorDBTest
, SimpleSuffixReverseComparator
) {
319 SetOwnedComparator(new test::SimpleSuffixReverseComparator());
321 for (int rnd_seed
= 301; rnd_seed
< 316; rnd_seed
++) {
322 Options
* opt
= GetOptions();
323 opt
->comparator
= comparator
;
325 Random
rnd(rnd_seed
);
327 std::vector
<std::string
> source_strings
;
328 std::vector
<std::string
> source_prefixes
;
329 // Randomly generate 5 prefixes
330 for (int i
= 0; i
< 5; i
++) {
331 source_prefixes
.push_back(test::RandomHumanReadableString(&rnd
, 8));
333 for (int j
= 0; j
< 20; j
++) {
334 int prefix_index
= rnd
.Uniform(static_cast<int>(source_prefixes
.size()));
335 std::string key
= source_prefixes
[prefix_index
] +
336 test::RandomHumanReadableString(&rnd
, rnd
.Uniform(8));
337 source_strings
.push_back(key
);
340 DoRandomIteraratorTest(GetDB(), source_strings
, &rnd
, 30, 600, 66);
344 TEST_F(ComparatorDBTest
, Uint64Comparator
) {
345 SetOwnedComparator(test::Uint64Comparator());
347 for (int rnd_seed
= 301; rnd_seed
< 316; rnd_seed
++) {
348 Options
* opt
= GetOptions();
349 opt
->comparator
= comparator
;
351 Random
rnd(rnd_seed
);
352 Random64
rnd64(rnd_seed
);
354 std::vector
<std::string
> source_strings
;
355 // Randomly generate source keys
356 for (int i
= 0; i
< 100; i
++) {
357 uint64_t r
= rnd64
.Next();
360 memcpy(&str
[0], static_cast<void*>(&r
), 8);
361 source_strings
.push_back(str
);
364 DoRandomIteraratorTest(GetDB(), source_strings
, &rnd
, 200, 1000, 66);
368 TEST_F(ComparatorDBTest
, DoubleComparator
) {
369 SetOwnedComparator(new DoubleComparator());
371 for (int rnd_seed
= 301; rnd_seed
< 316; rnd_seed
++) {
372 Options
* opt
= GetOptions();
373 opt
->comparator
= comparator
;
375 Random
rnd(rnd_seed
);
377 std::vector
<std::string
> source_strings
;
378 // Randomly generate source keys
379 for (int i
= 0; i
< 100; i
++) {
380 uint32_t r
= rnd
.Next();
381 uint32_t divide_order
= rnd
.Uniform(8);
382 double to_divide
= 1.0;
383 for (uint32_t j
= 0; j
< divide_order
; j
++) {
386 source_strings
.push_back(ToString(r
/ to_divide
));
389 DoRandomIteraratorTest(GetDB(), source_strings
, &rnd
, 200, 1000, 66);
393 TEST_F(ComparatorDBTest
, HashComparator
) {
394 SetOwnedComparator(new HashComparator());
396 for (int rnd_seed
= 301; rnd_seed
< 316; rnd_seed
++) {
397 Options
* opt
= GetOptions();
398 opt
->comparator
= comparator
;
400 Random
rnd(rnd_seed
);
402 std::vector
<std::string
> source_strings
;
403 // Randomly generate source keys
404 for (int i
= 0; i
< 100; i
++) {
405 source_strings
.push_back(test::RandomKey(&rnd
, 8));
408 DoRandomIteraratorTest(GetDB(), source_strings
, &rnd
, 200, 1000, 66);
412 TEST_F(ComparatorDBTest
, TwoStrComparator
) {
413 SetOwnedComparator(new TwoStrComparator());
415 for (int rnd_seed
= 301; rnd_seed
< 316; rnd_seed
++) {
416 Options
* opt
= GetOptions();
417 opt
->comparator
= comparator
;
419 Random
rnd(rnd_seed
);
421 std::vector
<std::string
> source_strings
;
422 // Randomly generate source keys
423 for (int i
= 0; i
< 100; i
++) {
425 uint32_t size1
= rnd
.Uniform(8);
426 uint32_t size2
= rnd
.Uniform(8);
427 str
.append(1, static_cast<char>(size1
));
428 str
.append(1, static_cast<char>(size2
));
429 str
.append(test::RandomKey(&rnd
, size1
));
430 str
.append(test::RandomKey(&rnd
, size2
));
431 source_strings
.push_back(str
);
434 DoRandomIteraratorTest(GetDB(), source_strings
, &rnd
, 200, 1000, 66);
438 } // namespace rocksdb
440 int main(int argc
, char** argv
) {
441 ::testing::InitGoogleTest(&argc
, argv
);
442 return RUN_ALL_TESTS();