]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/db/plain_table_db_test.cc
import 14.2.4 nautilus point release
[ceph.git] / ceph / src / rocksdb / db / plain_table_db_test.cc
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#ifndef ROCKSDB_LITE
11
12#include <algorithm>
13#include <set>
14
15#include "db/db_impl.h"
16#include "db/version_set.h"
17#include "db/write_batch_internal.h"
18#include "rocksdb/cache.h"
19#include "rocksdb/compaction_filter.h"
20#include "rocksdb/db.h"
21#include "rocksdb/env.h"
22#include "rocksdb/filter_policy.h"
23#include "rocksdb/slice_transform.h"
24#include "rocksdb/table.h"
25#include "table/bloom_block.h"
26#include "table/meta_blocks.h"
27#include "table/plain_table_factory.h"
28#include "table/plain_table_key_coding.h"
29#include "table/plain_table_reader.h"
30#include "table/table_builder.h"
31#include "util/filename.h"
32#include "util/hash.h"
33#include "util/logging.h"
34#include "util/mutexlock.h"
35#include "util/string_util.h"
36#include "util/testharness.h"
37#include "util/testutil.h"
38#include "utilities/merge_operators.h"
39
40using std::unique_ptr;
41
42namespace rocksdb {
43class PlainTableKeyDecoderTest : public testing::Test {};
44
45TEST_F(PlainTableKeyDecoderTest, ReadNonMmap) {
46 std::string tmp;
47 Random rnd(301);
48 const uint32_t kLength = 2222;
49 Slice contents = test::RandomString(&rnd, kLength, &tmp);
50 test::StringSource* string_source =
51 new test::StringSource(contents, 0, false);
52
494da23a 53 std::unique_ptr<RandomAccessFileReader> file_reader(
7c673cae 54 test::GetRandomAccessFileReader(string_source));
494da23a
TL
55 std::unique_ptr<PlainTableReaderFileInfo> file_info(
56 new PlainTableReaderFileInfo(std::move(file_reader), EnvOptions(),
57 kLength));
7c673cae
FG
58
59 {
60 PlainTableFileReader reader(file_info.get());
61
62 const uint32_t kReadSize = 77;
63 for (uint32_t pos = 0; pos < kLength; pos += kReadSize) {
64 uint32_t read_size = std::min(kLength - pos, kReadSize);
65 Slice out;
66 ASSERT_TRUE(reader.Read(pos, read_size, &out));
67 ASSERT_EQ(0, out.compare(tmp.substr(pos, read_size)));
68 }
69
70 ASSERT_LT(uint32_t(string_source->total_reads()), kLength / kReadSize / 2);
71 }
72
73 std::vector<std::vector<std::pair<uint32_t, uint32_t>>> reads = {
74 {{600, 30}, {590, 30}, {600, 20}, {600, 40}},
75 {{800, 20}, {100, 20}, {500, 20}, {1500, 20}, {100, 20}, {80, 20}},
76 {{1000, 20}, {500, 20}, {1000, 50}},
77 {{1000, 20}, {500, 20}, {500, 20}},
78 {{1000, 20}, {500, 20}, {200, 20}, {500, 20}},
79 {{1000, 20}, {500, 20}, {200, 20}, {1000, 50}},
80 {{600, 500}, {610, 20}, {100, 20}},
81 {{500, 100}, {490, 100}, {550, 50}},
82 };
83
84 std::vector<int> num_file_reads = {2, 6, 2, 2, 4, 3, 2, 2};
85
86 for (size_t i = 0; i < reads.size(); i++) {
87 string_source->set_total_reads(0);
88 PlainTableFileReader reader(file_info.get());
89 for (auto p : reads[i]) {
90 Slice out;
91 ASSERT_TRUE(reader.Read(p.first, p.second, &out));
92 ASSERT_EQ(0, out.compare(tmp.substr(p.first, p.second)));
93 }
94 ASSERT_EQ(num_file_reads[i], string_source->total_reads());
95 }
96}
97
98class PlainTableDBTest : public testing::Test,
99 public testing::WithParamInterface<bool> {
100 protected:
101 private:
102 std::string dbname_;
103 Env* env_;
104 DB* db_;
105
106 bool mmap_mode_;
107 Options last_options_;
108
109 public:
110 PlainTableDBTest() : env_(Env::Default()) {}
111
494da23a 112 ~PlainTableDBTest() override {
7c673cae
FG
113 delete db_;
114 EXPECT_OK(DestroyDB(dbname_, Options()));
115 }
116
117 void SetUp() override {
118 mmap_mode_ = GetParam();
11fdf7f2 119 dbname_ = test::PerThreadDBPath("plain_table_db_test");
7c673cae
FG
120 EXPECT_OK(DestroyDB(dbname_, Options()));
121 db_ = nullptr;
122 Reopen();
123 }
124
125 // Return the current option configuration.
126 Options CurrentOptions() {
127 Options options;
128
129 PlainTableOptions plain_table_options;
130 plain_table_options.user_key_len = 0;
131 plain_table_options.bloom_bits_per_key = 2;
132 plain_table_options.hash_table_ratio = 0.8;
133 plain_table_options.index_sparseness = 3;
134 plain_table_options.huge_page_tlb_size = 0;
135 plain_table_options.encoding_type = kPrefix;
136 plain_table_options.full_scan_mode = false;
137 plain_table_options.store_index_in_file = false;
138
139 options.table_factory.reset(NewPlainTableFactory(plain_table_options));
140 options.memtable_factory.reset(NewHashLinkListRepFactory(4, 0, 3, true));
141
142 options.prefix_extractor.reset(NewFixedPrefixTransform(8));
143 options.allow_mmap_reads = mmap_mode_;
144 options.allow_concurrent_memtable_write = false;
145 return options;
146 }
147
148 DBImpl* dbfull() {
149 return reinterpret_cast<DBImpl*>(db_);
150 }
151
152 void Reopen(Options* options = nullptr) {
153 ASSERT_OK(TryReopen(options));
154 }
155
156 void Close() {
157 delete db_;
158 db_ = nullptr;
159 }
160
494da23a
TL
161 bool mmap_mode() const { return mmap_mode_; }
162
7c673cae
FG
163 void DestroyAndReopen(Options* options = nullptr) {
164 //Destroy using last options
165 Destroy(&last_options_);
166 ASSERT_OK(TryReopen(options));
167 }
168
169 void Destroy(Options* options) {
170 delete db_;
171 db_ = nullptr;
172 ASSERT_OK(DestroyDB(dbname_, *options));
173 }
174
175 Status PureReopen(Options* options, DB** db) {
176 return DB::Open(*options, dbname_, db);
177 }
178
494da23a
TL
179 Status ReopenForReadOnly(Options* options) {
180 delete db_;
181 db_ = nullptr;
182 return DB::OpenForReadOnly(*options, dbname_, &db_);
183 }
184
7c673cae
FG
185 Status TryReopen(Options* options = nullptr) {
186 delete db_;
187 db_ = nullptr;
188 Options opts;
189 if (options != nullptr) {
190 opts = *options;
191 } else {
192 opts = CurrentOptions();
193 opts.create_if_missing = true;
194 }
195 last_options_ = opts;
196
197 return DB::Open(opts, dbname_, &db_);
198 }
199
200 Status Put(const Slice& k, const Slice& v) {
201 return db_->Put(WriteOptions(), k, v);
202 }
203
204 Status Delete(const std::string& k) {
205 return db_->Delete(WriteOptions(), k);
206 }
207
208 std::string Get(const std::string& k, const Snapshot* snapshot = nullptr) {
209 ReadOptions options;
210 options.snapshot = snapshot;
211 std::string result;
212 Status s = db_->Get(options, k, &result);
213 if (s.IsNotFound()) {
214 result = "NOT_FOUND";
215 } else if (!s.ok()) {
216 result = s.ToString();
217 }
218 return result;
219 }
220
221
222 int NumTableFilesAtLevel(int level) {
223 std::string property;
224 EXPECT_TRUE(db_->GetProperty(
225 "rocksdb.num-files-at-level" + NumberToString(level), &property));
226 return atoi(property.c_str());
227 }
228
229 // Return spread of files per level
230 std::string FilesPerLevel() {
231 std::string result;
232 size_t last_non_zero_offset = 0;
233 for (int level = 0; level < db_->NumberLevels(); level++) {
234 int f = NumTableFilesAtLevel(level);
235 char buf[100];
236 snprintf(buf, sizeof(buf), "%s%d", (level ? "," : ""), f);
237 result += buf;
238 if (f > 0) {
239 last_non_zero_offset = result.size();
240 }
241 }
242 result.resize(last_non_zero_offset);
243 return result;
244 }
245
246 std::string IterStatus(Iterator* iter) {
247 std::string result;
248 if (iter->Valid()) {
249 result = iter->key().ToString() + "->" + iter->value().ToString();
250 } else {
251 result = "(invalid)";
252 }
253 return result;
254 }
255};
256
257TEST_P(PlainTableDBTest, Empty) {
258 ASSERT_TRUE(dbfull() != nullptr);
259 ASSERT_EQ("NOT_FOUND", Get("0000000000000foo"));
260}
261
262extern const uint64_t kPlainTableMagicNumber;
263
264class TestPlainTableReader : public PlainTableReader {
265 public:
266 TestPlainTableReader(const EnvOptions& env_options,
267 const InternalKeyComparator& icomparator,
268 EncodingType encoding_type, uint64_t file_size,
269 int bloom_bits_per_key, double hash_table_ratio,
270 size_t index_sparseness,
271 const TableProperties* table_properties,
494da23a 272 std::unique_ptr<RandomAccessFileReader>&& file,
7c673cae 273 const ImmutableCFOptions& ioptions,
11fdf7f2 274 const SliceTransform* prefix_extractor,
7c673cae
FG
275 bool* expect_bloom_not_match, bool store_index_in_file,
276 uint32_t column_family_id,
277 const std::string& column_family_name)
278 : PlainTableReader(ioptions, std::move(file), env_options, icomparator,
11fdf7f2
TL
279 encoding_type, file_size, table_properties,
280 prefix_extractor),
7c673cae
FG
281 expect_bloom_not_match_(expect_bloom_not_match) {
282 Status s = MmapDataIfNeeded();
283 EXPECT_TRUE(s.ok());
284
285 s = PopulateIndex(const_cast<TableProperties*>(table_properties),
286 bloom_bits_per_key, hash_table_ratio, index_sparseness,
287 2 * 1024 * 1024);
288 EXPECT_TRUE(s.ok());
289
290 TableProperties* props = const_cast<TableProperties*>(table_properties);
291 EXPECT_EQ(column_family_id, static_cast<uint32_t>(props->column_family_id));
292 EXPECT_EQ(column_family_name, props->column_family_name);
293 if (store_index_in_file) {
294 auto bloom_version_ptr = props->user_collected_properties.find(
295 PlainTablePropertyNames::kBloomVersion);
296 EXPECT_TRUE(bloom_version_ptr != props->user_collected_properties.end());
297 EXPECT_EQ(bloom_version_ptr->second, std::string("1"));
298 if (ioptions.bloom_locality > 0) {
299 auto num_blocks_ptr = props->user_collected_properties.find(
300 PlainTablePropertyNames::kNumBloomBlocks);
301 EXPECT_TRUE(num_blocks_ptr != props->user_collected_properties.end());
302 }
303 }
304 }
305
494da23a 306 ~TestPlainTableReader() override {}
7c673cae
FG
307
308 private:
494da23a 309 bool MatchBloom(uint32_t hash) const override {
7c673cae
FG
310 bool ret = PlainTableReader::MatchBloom(hash);
311 if (*expect_bloom_not_match_) {
312 EXPECT_TRUE(!ret);
313 } else {
314 EXPECT_TRUE(ret);
315 }
316 return ret;
317 }
318 bool* expect_bloom_not_match_;
319};
320
321extern const uint64_t kPlainTableMagicNumber;
322class TestPlainTableFactory : public PlainTableFactory {
323 public:
324 explicit TestPlainTableFactory(bool* expect_bloom_not_match,
325 const PlainTableOptions& options,
326 uint32_t column_family_id,
327 std::string column_family_name)
328 : PlainTableFactory(options),
329 bloom_bits_per_key_(options.bloom_bits_per_key),
330 hash_table_ratio_(options.hash_table_ratio),
331 index_sparseness_(options.index_sparseness),
332 store_index_in_file_(options.store_index_in_file),
333 expect_bloom_not_match_(expect_bloom_not_match),
334 column_family_id_(column_family_id),
335 column_family_name_(std::move(column_family_name)) {}
336
337 Status NewTableReader(
338 const TableReaderOptions& table_reader_options,
494da23a
TL
339 std::unique_ptr<RandomAccessFileReader>&& file, uint64_t file_size,
340 std::unique_ptr<TableReader>* table,
11fdf7f2 341 bool /*prefetch_index_and_filter_in_cache*/) const override {
7c673cae
FG
342 TableProperties* props = nullptr;
343 auto s =
344 ReadTableProperties(file.get(), file_size, kPlainTableMagicNumber,
11fdf7f2
TL
345 table_reader_options.ioptions, &props,
346 true /* compression_type_missing */);
7c673cae
FG
347 EXPECT_TRUE(s.ok());
348
349 if (store_index_in_file_) {
350 BlockHandle bloom_block_handle;
351 s = FindMetaBlock(file.get(), file_size, kPlainTableMagicNumber,
352 table_reader_options.ioptions,
11fdf7f2
TL
353 BloomBlockBuilder::kBloomBlock, &bloom_block_handle,
354 /* compression_type_missing */ true);
7c673cae
FG
355 EXPECT_TRUE(s.ok());
356
357 BlockHandle index_block_handle;
358 s = FindMetaBlock(file.get(), file_size, kPlainTableMagicNumber,
359 table_reader_options.ioptions,
360 PlainTableIndexBuilder::kPlainTableIndexBlock,
11fdf7f2 361 &index_block_handle, /* compression_type_missing */ true);
7c673cae
FG
362 EXPECT_TRUE(s.ok());
363 }
364
365 auto& user_props = props->user_collected_properties;
366 auto encoding_type_prop =
367 user_props.find(PlainTablePropertyNames::kEncodingType);
368 assert(encoding_type_prop != user_props.end());
369 EncodingType encoding_type = static_cast<EncodingType>(
370 DecodeFixed32(encoding_type_prop->second.c_str()));
371
372 std::unique_ptr<PlainTableReader> new_reader(new TestPlainTableReader(
373 table_reader_options.env_options,
374 table_reader_options.internal_comparator, encoding_type, file_size,
375 bloom_bits_per_key_, hash_table_ratio_, index_sparseness_, props,
11fdf7f2
TL
376 std::move(file), table_reader_options.ioptions,
377 table_reader_options.prefix_extractor, expect_bloom_not_match_,
7c673cae
FG
378 store_index_in_file_, column_family_id_, column_family_name_));
379
380 *table = std::move(new_reader);
381 return s;
382 }
383
384 private:
385 int bloom_bits_per_key_;
386 double hash_table_ratio_;
387 size_t index_sparseness_;
388 bool store_index_in_file_;
389 bool* expect_bloom_not_match_;
390 const uint32_t column_family_id_;
391 const std::string column_family_name_;
392};
393
394TEST_P(PlainTableDBTest, Flush) {
395 for (size_t huge_page_tlb_size = 0; huge_page_tlb_size <= 2 * 1024 * 1024;
396 huge_page_tlb_size += 2 * 1024 * 1024) {
397 for (EncodingType encoding_type : {kPlain, kPrefix}) {
398 for (int bloom_bits = 0; bloom_bits <= 117; bloom_bits += 117) {
399 for (int total_order = 0; total_order <= 1; total_order++) {
400 for (int store_index_in_file = 0; store_index_in_file <= 1;
401 ++store_index_in_file) {
402 Options options = CurrentOptions();
403 options.create_if_missing = true;
404 // Set only one bucket to force bucket conflict.
405 // Test index interval for the same prefix to be 1, 2 and 4
406 if (total_order) {
407 options.prefix_extractor.reset();
408
409 PlainTableOptions plain_table_options;
410 plain_table_options.user_key_len = 0;
411 plain_table_options.bloom_bits_per_key = bloom_bits;
412 plain_table_options.hash_table_ratio = 0;
413 plain_table_options.index_sparseness = 2;
414 plain_table_options.huge_page_tlb_size = huge_page_tlb_size;
415 plain_table_options.encoding_type = encoding_type;
416 plain_table_options.full_scan_mode = false;
417 plain_table_options.store_index_in_file = store_index_in_file;
418
419 options.table_factory.reset(
420 NewPlainTableFactory(plain_table_options));
421 } else {
422 PlainTableOptions plain_table_options;
423 plain_table_options.user_key_len = 0;
424 plain_table_options.bloom_bits_per_key = bloom_bits;
425 plain_table_options.hash_table_ratio = 0.75;
426 plain_table_options.index_sparseness = 16;
427 plain_table_options.huge_page_tlb_size = huge_page_tlb_size;
428 plain_table_options.encoding_type = encoding_type;
429 plain_table_options.full_scan_mode = false;
430 plain_table_options.store_index_in_file = store_index_in_file;
431
432 options.table_factory.reset(
433 NewPlainTableFactory(plain_table_options));
434 }
435 DestroyAndReopen(&options);
436 uint64_t int_num;
437 ASSERT_TRUE(dbfull()->GetIntProperty(
438 "rocksdb.estimate-table-readers-mem", &int_num));
439 ASSERT_EQ(int_num, 0U);
440
441 ASSERT_OK(Put("1000000000000foo", "v1"));
442 ASSERT_OK(Put("0000000000000bar", "v2"));
443 ASSERT_OK(Put("1000000000000foo", "v3"));
444 dbfull()->TEST_FlushMemTable();
445
446 ASSERT_TRUE(dbfull()->GetIntProperty(
447 "rocksdb.estimate-table-readers-mem", &int_num));
448 ASSERT_GT(int_num, 0U);
449
450 TablePropertiesCollection ptc;
451 reinterpret_cast<DB*>(dbfull())->GetPropertiesOfAllTables(&ptc);
452 ASSERT_EQ(1U, ptc.size());
453 auto row = ptc.begin();
454 auto tp = row->second;
455
456 if (!store_index_in_file) {
457 ASSERT_EQ(total_order ? "4" : "12",
458 (tp->user_collected_properties)
459 .at("plain_table_hash_table_size"));
460 ASSERT_EQ("0", (tp->user_collected_properties)
461 .at("plain_table_sub_index_size"));
462 } else {
463 ASSERT_EQ("0", (tp->user_collected_properties)
464 .at("plain_table_hash_table_size"));
465 ASSERT_EQ("0", (tp->user_collected_properties)
466 .at("plain_table_sub_index_size"));
467 }
468 ASSERT_EQ("v3", Get("1000000000000foo"));
469 ASSERT_EQ("v2", Get("0000000000000bar"));
470 }
471 }
472 }
473 }
474 }
475}
476
477TEST_P(PlainTableDBTest, Flush2) {
478 for (size_t huge_page_tlb_size = 0; huge_page_tlb_size <= 2 * 1024 * 1024;
479 huge_page_tlb_size += 2 * 1024 * 1024) {
480 for (EncodingType encoding_type : {kPlain, kPrefix}) {
481 for (int bloom_bits = 0; bloom_bits <= 117; bloom_bits += 117) {
482 for (int total_order = 0; total_order <= 1; total_order++) {
483 for (int store_index_in_file = 0; store_index_in_file <= 1;
484 ++store_index_in_file) {
485 if (encoding_type == kPrefix && total_order) {
486 continue;
487 }
488 if (!bloom_bits && store_index_in_file) {
489 continue;
490 }
491 if (total_order && store_index_in_file) {
492 continue;
493 }
494 bool expect_bloom_not_match = false;
495 Options options = CurrentOptions();
496 options.create_if_missing = true;
497 // Set only one bucket to force bucket conflict.
498 // Test index interval for the same prefix to be 1, 2 and 4
499 PlainTableOptions plain_table_options;
500 if (total_order) {
501 options.prefix_extractor = nullptr;
502 plain_table_options.hash_table_ratio = 0;
503 plain_table_options.index_sparseness = 2;
504 } else {
505 plain_table_options.hash_table_ratio = 0.75;
506 plain_table_options.index_sparseness = 16;
507 }
508 plain_table_options.user_key_len = kPlainTableVariableLength;
509 plain_table_options.bloom_bits_per_key = bloom_bits;
510 plain_table_options.huge_page_tlb_size = huge_page_tlb_size;
511 plain_table_options.encoding_type = encoding_type;
512 plain_table_options.store_index_in_file = store_index_in_file;
513 options.table_factory.reset(new TestPlainTableFactory(
514 &expect_bloom_not_match, plain_table_options,
515 0 /* column_family_id */, kDefaultColumnFamilyName));
516
517 DestroyAndReopen(&options);
518 ASSERT_OK(Put("0000000000000bar", "b"));
519 ASSERT_OK(Put("1000000000000foo", "v1"));
520 dbfull()->TEST_FlushMemTable();
521
522 ASSERT_OK(Put("1000000000000foo", "v2"));
523 dbfull()->TEST_FlushMemTable();
524 ASSERT_EQ("v2", Get("1000000000000foo"));
525
526 ASSERT_OK(Put("0000000000000eee", "v3"));
527 dbfull()->TEST_FlushMemTable();
528 ASSERT_EQ("v3", Get("0000000000000eee"));
529
530 ASSERT_OK(Delete("0000000000000bar"));
531 dbfull()->TEST_FlushMemTable();
532 ASSERT_EQ("NOT_FOUND", Get("0000000000000bar"));
533
534 ASSERT_OK(Put("0000000000000eee", "v5"));
535 ASSERT_OK(Put("9000000000000eee", "v5"));
536 dbfull()->TEST_FlushMemTable();
537 ASSERT_EQ("v5", Get("0000000000000eee"));
538
539 // Test Bloom Filter
540 if (bloom_bits > 0) {
541 // Neither key nor value should exist.
542 expect_bloom_not_match = true;
543 ASSERT_EQ("NOT_FOUND", Get("5_not00000000bar"));
544 // Key doesn't exist any more but prefix exists.
545 if (total_order) {
546 ASSERT_EQ("NOT_FOUND", Get("1000000000000not"));
547 ASSERT_EQ("NOT_FOUND", Get("0000000000000not"));
548 }
549 expect_bloom_not_match = false;
550 }
551 }
552 }
553 }
554 }
555 }
556}
557
494da23a
TL
558TEST_P(PlainTableDBTest, Immortal) {
559 for (EncodingType encoding_type : {kPlain, kPrefix}) {
560 Options options = CurrentOptions();
561 options.create_if_missing = true;
562 options.max_open_files = -1;
563 // Set only one bucket to force bucket conflict.
564 // Test index interval for the same prefix to be 1, 2 and 4
565 PlainTableOptions plain_table_options;
566 plain_table_options.hash_table_ratio = 0.75;
567 plain_table_options.index_sparseness = 16;
568 plain_table_options.user_key_len = kPlainTableVariableLength;
569 plain_table_options.bloom_bits_per_key = 10;
570 plain_table_options.encoding_type = encoding_type;
571 options.table_factory.reset(NewPlainTableFactory(plain_table_options));
572
573 DestroyAndReopen(&options);
574 ASSERT_OK(Put("0000000000000bar", "b"));
575 ASSERT_OK(Put("1000000000000foo", "v1"));
576 dbfull()->TEST_FlushMemTable();
577
578 int copied = 0;
579 rocksdb::SyncPoint::GetInstance()->SetCallBack(
580 "GetContext::SaveValue::PinSelf", [&](void* /*arg*/) { copied++; });
581 rocksdb::SyncPoint::GetInstance()->EnableProcessing();
582 ASSERT_EQ("b", Get("0000000000000bar"));
583 ASSERT_EQ("v1", Get("1000000000000foo"));
584 ASSERT_EQ(2, copied);
585 copied = 0;
586
587 Close();
588 ASSERT_OK(ReopenForReadOnly(&options));
589
590 ASSERT_EQ("b", Get("0000000000000bar"));
591 ASSERT_EQ("v1", Get("1000000000000foo"));
592 ASSERT_EQ("NOT_FOUND", Get("1000000000000bar"));
593 if (mmap_mode()) {
594 ASSERT_EQ(0, copied);
595 } else {
596 ASSERT_EQ(2, copied);
597 }
598 rocksdb::SyncPoint::GetInstance()->DisableProcessing();
599 }
600}
601
7c673cae
FG
602TEST_P(PlainTableDBTest, Iterator) {
603 for (size_t huge_page_tlb_size = 0; huge_page_tlb_size <= 2 * 1024 * 1024;
604 huge_page_tlb_size += 2 * 1024 * 1024) {
605 for (EncodingType encoding_type : {kPlain, kPrefix}) {
606 for (int bloom_bits = 0; bloom_bits <= 117; bloom_bits += 117) {
607 for (int total_order = 0; total_order <= 1; total_order++) {
608 if (encoding_type == kPrefix && total_order == 1) {
609 continue;
610 }
611 bool expect_bloom_not_match = false;
612 Options options = CurrentOptions();
613 options.create_if_missing = true;
614 // Set only one bucket to force bucket conflict.
615 // Test index interval for the same prefix to be 1, 2 and 4
616 if (total_order) {
617 options.prefix_extractor = nullptr;
618
619 PlainTableOptions plain_table_options;
620 plain_table_options.user_key_len = 16;
621 plain_table_options.bloom_bits_per_key = bloom_bits;
622 plain_table_options.hash_table_ratio = 0;
623 plain_table_options.index_sparseness = 2;
624 plain_table_options.huge_page_tlb_size = huge_page_tlb_size;
625 plain_table_options.encoding_type = encoding_type;
626
627 options.table_factory.reset(new TestPlainTableFactory(
628 &expect_bloom_not_match, plain_table_options,
629 0 /* column_family_id */, kDefaultColumnFamilyName));
630 } else {
631 PlainTableOptions plain_table_options;
632 plain_table_options.user_key_len = 16;
633 plain_table_options.bloom_bits_per_key = bloom_bits;
634 plain_table_options.hash_table_ratio = 0.75;
635 plain_table_options.index_sparseness = 16;
636 plain_table_options.huge_page_tlb_size = huge_page_tlb_size;
637 plain_table_options.encoding_type = encoding_type;
638
639 options.table_factory.reset(new TestPlainTableFactory(
640 &expect_bloom_not_match, plain_table_options,
641 0 /* column_family_id */, kDefaultColumnFamilyName));
642 }
643 DestroyAndReopen(&options);
644
645 ASSERT_OK(Put("1000000000foo002", "v_2"));
646 ASSERT_OK(Put("0000000000000bar", "random"));
647 ASSERT_OK(Put("1000000000foo001", "v1"));
648 ASSERT_OK(Put("3000000000000bar", "bar_v"));
649 ASSERT_OK(Put("1000000000foo003", "v__3"));
650 ASSERT_OK(Put("1000000000foo004", "v__4"));
651 ASSERT_OK(Put("1000000000foo005", "v__5"));
652 ASSERT_OK(Put("1000000000foo007", "v__7"));
653 ASSERT_OK(Put("1000000000foo008", "v__8"));
654 dbfull()->TEST_FlushMemTable();
655 ASSERT_EQ("v1", Get("1000000000foo001"));
656 ASSERT_EQ("v__3", Get("1000000000foo003"));
657 Iterator* iter = dbfull()->NewIterator(ReadOptions());
658 iter->Seek("1000000000foo000");
659 ASSERT_TRUE(iter->Valid());
660 ASSERT_EQ("1000000000foo001", iter->key().ToString());
661 ASSERT_EQ("v1", iter->value().ToString());
662
663 iter->Next();
664 ASSERT_TRUE(iter->Valid());
665 ASSERT_EQ("1000000000foo002", iter->key().ToString());
666 ASSERT_EQ("v_2", iter->value().ToString());
667
668 iter->Next();
669 ASSERT_TRUE(iter->Valid());
670 ASSERT_EQ("1000000000foo003", iter->key().ToString());
671 ASSERT_EQ("v__3", iter->value().ToString());
672
673 iter->Next();
674 ASSERT_TRUE(iter->Valid());
675 ASSERT_EQ("1000000000foo004", iter->key().ToString());
676 ASSERT_EQ("v__4", iter->value().ToString());
677
678 iter->Seek("3000000000000bar");
679 ASSERT_TRUE(iter->Valid());
680 ASSERT_EQ("3000000000000bar", iter->key().ToString());
681 ASSERT_EQ("bar_v", iter->value().ToString());
682
683 iter->Seek("1000000000foo000");
684 ASSERT_TRUE(iter->Valid());
685 ASSERT_EQ("1000000000foo001", iter->key().ToString());
686 ASSERT_EQ("v1", iter->value().ToString());
687
688 iter->Seek("1000000000foo005");
689 ASSERT_TRUE(iter->Valid());
690 ASSERT_EQ("1000000000foo005", iter->key().ToString());
691 ASSERT_EQ("v__5", iter->value().ToString());
692
693 iter->Seek("1000000000foo006");
694 ASSERT_TRUE(iter->Valid());
695 ASSERT_EQ("1000000000foo007", iter->key().ToString());
696 ASSERT_EQ("v__7", iter->value().ToString());
697
698 iter->Seek("1000000000foo008");
699 ASSERT_TRUE(iter->Valid());
700 ASSERT_EQ("1000000000foo008", iter->key().ToString());
701 ASSERT_EQ("v__8", iter->value().ToString());
702
703 if (total_order == 0) {
704 iter->Seek("1000000000foo009");
705 ASSERT_TRUE(iter->Valid());
706 ASSERT_EQ("3000000000000bar", iter->key().ToString());
707 }
708
709 // Test Bloom Filter
710 if (bloom_bits > 0) {
711 if (!total_order) {
712 // Neither key nor value should exist.
713 expect_bloom_not_match = true;
714 iter->Seek("2not000000000bar");
715 ASSERT_TRUE(!iter->Valid());
716 ASSERT_EQ("NOT_FOUND", Get("2not000000000bar"));
717 expect_bloom_not_match = false;
718 } else {
719 expect_bloom_not_match = true;
720 ASSERT_EQ("NOT_FOUND", Get("2not000000000bar"));
721 expect_bloom_not_match = false;
722 }
723 }
724
725 delete iter;
726 }
727 }
728 }
729 }
730}
731
732namespace {
733std::string MakeLongKey(size_t length, char c) {
734 return std::string(length, c);
735}
736} // namespace
737
738TEST_P(PlainTableDBTest, IteratorLargeKeys) {
739 Options options = CurrentOptions();
740
741 PlainTableOptions plain_table_options;
742 plain_table_options.user_key_len = 0;
743 plain_table_options.bloom_bits_per_key = 0;
744 plain_table_options.hash_table_ratio = 0;
745
746 options.table_factory.reset(NewPlainTableFactory(plain_table_options));
747 options.create_if_missing = true;
748 options.prefix_extractor.reset();
749 DestroyAndReopen(&options);
750
751 std::string key_list[] = {
752 MakeLongKey(30, '0'),
753 MakeLongKey(16, '1'),
754 MakeLongKey(32, '2'),
755 MakeLongKey(60, '3'),
756 MakeLongKey(90, '4'),
757 MakeLongKey(50, '5'),
758 MakeLongKey(26, '6')
759 };
760
761 for (size_t i = 0; i < 7; i++) {
762 ASSERT_OK(Put(key_list[i], ToString(i)));
763 }
764
765 dbfull()->TEST_FlushMemTable();
766
767 Iterator* iter = dbfull()->NewIterator(ReadOptions());
768 iter->Seek(key_list[0]);
769
770 for (size_t i = 0; i < 7; i++) {
771 ASSERT_TRUE(iter->Valid());
772 ASSERT_EQ(key_list[i], iter->key().ToString());
773 ASSERT_EQ(ToString(i), iter->value().ToString());
774 iter->Next();
775 }
776
777 ASSERT_TRUE(!iter->Valid());
778
779 delete iter;
780}
781
782namespace {
783std::string MakeLongKeyWithPrefix(size_t length, char c) {
784 return "00000000" + std::string(length - 8, c);
785}
786} // namespace
787
788TEST_P(PlainTableDBTest, IteratorLargeKeysWithPrefix) {
789 Options options = CurrentOptions();
790
791 PlainTableOptions plain_table_options;
792 plain_table_options.user_key_len = 16;
793 plain_table_options.bloom_bits_per_key = 0;
794 plain_table_options.hash_table_ratio = 0.8;
795 plain_table_options.index_sparseness = 3;
796 plain_table_options.huge_page_tlb_size = 0;
797 plain_table_options.encoding_type = kPrefix;
798
799 options.table_factory.reset(NewPlainTableFactory(plain_table_options));
800 options.create_if_missing = true;
801 DestroyAndReopen(&options);
802
803 std::string key_list[] = {
804 MakeLongKeyWithPrefix(30, '0'), MakeLongKeyWithPrefix(16, '1'),
805 MakeLongKeyWithPrefix(32, '2'), MakeLongKeyWithPrefix(60, '3'),
806 MakeLongKeyWithPrefix(90, '4'), MakeLongKeyWithPrefix(50, '5'),
807 MakeLongKeyWithPrefix(26, '6')};
808
809 for (size_t i = 0; i < 7; i++) {
810 ASSERT_OK(Put(key_list[i], ToString(i)));
811 }
812
813 dbfull()->TEST_FlushMemTable();
814
815 Iterator* iter = dbfull()->NewIterator(ReadOptions());
816 iter->Seek(key_list[0]);
817
818 for (size_t i = 0; i < 7; i++) {
819 ASSERT_TRUE(iter->Valid());
820 ASSERT_EQ(key_list[i], iter->key().ToString());
821 ASSERT_EQ(ToString(i), iter->value().ToString());
822 iter->Next();
823 }
824
825 ASSERT_TRUE(!iter->Valid());
826
827 delete iter;
828}
829
830TEST_P(PlainTableDBTest, IteratorReverseSuffixComparator) {
831 Options options = CurrentOptions();
832 options.create_if_missing = true;
833 // Set only one bucket to force bucket conflict.
834 // Test index interval for the same prefix to be 1, 2 and 4
835 test::SimpleSuffixReverseComparator comp;
836 options.comparator = &comp;
837 DestroyAndReopen(&options);
838
839 ASSERT_OK(Put("1000000000foo002", "v_2"));
840 ASSERT_OK(Put("0000000000000bar", "random"));
841 ASSERT_OK(Put("1000000000foo001", "v1"));
842 ASSERT_OK(Put("3000000000000bar", "bar_v"));
843 ASSERT_OK(Put("1000000000foo003", "v__3"));
844 ASSERT_OK(Put("1000000000foo004", "v__4"));
845 ASSERT_OK(Put("1000000000foo005", "v__5"));
846 ASSERT_OK(Put("1000000000foo007", "v__7"));
847 ASSERT_OK(Put("1000000000foo008", "v__8"));
848 dbfull()->TEST_FlushMemTable();
849 ASSERT_EQ("v1", Get("1000000000foo001"));
850 ASSERT_EQ("v__3", Get("1000000000foo003"));
851 Iterator* iter = dbfull()->NewIterator(ReadOptions());
852 iter->Seek("1000000000foo009");
853 ASSERT_TRUE(iter->Valid());
854 ASSERT_EQ("1000000000foo008", iter->key().ToString());
855 ASSERT_EQ("v__8", iter->value().ToString());
856
857 iter->Next();
858 ASSERT_TRUE(iter->Valid());
859 ASSERT_EQ("1000000000foo007", iter->key().ToString());
860 ASSERT_EQ("v__7", iter->value().ToString());
861
862 iter->Next();
863 ASSERT_TRUE(iter->Valid());
864 ASSERT_EQ("1000000000foo005", iter->key().ToString());
865 ASSERT_EQ("v__5", iter->value().ToString());
866
867 iter->Next();
868 ASSERT_TRUE(iter->Valid());
869 ASSERT_EQ("1000000000foo004", iter->key().ToString());
870 ASSERT_EQ("v__4", iter->value().ToString());
871
872 iter->Seek("3000000000000bar");
873 ASSERT_TRUE(iter->Valid());
874 ASSERT_EQ("3000000000000bar", iter->key().ToString());
875 ASSERT_EQ("bar_v", iter->value().ToString());
876
877 iter->Seek("1000000000foo005");
878 ASSERT_TRUE(iter->Valid());
879 ASSERT_EQ("1000000000foo005", iter->key().ToString());
880 ASSERT_EQ("v__5", iter->value().ToString());
881
882 iter->Seek("1000000000foo006");
883 ASSERT_TRUE(iter->Valid());
884 ASSERT_EQ("1000000000foo005", iter->key().ToString());
885 ASSERT_EQ("v__5", iter->value().ToString());
886
887 iter->Seek("1000000000foo008");
888 ASSERT_TRUE(iter->Valid());
889 ASSERT_EQ("1000000000foo008", iter->key().ToString());
890 ASSERT_EQ("v__8", iter->value().ToString());
891
892 iter->Seek("1000000000foo000");
893 ASSERT_TRUE(iter->Valid());
894 ASSERT_EQ("3000000000000bar", iter->key().ToString());
895
896 delete iter;
897}
898
899TEST_P(PlainTableDBTest, HashBucketConflict) {
900 for (size_t huge_page_tlb_size = 0; huge_page_tlb_size <= 2 * 1024 * 1024;
901 huge_page_tlb_size += 2 * 1024 * 1024) {
902 for (unsigned char i = 1; i <= 3; i++) {
903 Options options = CurrentOptions();
904 options.create_if_missing = true;
905 // Set only one bucket to force bucket conflict.
906 // Test index interval for the same prefix to be 1, 2 and 4
907
908 PlainTableOptions plain_table_options;
909 plain_table_options.user_key_len = 16;
910 plain_table_options.bloom_bits_per_key = 0;
911 plain_table_options.hash_table_ratio = 0;
912 plain_table_options.index_sparseness = 2 ^ i;
913 plain_table_options.huge_page_tlb_size = huge_page_tlb_size;
914
915 options.table_factory.reset(NewPlainTableFactory(plain_table_options));
916
917 DestroyAndReopen(&options);
918 ASSERT_OK(Put("5000000000000fo0", "v1"));
919 ASSERT_OK(Put("5000000000000fo1", "v2"));
920 ASSERT_OK(Put("5000000000000fo2", "v"));
921 ASSERT_OK(Put("2000000000000fo0", "v3"));
922 ASSERT_OK(Put("2000000000000fo1", "v4"));
923 ASSERT_OK(Put("2000000000000fo2", "v"));
924 ASSERT_OK(Put("2000000000000fo3", "v"));
925
926 dbfull()->TEST_FlushMemTable();
927
928 ASSERT_EQ("v1", Get("5000000000000fo0"));
929 ASSERT_EQ("v2", Get("5000000000000fo1"));
930 ASSERT_EQ("v3", Get("2000000000000fo0"));
931 ASSERT_EQ("v4", Get("2000000000000fo1"));
932
933 ASSERT_EQ("NOT_FOUND", Get("5000000000000bar"));
934 ASSERT_EQ("NOT_FOUND", Get("2000000000000bar"));
935 ASSERT_EQ("NOT_FOUND", Get("5000000000000fo8"));
936 ASSERT_EQ("NOT_FOUND", Get("2000000000000fo8"));
937
938 ReadOptions ro;
939 Iterator* iter = dbfull()->NewIterator(ro);
940
941 iter->Seek("5000000000000fo0");
942 ASSERT_TRUE(iter->Valid());
943 ASSERT_EQ("5000000000000fo0", iter->key().ToString());
944 iter->Next();
945 ASSERT_TRUE(iter->Valid());
946 ASSERT_EQ("5000000000000fo1", iter->key().ToString());
947
948 iter->Seek("5000000000000fo1");
949 ASSERT_TRUE(iter->Valid());
950 ASSERT_EQ("5000000000000fo1", iter->key().ToString());
951
952 iter->Seek("2000000000000fo0");
953 ASSERT_TRUE(iter->Valid());
954 ASSERT_EQ("2000000000000fo0", iter->key().ToString());
955 iter->Next();
956 ASSERT_TRUE(iter->Valid());
957 ASSERT_EQ("2000000000000fo1", iter->key().ToString());
958
959 iter->Seek("2000000000000fo1");
960 ASSERT_TRUE(iter->Valid());
961 ASSERT_EQ("2000000000000fo1", iter->key().ToString());
962
963 iter->Seek("2000000000000bar");
964 ASSERT_TRUE(iter->Valid());
965 ASSERT_EQ("2000000000000fo0", iter->key().ToString());
966
967 iter->Seek("5000000000000bar");
968 ASSERT_TRUE(iter->Valid());
969 ASSERT_EQ("5000000000000fo0", iter->key().ToString());
970
971 iter->Seek("2000000000000fo8");
972 ASSERT_TRUE(!iter->Valid() ||
973 options.comparator->Compare(iter->key(), "20000001") > 0);
974
975 iter->Seek("5000000000000fo8");
976 ASSERT_TRUE(!iter->Valid());
977
978 iter->Seek("1000000000000fo2");
979 ASSERT_TRUE(!iter->Valid());
980
981 iter->Seek("3000000000000fo2");
982 ASSERT_TRUE(!iter->Valid());
983
984 iter->Seek("8000000000000fo2");
985 ASSERT_TRUE(!iter->Valid());
986
987 delete iter;
988 }
989 }
990}
991
992TEST_P(PlainTableDBTest, HashBucketConflictReverseSuffixComparator) {
993 for (size_t huge_page_tlb_size = 0; huge_page_tlb_size <= 2 * 1024 * 1024;
994 huge_page_tlb_size += 2 * 1024 * 1024) {
995 for (unsigned char i = 1; i <= 3; i++) {
996 Options options = CurrentOptions();
997 options.create_if_missing = true;
998 test::SimpleSuffixReverseComparator comp;
999 options.comparator = &comp;
1000 // Set only one bucket to force bucket conflict.
1001 // Test index interval for the same prefix to be 1, 2 and 4
1002
1003 PlainTableOptions plain_table_options;
1004 plain_table_options.user_key_len = 16;
1005 plain_table_options.bloom_bits_per_key = 0;
1006 plain_table_options.hash_table_ratio = 0;
1007 plain_table_options.index_sparseness = 2 ^ i;
1008 plain_table_options.huge_page_tlb_size = huge_page_tlb_size;
1009
1010 options.table_factory.reset(NewPlainTableFactory(plain_table_options));
1011 DestroyAndReopen(&options);
1012 ASSERT_OK(Put("5000000000000fo0", "v1"));
1013 ASSERT_OK(Put("5000000000000fo1", "v2"));
1014 ASSERT_OK(Put("5000000000000fo2", "v"));
1015 ASSERT_OK(Put("2000000000000fo0", "v3"));
1016 ASSERT_OK(Put("2000000000000fo1", "v4"));
1017 ASSERT_OK(Put("2000000000000fo2", "v"));
1018 ASSERT_OK(Put("2000000000000fo3", "v"));
1019
1020 dbfull()->TEST_FlushMemTable();
1021
1022 ASSERT_EQ("v1", Get("5000000000000fo0"));
1023 ASSERT_EQ("v2", Get("5000000000000fo1"));
1024 ASSERT_EQ("v3", Get("2000000000000fo0"));
1025 ASSERT_EQ("v4", Get("2000000000000fo1"));
1026
1027 ASSERT_EQ("NOT_FOUND", Get("5000000000000bar"));
1028 ASSERT_EQ("NOT_FOUND", Get("2000000000000bar"));
1029 ASSERT_EQ("NOT_FOUND", Get("5000000000000fo8"));
1030 ASSERT_EQ("NOT_FOUND", Get("2000000000000fo8"));
1031
1032 ReadOptions ro;
1033 Iterator* iter = dbfull()->NewIterator(ro);
1034
1035 iter->Seek("5000000000000fo1");
1036 ASSERT_TRUE(iter->Valid());
1037 ASSERT_EQ("5000000000000fo1", iter->key().ToString());
1038 iter->Next();
1039 ASSERT_TRUE(iter->Valid());
1040 ASSERT_EQ("5000000000000fo0", iter->key().ToString());
1041
1042 iter->Seek("5000000000000fo1");
1043 ASSERT_TRUE(iter->Valid());
1044 ASSERT_EQ("5000000000000fo1", iter->key().ToString());
1045
1046 iter->Seek("2000000000000fo1");
1047 ASSERT_TRUE(iter->Valid());
1048 ASSERT_EQ("2000000000000fo1", iter->key().ToString());
1049 iter->Next();
1050 ASSERT_TRUE(iter->Valid());
1051 ASSERT_EQ("2000000000000fo0", iter->key().ToString());
1052
1053 iter->Seek("2000000000000fo1");
1054 ASSERT_TRUE(iter->Valid());
1055 ASSERT_EQ("2000000000000fo1", iter->key().ToString());
1056
1057 iter->Seek("2000000000000var");
1058 ASSERT_TRUE(iter->Valid());
1059 ASSERT_EQ("2000000000000fo3", iter->key().ToString());
1060
1061 iter->Seek("5000000000000var");
1062 ASSERT_TRUE(iter->Valid());
1063 ASSERT_EQ("5000000000000fo2", iter->key().ToString());
1064
1065 std::string seek_key = "2000000000000bar";
1066 iter->Seek(seek_key);
1067 ASSERT_TRUE(!iter->Valid() ||
1068 options.prefix_extractor->Transform(iter->key()) !=
1069 options.prefix_extractor->Transform(seek_key));
1070
1071 iter->Seek("1000000000000fo2");
1072 ASSERT_TRUE(!iter->Valid());
1073
1074 iter->Seek("3000000000000fo2");
1075 ASSERT_TRUE(!iter->Valid());
1076
1077 iter->Seek("8000000000000fo2");
1078 ASSERT_TRUE(!iter->Valid());
1079
1080 delete iter;
1081 }
1082 }
1083}
1084
1085TEST_P(PlainTableDBTest, NonExistingKeyToNonEmptyBucket) {
1086 Options options = CurrentOptions();
1087 options.create_if_missing = true;
1088 // Set only one bucket to force bucket conflict.
1089 // Test index interval for the same prefix to be 1, 2 and 4
1090 PlainTableOptions plain_table_options;
1091 plain_table_options.user_key_len = 16;
1092 plain_table_options.bloom_bits_per_key = 0;
1093 plain_table_options.hash_table_ratio = 0;
1094 plain_table_options.index_sparseness = 5;
1095
1096 options.table_factory.reset(NewPlainTableFactory(plain_table_options));
1097 DestroyAndReopen(&options);
1098 ASSERT_OK(Put("5000000000000fo0", "v1"));
1099 ASSERT_OK(Put("5000000000000fo1", "v2"));
1100 ASSERT_OK(Put("5000000000000fo2", "v3"));
1101
1102 dbfull()->TEST_FlushMemTable();
1103
1104 ASSERT_EQ("v1", Get("5000000000000fo0"));
1105 ASSERT_EQ("v2", Get("5000000000000fo1"));
1106 ASSERT_EQ("v3", Get("5000000000000fo2"));
1107
1108 ASSERT_EQ("NOT_FOUND", Get("8000000000000bar"));
1109 ASSERT_EQ("NOT_FOUND", Get("1000000000000bar"));
1110
1111 Iterator* iter = dbfull()->NewIterator(ReadOptions());
1112
1113 iter->Seek("5000000000000bar");
1114 ASSERT_TRUE(iter->Valid());
1115 ASSERT_EQ("5000000000000fo0", iter->key().ToString());
1116
1117 iter->Seek("5000000000000fo8");
1118 ASSERT_TRUE(!iter->Valid());
1119
1120 iter->Seek("1000000000000fo2");
1121 ASSERT_TRUE(!iter->Valid());
1122
1123 iter->Seek("8000000000000fo2");
1124 ASSERT_TRUE(!iter->Valid());
1125
1126 delete iter;
1127}
1128
1129static std::string Key(int i) {
1130 char buf[100];
1131 snprintf(buf, sizeof(buf), "key_______%06d", i);
1132 return std::string(buf);
1133}
1134
1135static std::string RandomString(Random* rnd, int len) {
1136 std::string r;
1137 test::RandomString(rnd, len, &r);
1138 return r;
1139}
1140
1141TEST_P(PlainTableDBTest, CompactionTrigger) {
1142 Options options = CurrentOptions();
1143 options.write_buffer_size = 120 << 10; // 100KB
1144 options.num_levels = 3;
1145 options.level0_file_num_compaction_trigger = 3;
1146 Reopen(&options);
1147
1148 Random rnd(301);
1149
1150 for (int num = 0; num < options.level0_file_num_compaction_trigger - 1;
1151 num++) {
1152 std::vector<std::string> values;
1153 // Write 120KB (10 values, each 12K)
1154 for (int i = 0; i < 10; i++) {
1155 values.push_back(RandomString(&rnd, 12000));
1156 ASSERT_OK(Put(Key(i), values[i]));
1157 }
1158 ASSERT_OK(Put(Key(999), ""));
1159 dbfull()->TEST_WaitForFlushMemTable();
1160 ASSERT_EQ(NumTableFilesAtLevel(0), num + 1);
1161 }
1162
1163 //generate one more file in level-0, and should trigger level-0 compaction
1164 std::vector<std::string> values;
1165 for (int i = 0; i < 12; i++) {
1166 values.push_back(RandomString(&rnd, 10000));
1167 ASSERT_OK(Put(Key(i), values[i]));
1168 }
1169 ASSERT_OK(Put(Key(999), ""));
1170 dbfull()->TEST_WaitForCompact();
1171
1172 ASSERT_EQ(NumTableFilesAtLevel(0), 0);
1173 ASSERT_EQ(NumTableFilesAtLevel(1), 1);
1174}
1175
1176TEST_P(PlainTableDBTest, AdaptiveTable) {
1177 Options options = CurrentOptions();
1178 options.create_if_missing = true;
1179
1180 options.table_factory.reset(NewPlainTableFactory());
1181 DestroyAndReopen(&options);
1182
1183 ASSERT_OK(Put("1000000000000foo", "v1"));
1184 ASSERT_OK(Put("0000000000000bar", "v2"));
1185 ASSERT_OK(Put("1000000000000foo", "v3"));
1186 dbfull()->TEST_FlushMemTable();
1187
1188 options.create_if_missing = false;
1189 std::shared_ptr<TableFactory> dummy_factory;
1190 std::shared_ptr<TableFactory> block_based_factory(
1191 NewBlockBasedTableFactory());
1192 options.table_factory.reset(NewAdaptiveTableFactory(
1193 block_based_factory, dummy_factory, dummy_factory));
1194 Reopen(&options);
1195 ASSERT_EQ("v3", Get("1000000000000foo"));
1196 ASSERT_EQ("v2", Get("0000000000000bar"));
1197
1198 ASSERT_OK(Put("2000000000000foo", "v4"));
1199 ASSERT_OK(Put("3000000000000bar", "v5"));
1200 dbfull()->TEST_FlushMemTable();
1201 ASSERT_EQ("v4", Get("2000000000000foo"));
1202 ASSERT_EQ("v5", Get("3000000000000bar"));
1203
1204 Reopen(&options);
1205 ASSERT_EQ("v3", Get("1000000000000foo"));
1206 ASSERT_EQ("v2", Get("0000000000000bar"));
1207 ASSERT_EQ("v4", Get("2000000000000foo"));
1208 ASSERT_EQ("v5", Get("3000000000000bar"));
1209
1210 options.table_factory.reset(NewBlockBasedTableFactory());
1211 Reopen(&options);
1212 ASSERT_NE("v3", Get("1000000000000foo"));
1213
1214 options.table_factory.reset(NewPlainTableFactory());
1215 Reopen(&options);
1216 ASSERT_NE("v5", Get("3000000000000bar"));
1217}
1218
1219INSTANTIATE_TEST_CASE_P(PlainTableDBTest, PlainTableDBTest, ::testing::Bool());
1220
1221} // namespace rocksdb
1222
1223int main(int argc, char** argv) {
1224 ::testing::InitGoogleTest(&argc, argv);
1225 return RUN_ALL_TESTS();
1226}
1227
1228#else
1229#include <stdio.h>
1230
11fdf7f2 1231int main(int /*argc*/, char** /*argv*/) {
7c673cae
FG
1232 fprintf(stderr, "SKIPPED as plain table is not supported in ROCKSDB_LITE\n");
1233 return 0;
1234}
1235
1236#endif // !ROCKSDB_LITE