1 // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
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).
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.
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"
40 using std::unique_ptr
;
43 class PlainTableKeyDecoderTest
: public testing::Test
{};
45 TEST_F(PlainTableKeyDecoderTest
, ReadNonMmap
) {
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);
53 std::unique_ptr
<RandomAccessFileReader
> file_reader(
54 test::GetRandomAccessFileReader(string_source
));
55 std::unique_ptr
<PlainTableReaderFileInfo
> file_info(
56 new PlainTableReaderFileInfo(std::move(file_reader
), EnvOptions(),
60 PlainTableFileReader
reader(file_info
.get());
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
);
66 ASSERT_TRUE(reader
.Read(pos
, read_size
, &out
));
67 ASSERT_EQ(0, out
.compare(tmp
.substr(pos
, read_size
)));
70 ASSERT_LT(uint32_t(string_source
->total_reads()), kLength
/ kReadSize
/ 2);
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}},
84 std::vector
<int> num_file_reads
= {2, 6, 2, 2, 4, 3, 2, 2};
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
]) {
91 ASSERT_TRUE(reader
.Read(p
.first
, p
.second
, &out
));
92 ASSERT_EQ(0, out
.compare(tmp
.substr(p
.first
, p
.second
)));
94 ASSERT_EQ(num_file_reads
[i
], string_source
->total_reads());
98 class PlainTableDBTest
: public testing::Test
,
99 public testing::WithParamInterface
<bool> {
107 Options last_options_
;
110 PlainTableDBTest() : env_(Env::Default()) {}
112 ~PlainTableDBTest() override
{
114 EXPECT_OK(DestroyDB(dbname_
, Options()));
117 void SetUp() override
{
118 mmap_mode_
= GetParam();
119 dbname_
= test::PerThreadDBPath("plain_table_db_test");
120 EXPECT_OK(DestroyDB(dbname_
, Options()));
125 // Return the current option configuration.
126 Options
CurrentOptions() {
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;
139 options
.table_factory
.reset(NewPlainTableFactory(plain_table_options
));
140 options
.memtable_factory
.reset(NewHashLinkListRepFactory(4, 0, 3, true));
142 options
.prefix_extractor
.reset(NewFixedPrefixTransform(8));
143 options
.allow_mmap_reads
= mmap_mode_
;
144 options
.allow_concurrent_memtable_write
= false;
149 return reinterpret_cast<DBImpl
*>(db_
);
152 void Reopen(Options
* options
= nullptr) {
153 ASSERT_OK(TryReopen(options
));
161 bool mmap_mode() const { return mmap_mode_
; }
163 void DestroyAndReopen(Options
* options
= nullptr) {
164 //Destroy using last options
165 Destroy(&last_options_
);
166 ASSERT_OK(TryReopen(options
));
169 void Destroy(Options
* options
) {
172 ASSERT_OK(DestroyDB(dbname_
, *options
));
175 Status
PureReopen(Options
* options
, DB
** db
) {
176 return DB::Open(*options
, dbname_
, db
);
179 Status
ReopenForReadOnly(Options
* options
) {
182 return DB::OpenForReadOnly(*options
, dbname_
, &db_
);
185 Status
TryReopen(Options
* options
= nullptr) {
189 if (options
!= nullptr) {
192 opts
= CurrentOptions();
193 opts
.create_if_missing
= true;
195 last_options_
= opts
;
197 return DB::Open(opts
, dbname_
, &db_
);
200 Status
Put(const Slice
& k
, const Slice
& v
) {
201 return db_
->Put(WriteOptions(), k
, v
);
204 Status
Delete(const std::string
& k
) {
205 return db_
->Delete(WriteOptions(), k
);
208 std::string
Get(const std::string
& k
, const Snapshot
* snapshot
= nullptr) {
210 options
.snapshot
= snapshot
;
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();
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());
229 // Return spread of files per level
230 std::string
FilesPerLevel() {
232 size_t last_non_zero_offset
= 0;
233 for (int level
= 0; level
< db_
->NumberLevels(); level
++) {
234 int f
= NumTableFilesAtLevel(level
);
236 snprintf(buf
, sizeof(buf
), "%s%d", (level
? "," : ""), f
);
239 last_non_zero_offset
= result
.size();
242 result
.resize(last_non_zero_offset
);
246 std::string
IterStatus(Iterator
* iter
) {
249 result
= iter
->key().ToString() + "->" + iter
->value().ToString();
251 result
= "(invalid)";
257 TEST_P(PlainTableDBTest
, Empty
) {
258 ASSERT_TRUE(dbfull() != nullptr);
259 ASSERT_EQ("NOT_FOUND", Get("0000000000000foo"));
262 extern const uint64_t kPlainTableMagicNumber
;
264 class TestPlainTableReader
: public PlainTableReader
{
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
,
272 std::unique_ptr
<RandomAccessFileReader
>&& file
,
273 const ImmutableCFOptions
& ioptions
,
274 const SliceTransform
* prefix_extractor
,
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
,
279 encoding_type
, file_size
, table_properties
,
281 expect_bloom_not_match_(expect_bloom_not_match
) {
282 Status s
= MmapDataIfNeeded();
285 s
= PopulateIndex(const_cast<TableProperties
*>(table_properties
),
286 bloom_bits_per_key
, hash_table_ratio
, index_sparseness
,
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());
306 ~TestPlainTableReader() override
{}
309 bool MatchBloom(uint32_t hash
) const override
{
310 bool ret
= PlainTableReader::MatchBloom(hash
);
311 if (*expect_bloom_not_match_
) {
318 bool* expect_bloom_not_match_
;
321 extern const uint64_t kPlainTableMagicNumber
;
322 class TestPlainTableFactory
: public PlainTableFactory
{
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
)) {}
337 Status
NewTableReader(
338 const TableReaderOptions
& table_reader_options
,
339 std::unique_ptr
<RandomAccessFileReader
>&& file
, uint64_t file_size
,
340 std::unique_ptr
<TableReader
>* table
,
341 bool /*prefetch_index_and_filter_in_cache*/) const override
{
342 TableProperties
* props
= nullptr;
344 ReadTableProperties(file
.get(), file_size
, kPlainTableMagicNumber
,
345 table_reader_options
.ioptions
, &props
,
346 true /* compression_type_missing */);
349 if (store_index_in_file_
) {
350 BlockHandle bloom_block_handle
;
351 s
= FindMetaBlock(file
.get(), file_size
, kPlainTableMagicNumber
,
352 table_reader_options
.ioptions
,
353 BloomBlockBuilder::kBloomBlock
, &bloom_block_handle
,
354 /* compression_type_missing */ true);
357 BlockHandle index_block_handle
;
358 s
= FindMetaBlock(file
.get(), file_size
, kPlainTableMagicNumber
,
359 table_reader_options
.ioptions
,
360 PlainTableIndexBuilder::kPlainTableIndexBlock
,
361 &index_block_handle
, /* compression_type_missing */ true);
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()));
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
,
376 std::move(file
), table_reader_options
.ioptions
,
377 table_reader_options
.prefix_extractor
, expect_bloom_not_match_
,
378 store_index_in_file_
, column_family_id_
, column_family_name_
));
380 *table
= std::move(new_reader
);
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_
;
394 TEST_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
407 options
.prefix_extractor
.reset();
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
;
419 options
.table_factory
.reset(
420 NewPlainTableFactory(plain_table_options
));
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
;
432 options
.table_factory
.reset(
433 NewPlainTableFactory(plain_table_options
));
435 DestroyAndReopen(&options
);
437 ASSERT_TRUE(dbfull()->GetIntProperty(
438 "rocksdb.estimate-table-readers-mem", &int_num
));
439 ASSERT_EQ(int_num
, 0U);
441 ASSERT_OK(Put("1000000000000foo", "v1"));
442 ASSERT_OK(Put("0000000000000bar", "v2"));
443 ASSERT_OK(Put("1000000000000foo", "v3"));
444 dbfull()->TEST_FlushMemTable();
446 ASSERT_TRUE(dbfull()->GetIntProperty(
447 "rocksdb.estimate-table-readers-mem", &int_num
));
448 ASSERT_GT(int_num
, 0U);
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
;
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"));
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"));
468 ASSERT_EQ("v3", Get("1000000000000foo"));
469 ASSERT_EQ("v2", Get("0000000000000bar"));
477 TEST_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
) {
488 if (!bloom_bits
&& store_index_in_file
) {
491 if (total_order
&& store_index_in_file
) {
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
;
501 options
.prefix_extractor
= nullptr;
502 plain_table_options
.hash_table_ratio
= 0;
503 plain_table_options
.index_sparseness
= 2;
505 plain_table_options
.hash_table_ratio
= 0.75;
506 plain_table_options
.index_sparseness
= 16;
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
));
517 DestroyAndReopen(&options
);
518 ASSERT_OK(Put("0000000000000bar", "b"));
519 ASSERT_OK(Put("1000000000000foo", "v1"));
520 dbfull()->TEST_FlushMemTable();
522 ASSERT_OK(Put("1000000000000foo", "v2"));
523 dbfull()->TEST_FlushMemTable();
524 ASSERT_EQ("v2", Get("1000000000000foo"));
526 ASSERT_OK(Put("0000000000000eee", "v3"));
527 dbfull()->TEST_FlushMemTable();
528 ASSERT_EQ("v3", Get("0000000000000eee"));
530 ASSERT_OK(Delete("0000000000000bar"));
531 dbfull()->TEST_FlushMemTable();
532 ASSERT_EQ("NOT_FOUND", Get("0000000000000bar"));
534 ASSERT_OK(Put("0000000000000eee", "v5"));
535 ASSERT_OK(Put("9000000000000eee", "v5"));
536 dbfull()->TEST_FlushMemTable();
537 ASSERT_EQ("v5", Get("0000000000000eee"));
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.
546 ASSERT_EQ("NOT_FOUND", Get("1000000000000not"));
547 ASSERT_EQ("NOT_FOUND", Get("0000000000000not"));
549 expect_bloom_not_match
= false;
558 TEST_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
));
573 DestroyAndReopen(&options
);
574 ASSERT_OK(Put("0000000000000bar", "b"));
575 ASSERT_OK(Put("1000000000000foo", "v1"));
576 dbfull()->TEST_FlushMemTable();
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
);
588 ASSERT_OK(ReopenForReadOnly(&options
));
590 ASSERT_EQ("b", Get("0000000000000bar"));
591 ASSERT_EQ("v1", Get("1000000000000foo"));
592 ASSERT_EQ("NOT_FOUND", Get("1000000000000bar"));
594 ASSERT_EQ(0, copied
);
596 ASSERT_EQ(2, copied
);
598 rocksdb::SyncPoint::GetInstance()->DisableProcessing();
602 TEST_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) {
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
617 options
.prefix_extractor
= nullptr;
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
;
627 options
.table_factory
.reset(new TestPlainTableFactory(
628 &expect_bloom_not_match
, plain_table_options
,
629 0 /* column_family_id */, kDefaultColumnFamilyName
));
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
;
639 options
.table_factory
.reset(new TestPlainTableFactory(
640 &expect_bloom_not_match
, plain_table_options
,
641 0 /* column_family_id */, kDefaultColumnFamilyName
));
643 DestroyAndReopen(&options
);
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());
664 ASSERT_TRUE(iter
->Valid());
665 ASSERT_EQ("1000000000foo002", iter
->key().ToString());
666 ASSERT_EQ("v_2", iter
->value().ToString());
669 ASSERT_TRUE(iter
->Valid());
670 ASSERT_EQ("1000000000foo003", iter
->key().ToString());
671 ASSERT_EQ("v__3", iter
->value().ToString());
674 ASSERT_TRUE(iter
->Valid());
675 ASSERT_EQ("1000000000foo004", iter
->key().ToString());
676 ASSERT_EQ("v__4", iter
->value().ToString());
678 iter
->Seek("3000000000000bar");
679 ASSERT_TRUE(iter
->Valid());
680 ASSERT_EQ("3000000000000bar", iter
->key().ToString());
681 ASSERT_EQ("bar_v", iter
->value().ToString());
683 iter
->Seek("1000000000foo000");
684 ASSERT_TRUE(iter
->Valid());
685 ASSERT_EQ("1000000000foo001", iter
->key().ToString());
686 ASSERT_EQ("v1", iter
->value().ToString());
688 iter
->Seek("1000000000foo005");
689 ASSERT_TRUE(iter
->Valid());
690 ASSERT_EQ("1000000000foo005", iter
->key().ToString());
691 ASSERT_EQ("v__5", iter
->value().ToString());
693 iter
->Seek("1000000000foo006");
694 ASSERT_TRUE(iter
->Valid());
695 ASSERT_EQ("1000000000foo007", iter
->key().ToString());
696 ASSERT_EQ("v__7", iter
->value().ToString());
698 iter
->Seek("1000000000foo008");
699 ASSERT_TRUE(iter
->Valid());
700 ASSERT_EQ("1000000000foo008", iter
->key().ToString());
701 ASSERT_EQ("v__8", iter
->value().ToString());
703 if (total_order
== 0) {
704 iter
->Seek("1000000000foo009");
705 ASSERT_TRUE(iter
->Valid());
706 ASSERT_EQ("3000000000000bar", iter
->key().ToString());
710 if (bloom_bits
> 0) {
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;
719 expect_bloom_not_match
= true;
720 ASSERT_EQ("NOT_FOUND", Get("2not000000000bar"));
721 expect_bloom_not_match
= false;
733 std::string
MakeLongKey(size_t length
, char c
) {
734 return std::string(length
, c
);
738 TEST_P(PlainTableDBTest
, IteratorLargeKeys
) {
739 Options options
= CurrentOptions();
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;
746 options
.table_factory
.reset(NewPlainTableFactory(plain_table_options
));
747 options
.create_if_missing
= true;
748 options
.prefix_extractor
.reset();
749 DestroyAndReopen(&options
);
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'),
761 for (size_t i
= 0; i
< 7; i
++) {
762 ASSERT_OK(Put(key_list
[i
], ToString(i
)));
765 dbfull()->TEST_FlushMemTable();
767 Iterator
* iter
= dbfull()->NewIterator(ReadOptions());
768 iter
->Seek(key_list
[0]);
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());
777 ASSERT_TRUE(!iter
->Valid());
783 std::string
MakeLongKeyWithPrefix(size_t length
, char c
) {
784 return "00000000" + std::string(length
- 8, c
);
788 TEST_P(PlainTableDBTest
, IteratorLargeKeysWithPrefix
) {
789 Options options
= CurrentOptions();
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
;
799 options
.table_factory
.reset(NewPlainTableFactory(plain_table_options
));
800 options
.create_if_missing
= true;
801 DestroyAndReopen(&options
);
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')};
809 for (size_t i
= 0; i
< 7; i
++) {
810 ASSERT_OK(Put(key_list
[i
], ToString(i
)));
813 dbfull()->TEST_FlushMemTable();
815 Iterator
* iter
= dbfull()->NewIterator(ReadOptions());
816 iter
->Seek(key_list
[0]);
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());
825 ASSERT_TRUE(!iter
->Valid());
830 TEST_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
);
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());
858 ASSERT_TRUE(iter
->Valid());
859 ASSERT_EQ("1000000000foo007", iter
->key().ToString());
860 ASSERT_EQ("v__7", iter
->value().ToString());
863 ASSERT_TRUE(iter
->Valid());
864 ASSERT_EQ("1000000000foo005", iter
->key().ToString());
865 ASSERT_EQ("v__5", iter
->value().ToString());
868 ASSERT_TRUE(iter
->Valid());
869 ASSERT_EQ("1000000000foo004", iter
->key().ToString());
870 ASSERT_EQ("v__4", iter
->value().ToString());
872 iter
->Seek("3000000000000bar");
873 ASSERT_TRUE(iter
->Valid());
874 ASSERT_EQ("3000000000000bar", iter
->key().ToString());
875 ASSERT_EQ("bar_v", iter
->value().ToString());
877 iter
->Seek("1000000000foo005");
878 ASSERT_TRUE(iter
->Valid());
879 ASSERT_EQ("1000000000foo005", iter
->key().ToString());
880 ASSERT_EQ("v__5", iter
->value().ToString());
882 iter
->Seek("1000000000foo006");
883 ASSERT_TRUE(iter
->Valid());
884 ASSERT_EQ("1000000000foo005", iter
->key().ToString());
885 ASSERT_EQ("v__5", iter
->value().ToString());
887 iter
->Seek("1000000000foo008");
888 ASSERT_TRUE(iter
->Valid());
889 ASSERT_EQ("1000000000foo008", iter
->key().ToString());
890 ASSERT_EQ("v__8", iter
->value().ToString());
892 iter
->Seek("1000000000foo000");
893 ASSERT_TRUE(iter
->Valid());
894 ASSERT_EQ("3000000000000bar", iter
->key().ToString());
899 TEST_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
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
;
915 options
.table_factory
.reset(NewPlainTableFactory(plain_table_options
));
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"));
926 dbfull()->TEST_FlushMemTable();
928 ASSERT_EQ("v1", Get("5000000000000fo0"));
929 ASSERT_EQ("v2", Get("5000000000000fo1"));
930 ASSERT_EQ("v3", Get("2000000000000fo0"));
931 ASSERT_EQ("v4", Get("2000000000000fo1"));
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"));
939 Iterator
* iter
= dbfull()->NewIterator(ro
);
941 iter
->Seek("5000000000000fo0");
942 ASSERT_TRUE(iter
->Valid());
943 ASSERT_EQ("5000000000000fo0", iter
->key().ToString());
945 ASSERT_TRUE(iter
->Valid());
946 ASSERT_EQ("5000000000000fo1", iter
->key().ToString());
948 iter
->Seek("5000000000000fo1");
949 ASSERT_TRUE(iter
->Valid());
950 ASSERT_EQ("5000000000000fo1", iter
->key().ToString());
952 iter
->Seek("2000000000000fo0");
953 ASSERT_TRUE(iter
->Valid());
954 ASSERT_EQ("2000000000000fo0", iter
->key().ToString());
956 ASSERT_TRUE(iter
->Valid());
957 ASSERT_EQ("2000000000000fo1", iter
->key().ToString());
959 iter
->Seek("2000000000000fo1");
960 ASSERT_TRUE(iter
->Valid());
961 ASSERT_EQ("2000000000000fo1", iter
->key().ToString());
963 iter
->Seek("2000000000000bar");
964 ASSERT_TRUE(iter
->Valid());
965 ASSERT_EQ("2000000000000fo0", iter
->key().ToString());
967 iter
->Seek("5000000000000bar");
968 ASSERT_TRUE(iter
->Valid());
969 ASSERT_EQ("5000000000000fo0", iter
->key().ToString());
971 iter
->Seek("2000000000000fo8");
972 ASSERT_TRUE(!iter
->Valid() ||
973 options
.comparator
->Compare(iter
->key(), "20000001") > 0);
975 iter
->Seek("5000000000000fo8");
976 ASSERT_TRUE(!iter
->Valid());
978 iter
->Seek("1000000000000fo2");
979 ASSERT_TRUE(!iter
->Valid());
981 iter
->Seek("3000000000000fo2");
982 ASSERT_TRUE(!iter
->Valid());
984 iter
->Seek("8000000000000fo2");
985 ASSERT_TRUE(!iter
->Valid());
992 TEST_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
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
;
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"));
1020 dbfull()->TEST_FlushMemTable();
1022 ASSERT_EQ("v1", Get("5000000000000fo0"));
1023 ASSERT_EQ("v2", Get("5000000000000fo1"));
1024 ASSERT_EQ("v3", Get("2000000000000fo0"));
1025 ASSERT_EQ("v4", Get("2000000000000fo1"));
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"));
1033 Iterator
* iter
= dbfull()->NewIterator(ro
);
1035 iter
->Seek("5000000000000fo1");
1036 ASSERT_TRUE(iter
->Valid());
1037 ASSERT_EQ("5000000000000fo1", iter
->key().ToString());
1039 ASSERT_TRUE(iter
->Valid());
1040 ASSERT_EQ("5000000000000fo0", iter
->key().ToString());
1042 iter
->Seek("5000000000000fo1");
1043 ASSERT_TRUE(iter
->Valid());
1044 ASSERT_EQ("5000000000000fo1", iter
->key().ToString());
1046 iter
->Seek("2000000000000fo1");
1047 ASSERT_TRUE(iter
->Valid());
1048 ASSERT_EQ("2000000000000fo1", iter
->key().ToString());
1050 ASSERT_TRUE(iter
->Valid());
1051 ASSERT_EQ("2000000000000fo0", iter
->key().ToString());
1053 iter
->Seek("2000000000000fo1");
1054 ASSERT_TRUE(iter
->Valid());
1055 ASSERT_EQ("2000000000000fo1", iter
->key().ToString());
1057 iter
->Seek("2000000000000var");
1058 ASSERT_TRUE(iter
->Valid());
1059 ASSERT_EQ("2000000000000fo3", iter
->key().ToString());
1061 iter
->Seek("5000000000000var");
1062 ASSERT_TRUE(iter
->Valid());
1063 ASSERT_EQ("5000000000000fo2", iter
->key().ToString());
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
));
1071 iter
->Seek("1000000000000fo2");
1072 ASSERT_TRUE(!iter
->Valid());
1074 iter
->Seek("3000000000000fo2");
1075 ASSERT_TRUE(!iter
->Valid());
1077 iter
->Seek("8000000000000fo2");
1078 ASSERT_TRUE(!iter
->Valid());
1085 TEST_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;
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"));
1102 dbfull()->TEST_FlushMemTable();
1104 ASSERT_EQ("v1", Get("5000000000000fo0"));
1105 ASSERT_EQ("v2", Get("5000000000000fo1"));
1106 ASSERT_EQ("v3", Get("5000000000000fo2"));
1108 ASSERT_EQ("NOT_FOUND", Get("8000000000000bar"));
1109 ASSERT_EQ("NOT_FOUND", Get("1000000000000bar"));
1111 Iterator
* iter
= dbfull()->NewIterator(ReadOptions());
1113 iter
->Seek("5000000000000bar");
1114 ASSERT_TRUE(iter
->Valid());
1115 ASSERT_EQ("5000000000000fo0", iter
->key().ToString());
1117 iter
->Seek("5000000000000fo8");
1118 ASSERT_TRUE(!iter
->Valid());
1120 iter
->Seek("1000000000000fo2");
1121 ASSERT_TRUE(!iter
->Valid());
1123 iter
->Seek("8000000000000fo2");
1124 ASSERT_TRUE(!iter
->Valid());
1129 static std::string
Key(int i
) {
1131 snprintf(buf
, sizeof(buf
), "key_______%06d", i
);
1132 return std::string(buf
);
1135 static std::string
RandomString(Random
* rnd
, int len
) {
1137 test::RandomString(rnd
, len
, &r
);
1141 TEST_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;
1150 for (int num
= 0; num
< options
.level0_file_num_compaction_trigger
- 1;
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
]));
1158 ASSERT_OK(Put(Key(999), ""));
1159 dbfull()->TEST_WaitForFlushMemTable();
1160 ASSERT_EQ(NumTableFilesAtLevel(0), num
+ 1);
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
]));
1169 ASSERT_OK(Put(Key(999), ""));
1170 dbfull()->TEST_WaitForCompact();
1172 ASSERT_EQ(NumTableFilesAtLevel(0), 0);
1173 ASSERT_EQ(NumTableFilesAtLevel(1), 1);
1176 TEST_P(PlainTableDBTest
, AdaptiveTable
) {
1177 Options options
= CurrentOptions();
1178 options
.create_if_missing
= true;
1180 options
.table_factory
.reset(NewPlainTableFactory());
1181 DestroyAndReopen(&options
);
1183 ASSERT_OK(Put("1000000000000foo", "v1"));
1184 ASSERT_OK(Put("0000000000000bar", "v2"));
1185 ASSERT_OK(Put("1000000000000foo", "v3"));
1186 dbfull()->TEST_FlushMemTable();
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
));
1195 ASSERT_EQ("v3", Get("1000000000000foo"));
1196 ASSERT_EQ("v2", Get("0000000000000bar"));
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"));
1205 ASSERT_EQ("v3", Get("1000000000000foo"));
1206 ASSERT_EQ("v2", Get("0000000000000bar"));
1207 ASSERT_EQ("v4", Get("2000000000000foo"));
1208 ASSERT_EQ("v5", Get("3000000000000bar"));
1210 options
.table_factory
.reset(NewBlockBasedTableFactory());
1212 ASSERT_NE("v3", Get("1000000000000foo"));
1214 options
.table_factory
.reset(NewPlainTableFactory());
1216 ASSERT_NE("v5", Get("3000000000000bar"));
1219 INSTANTIATE_TEST_CASE_P(PlainTableDBTest
, PlainTableDBTest
, ::testing::Bool());
1221 } // namespace rocksdb
1223 int main(int argc
, char** argv
) {
1224 ::testing::InitGoogleTest(&argc
, argv
);
1225 return RUN_ALL_TESTS();
1231 int main(int /*argc*/, char** /*argv*/) {
1232 fprintf(stderr
, "SKIPPED as plain table is not supported in ROCKSDB_LITE\n");
1236 #endif // !ROCKSDB_LITE