plain_table_db_test.cc 41.7 KB
Newer Older
1
//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
S
Siying Dong 已提交
2 3 4
//  This source code is licensed under both the GPLv2 (found in the
//  COPYING file in the root directory) and Apache 2.0 License
//  (found in the LICENSE.Apache file in the root directory).
S
Siying Dong 已提交
5 6 7 8
//
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.
9 10 11

#ifndef ROCKSDB_LITE

S
Siying Dong 已提交
12 13 14 15 16 17 18 19
#include <algorithm>
#include <set>

#include "db/db_impl.h"
#include "db/version_set.h"
#include "db/write_batch_internal.h"
#include "rocksdb/cache.h"
#include "rocksdb/compaction_filter.h"
K
kailiu 已提交
20
#include "rocksdb/db.h"
S
Siying Dong 已提交
21
#include "rocksdb/env.h"
K
kailiu 已提交
22 23 24
#include "rocksdb/filter_policy.h"
#include "rocksdb/slice_transform.h"
#include "rocksdb/table.h"
25
#include "table/bloom_block.h"
26
#include "table/meta_blocks.h"
K
kailiu 已提交
27
#include "table/plain_table_factory.h"
28
#include "table/plain_table_key_coding.h"
29
#include "table/plain_table_reader.h"
30 31
#include "table/table_builder.h"
#include "util/filename.h"
S
Siying Dong 已提交
32 33 34
#include "util/hash.h"
#include "util/logging.h"
#include "util/mutexlock.h"
35
#include "util/string_util.h"
S
Siying Dong 已提交
36 37 38 39 40 41 42
#include "util/testharness.h"
#include "util/testutil.h"
#include "utilities/merge_operators.h"

using std::unique_ptr;

namespace rocksdb {
43 44 45 46 47 48 49 50 51 52
class PlainTableKeyDecoderTest : public testing::Test {};

TEST_F(PlainTableKeyDecoderTest, ReadNonMmap) {
  std::string tmp;
  Random rnd(301);
  const uint32_t kLength = 2222;
  Slice contents = test::RandomString(&rnd, kLength, &tmp);
  test::StringSource* string_source =
      new test::StringSource(contents, 0, false);

53
  std::unique_ptr<RandomAccessFileReader> file_reader(
54
      test::GetRandomAccessFileReader(string_source));
55 56 57
  std::unique_ptr<PlainTableReaderFileInfo> file_info(
      new PlainTableReaderFileInfo(std::move(file_reader), EnvOptions(),
                                   kLength));
58 59 60 61 62 63 64 65 66 67 68 69

  {
    PlainTableFileReader reader(file_info.get());

    const uint32_t kReadSize = 77;
    for (uint32_t pos = 0; pos < kLength; pos += kReadSize) {
      uint32_t read_size = std::min(kLength - pos, kReadSize);
      Slice out;
      ASSERT_TRUE(reader.Read(pos, read_size, &out));
      ASSERT_EQ(0, out.compare(tmp.substr(pos, read_size)));
    }

D
Dmitri Smirnov 已提交
70
    ASSERT_LT(uint32_t(string_source->total_reads()), kLength / kReadSize / 2);
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
  }

  std::vector<std::vector<std::pair<uint32_t, uint32_t>>> reads = {
      {{600, 30}, {590, 30}, {600, 20}, {600, 40}},
      {{800, 20}, {100, 20}, {500, 20}, {1500, 20}, {100, 20}, {80, 20}},
      {{1000, 20}, {500, 20}, {1000, 50}},
      {{1000, 20}, {500, 20}, {500, 20}},
      {{1000, 20}, {500, 20}, {200, 20}, {500, 20}},
      {{1000, 20}, {500, 20}, {200, 20}, {1000, 50}},
      {{600, 500}, {610, 20}, {100, 20}},
      {{500, 100}, {490, 100}, {550, 50}},
  };

  std::vector<int> num_file_reads = {2, 6, 2, 2, 4, 3, 2, 2};

  for (size_t i = 0; i < reads.size(); i++) {
    string_source->set_total_reads(0);
    PlainTableFileReader reader(file_info.get());
    for (auto p : reads[i]) {
      Slice out;
      ASSERT_TRUE(reader.Read(p.first, p.second, &out));
      ASSERT_EQ(0, out.compare(tmp.substr(p.first, p.second)));
    }
    ASSERT_EQ(num_file_reads[i], string_source->total_reads());
  }
}
S
Siying Dong 已提交
97

98 99
class PlainTableDBTest : public testing::Test,
                         public testing::WithParamInterface<bool> {
K
Kai Liu 已提交
100 101
 protected:
 private:
S
Siying Dong 已提交
102 103 104 105
  std::string dbname_;
  Env* env_;
  DB* db_;

106
  bool mmap_mode_;
S
Siying Dong 已提交
107 108
  Options last_options_;

K
Kai Liu 已提交
109
 public:
110
  PlainTableDBTest() : env_(Env::Default()) {}
S
Siying Dong 已提交
111

112
  ~PlainTableDBTest() override {
S
Siying Dong 已提交
113
    delete db_;
114
    EXPECT_OK(DestroyDB(dbname_, Options()));
S
Siying Dong 已提交
115 116
  }

117 118
  void SetUp() override {
    mmap_mode_ = GetParam();
119
    dbname_ = test::PerThreadDBPath("plain_table_db_test");
120 121 122 123 124
    EXPECT_OK(DestroyDB(dbname_, Options()));
    db_ = nullptr;
    Reopen();
  }

S
Siying Dong 已提交
125 126 127
  // Return the current option configuration.
  Options CurrentOptions() {
    Options options;
S
Stanislau Hlebik 已提交
128 129 130 131 132 133 134 135 136

    PlainTableOptions plain_table_options;
    plain_table_options.user_key_len = 0;
    plain_table_options.bloom_bits_per_key = 2;
    plain_table_options.hash_table_ratio = 0.8;
    plain_table_options.index_sparseness = 3;
    plain_table_options.huge_page_tlb_size = 0;
    plain_table_options.encoding_type = kPrefix;
    plain_table_options.full_scan_mode = false;
137
    plain_table_options.store_index_in_file = false;
S
Stanislau Hlebik 已提交
138 139

    options.table_factory.reset(NewPlainTableFactory(plain_table_options));
140
    options.memtable_factory.reset(NewHashLinkListRepFactory(4, 0, 3, true));
S
Stanislau Hlebik 已提交
141

142
    options.prefix_extractor.reset(NewFixedPrefixTransform(8));
143
    options.allow_mmap_reads = mmap_mode_;
144
    options.allow_concurrent_memtable_write = false;
S
Siying Dong 已提交
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
    return options;
  }

  DBImpl* dbfull() {
    return reinterpret_cast<DBImpl*>(db_);
  }

  void Reopen(Options* options = nullptr) {
    ASSERT_OK(TryReopen(options));
  }

  void Close() {
    delete db_;
    db_ = nullptr;
  }

161 162
  bool mmap_mode() const { return mmap_mode_; }

S
Siying Dong 已提交
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
  void DestroyAndReopen(Options* options = nullptr) {
    //Destroy using last options
    Destroy(&last_options_);
    ASSERT_OK(TryReopen(options));
  }

  void Destroy(Options* options) {
    delete db_;
    db_ = nullptr;
    ASSERT_OK(DestroyDB(dbname_, *options));
  }

  Status PureReopen(Options* options, DB** db) {
    return DB::Open(*options, dbname_, db);
  }

179 180 181 182 183 184
  Status ReopenForReadOnly(Options* options) {
    delete db_;
    db_ = nullptr;
    return DB::OpenForReadOnly(*options, dbname_, &db_);
  }

S
Siying Dong 已提交
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
  Status TryReopen(Options* options = nullptr) {
    delete db_;
    db_ = nullptr;
    Options opts;
    if (options != nullptr) {
      opts = *options;
    } else {
      opts = CurrentOptions();
      opts.create_if_missing = true;
    }
    last_options_ = opts;

    return DB::Open(opts, dbname_, &db_);
  }

  Status Put(const Slice& k, const Slice& v) {
    return db_->Put(WriteOptions(), k, v);
  }

  Status Delete(const std::string& k) {
    return db_->Delete(WriteOptions(), k);
  }

  std::string Get(const std::string& k, const Snapshot* snapshot = nullptr) {
209
    ReadOptions options;
S
Siying Dong 已提交
210 211 212 213 214 215 216 217 218 219 220 221 222 223
    options.snapshot = snapshot;
    std::string result;
    Status s = db_->Get(options, k, &result);
    if (s.IsNotFound()) {
      result = "NOT_FOUND";
    } else if (!s.ok()) {
      result = s.ToString();
    }
    return result;
  }


  int NumTableFilesAtLevel(int level) {
    std::string property;
224 225
    EXPECT_TRUE(db_->GetProperty(
        "rocksdb.num-files-at-level" + NumberToString(level), &property));
S
Siying Dong 已提交
226 227 228 229 230 231
    return atoi(property.c_str());
  }

  // Return spread of files per level
  std::string FilesPerLevel() {
    std::string result;
232
    size_t last_non_zero_offset = 0;
S
Siying Dong 已提交
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
    for (int level = 0; level < db_->NumberLevels(); level++) {
      int f = NumTableFilesAtLevel(level);
      char buf[100];
      snprintf(buf, sizeof(buf), "%s%d", (level ? "," : ""), f);
      result += buf;
      if (f > 0) {
        last_non_zero_offset = result.size();
      }
    }
    result.resize(last_non_zero_offset);
    return result;
  }

  std::string IterStatus(Iterator* iter) {
    std::string result;
    if (iter->Valid()) {
      result = iter->key().ToString() + "->" + iter->value().ToString();
    } else {
      result = "(invalid)";
    }
    return result;
  }
};

257
TEST_P(PlainTableDBTest, Empty) {
K
Kai Liu 已提交
258
  ASSERT_TRUE(dbfull() != nullptr);
S
Siying Dong 已提交
259 260 261
  ASSERT_EQ("NOT_FOUND", Get("0000000000000foo"));
}

262 263
extern const uint64_t kPlainTableMagicNumber;

264 265
class TestPlainTableReader : public PlainTableReader {
 public:
L
Lei Jin 已提交
266
  TestPlainTableReader(const EnvOptions& env_options,
267
                       const InternalKeyComparator& icomparator,
268 269 270
                       EncodingType encoding_type, uint64_t file_size,
                       int bloom_bits_per_key, double hash_table_ratio,
                       size_t index_sparseness,
271
                       const TableProperties* table_properties,
272
                       std::unique_ptr<RandomAccessFileReader>&& file,
L
Lei Jin 已提交
273
                       const ImmutableCFOptions& ioptions,
274
                       const SliceTransform* prefix_extractor,
275 276
                       bool* expect_bloom_not_match, bool store_index_in_file,
                       uint32_t column_family_id,
277
                       const std::string& column_family_name)
L
Lei Jin 已提交
278
      : PlainTableReader(ioptions, std::move(file), env_options, icomparator,
279 280
                         encoding_type, file_size, table_properties,
                         prefix_extractor),
281
        expect_bloom_not_match_(expect_bloom_not_match) {
282
    Status s = MmapDataIfNeeded();
283
    EXPECT_TRUE(s.ok());
284 285 286 287

    s = PopulateIndex(const_cast<TableProperties*>(table_properties),
                      bloom_bits_per_key, hash_table_ratio, index_sparseness,
                      2 * 1024 * 1024);
288
    EXPECT_TRUE(s.ok());
289 290

    TableProperties* props = const_cast<TableProperties*>(table_properties);
291 292
    EXPECT_EQ(column_family_id, static_cast<uint32_t>(props->column_family_id));
    EXPECT_EQ(column_family_name, props->column_family_name);
293 294 295 296 297 298 299 300 301 302 303
    if (store_index_in_file) {
      auto bloom_version_ptr = props->user_collected_properties.find(
          PlainTablePropertyNames::kBloomVersion);
      EXPECT_TRUE(bloom_version_ptr != props->user_collected_properties.end());
      EXPECT_EQ(bloom_version_ptr->second, std::string("1"));
      if (ioptions.bloom_locality > 0) {
        auto num_blocks_ptr = props->user_collected_properties.find(
            PlainTablePropertyNames::kNumBloomBlocks);
        EXPECT_TRUE(num_blocks_ptr != props->user_collected_properties.end());
      }
    }
304 305
  }

306
  ~TestPlainTableReader() override {}
307 308

 private:
309
  bool MatchBloom(uint32_t hash) const override {
310
    bool ret = PlainTableReader::MatchBloom(hash);
311
    if (*expect_bloom_not_match_) {
312
      EXPECT_TRUE(!ret);
313
    } else {
314
      EXPECT_TRUE(ret);
315
    }
316 317 318 319 320 321 322 323 324
    return ret;
  }
  bool* expect_bloom_not_match_;
};

extern const uint64_t kPlainTableMagicNumber;
class TestPlainTableFactory : public PlainTableFactory {
 public:
  explicit TestPlainTableFactory(bool* expect_bloom_not_match,
325 326 327
                                 const PlainTableOptions& options,
                                 uint32_t column_family_id,
                                 std::string column_family_name)
S
Stanislau Hlebik 已提交
328 329 330 331
      : PlainTableFactory(options),
        bloom_bits_per_key_(options.bloom_bits_per_key),
        hash_table_ratio_(options.hash_table_ratio),
        index_sparseness_(options.index_sparseness),
332
        store_index_in_file_(options.store_index_in_file),
333 334 335
        expect_bloom_not_match_(expect_bloom_not_match),
        column_family_id_(column_family_id),
        column_family_name_(std::move(column_family_name)) {}
336

337 338
  Status NewTableReader(
      const TableReaderOptions& table_reader_options,
339 340
      std::unique_ptr<RandomAccessFileReader>&& file, uint64_t file_size,
      std::unique_ptr<TableReader>* table,
A
Andrew Kryczka 已提交
341
      bool /*prefetch_index_and_filter_in_cache*/) const override {
342
    TableProperties* props = nullptr;
343 344
    auto s =
        ReadTableProperties(file.get(), file_size, kPlainTableMagicNumber,
345 346
                            table_reader_options.ioptions, &props,
                            true /* compression_type_missing */);
347
    EXPECT_TRUE(s.ok());
348

349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
    if (store_index_in_file_) {
      BlockHandle bloom_block_handle;
      s = FindMetaBlock(file.get(), file_size, kPlainTableMagicNumber,
                        table_reader_options.ioptions,
                        BloomBlockBuilder::kBloomBlock, &bloom_block_handle,
                        /* compression_type_missing */ true);
      EXPECT_TRUE(s.ok());

      BlockHandle index_block_handle;
      s = FindMetaBlock(file.get(), file_size, kPlainTableMagicNumber,
                        table_reader_options.ioptions,
                        PlainTableIndexBuilder::kPlainTableIndexBlock,
                        &index_block_handle, /* compression_type_missing */ true);
      EXPECT_TRUE(s.ok());
    }

365 366 367 368 369 370 371
    auto& user_props = props->user_collected_properties;
    auto encoding_type_prop =
        user_props.find(PlainTablePropertyNames::kEncodingType);
    assert(encoding_type_prop != user_props.end());
    EncodingType encoding_type = static_cast<EncodingType>(
        DecodeFixed32(encoding_type_prop->second.c_str()));

372
    std::unique_ptr<PlainTableReader> new_reader(new TestPlainTableReader(
373 374
        table_reader_options.env_options,
        table_reader_options.internal_comparator, encoding_type, file_size,
375
        bloom_bits_per_key_, hash_table_ratio_, index_sparseness_, props,
376 377
        std::move(file), table_reader_options.ioptions,
        table_reader_options.prefix_extractor, expect_bloom_not_match_,
378
        store_index_in_file_, column_family_id_, column_family_name_));
379 380 381 382 383 384 385 386 387

    *table = std::move(new_reader);
    return s;
  }

 private:
  int bloom_bits_per_key_;
  double hash_table_ratio_;
  size_t index_sparseness_;
388
  bool store_index_in_file_;
389
  bool* expect_bloom_not_match_;
390 391
  const uint32_t column_family_id_;
  const std::string column_family_name_;
392
};
S
Siying Dong 已提交
393

394
TEST_P(PlainTableDBTest, Flush) {
395 396
  for (size_t huge_page_tlb_size = 0; huge_page_tlb_size <= 2 * 1024 * 1024;
       huge_page_tlb_size += 2 * 1024 * 1024) {
397
    for (EncodingType encoding_type : {kPlain, kPrefix}) {
398 399 400 401
    for (int bloom_bits = 0; bloom_bits <= 117; bloom_bits += 117) {
      for (int total_order = 0; total_order <= 1; total_order++) {
        for (int store_index_in_file = 0; store_index_in_file <= 1;
             ++store_index_in_file) {
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
          Options options = CurrentOptions();
          options.create_if_missing = true;
          // Set only one bucket to force bucket conflict.
          // Test index interval for the same prefix to be 1, 2 and 4
          if (total_order) {
            options.prefix_extractor.reset();

            PlainTableOptions plain_table_options;
            plain_table_options.user_key_len = 0;
            plain_table_options.bloom_bits_per_key = bloom_bits;
            plain_table_options.hash_table_ratio = 0;
            plain_table_options.index_sparseness = 2;
            plain_table_options.huge_page_tlb_size = huge_page_tlb_size;
            plain_table_options.encoding_type = encoding_type;
            plain_table_options.full_scan_mode = false;
417
            plain_table_options.store_index_in_file = store_index_in_file;
418 419 420 421 422 423 424 425 426 427 428 429

            options.table_factory.reset(
                NewPlainTableFactory(plain_table_options));
          } else {
            PlainTableOptions plain_table_options;
            plain_table_options.user_key_len = 0;
            plain_table_options.bloom_bits_per_key = bloom_bits;
            plain_table_options.hash_table_ratio = 0.75;
            plain_table_options.index_sparseness = 16;
            plain_table_options.huge_page_tlb_size = huge_page_tlb_size;
            plain_table_options.encoding_type = encoding_type;
            plain_table_options.full_scan_mode = false;
430
            plain_table_options.store_index_in_file = store_index_in_file;
431 432 433 434 435

            options.table_factory.reset(
                NewPlainTableFactory(plain_table_options));
          }
          DestroyAndReopen(&options);
436 437 438 439 440
          uint64_t int_num;
          ASSERT_TRUE(dbfull()->GetIntProperty(
              "rocksdb.estimate-table-readers-mem", &int_num));
          ASSERT_EQ(int_num, 0U);

441 442 443 444 445
          ASSERT_OK(Put("1000000000000foo", "v1"));
          ASSERT_OK(Put("0000000000000bar", "v2"));
          ASSERT_OK(Put("1000000000000foo", "v3"));
          dbfull()->TEST_FlushMemTable();

446 447 448 449
          ASSERT_TRUE(dbfull()->GetIntProperty(
              "rocksdb.estimate-table-readers-mem", &int_num));
          ASSERT_GT(int_num, 0U);

450 451 452 453 454 455
          TablePropertiesCollection ptc;
          reinterpret_cast<DB*>(dbfull())->GetPropertiesOfAllTables(&ptc);
          ASSERT_EQ(1U, ptc.size());
          auto row = ptc.begin();
          auto tp = row->second;

456 457 458 459 460 461 462 463 464 465 466 467
          if (!store_index_in_file) {
            ASSERT_EQ(total_order ? "4" : "12",
                      (tp->user_collected_properties)
                          .at("plain_table_hash_table_size"));
            ASSERT_EQ("0", (tp->user_collected_properties)
                               .at("plain_table_sub_index_size"));
          } else {
            ASSERT_EQ("0", (tp->user_collected_properties)
                               .at("plain_table_hash_table_size"));
            ASSERT_EQ("0", (tp->user_collected_properties)
                               .at("plain_table_sub_index_size"));
          }
468 469 470
          ASSERT_EQ("v3", Get("1000000000000foo"));
          ASSERT_EQ("v2", Get("0000000000000bar"));
        }
471
        }
472 473 474 475 476
      }
    }
  }
}

477
TEST_P(PlainTableDBTest, Flush2) {
478 479
  for (size_t huge_page_tlb_size = 0; huge_page_tlb_size <= 2 * 1024 * 1024;
       huge_page_tlb_size += 2 * 1024 * 1024) {
480
    for (EncodingType encoding_type : {kPlain, kPrefix}) {
481 482 483 484
    for (int bloom_bits = 0; bloom_bits <= 117; bloom_bits += 117) {
      for (int total_order = 0; total_order <= 1; total_order++) {
        for (int store_index_in_file = 0; store_index_in_file <= 1;
             ++store_index_in_file) {
485 486 487
          if (encoding_type == kPrefix && total_order) {
            continue;
          }
488 489 490 491 492 493
          if (!bloom_bits && store_index_in_file) {
            continue;
          }
          if (total_order && store_index_in_file) {
          continue;
        }
494 495 496 497 498
        bool expect_bloom_not_match = false;
        Options options = CurrentOptions();
        options.create_if_missing = true;
        // Set only one bucket to force bucket conflict.
        // 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;
S
Stanislau Hlebik 已提交
502 503
          plain_table_options.hash_table_ratio = 0;
          plain_table_options.index_sparseness = 2;
504
        } else {
S
Stanislau Hlebik 已提交
505 506
          plain_table_options.hash_table_ratio = 0.75;
          plain_table_options.index_sparseness = 16;
507
        }
508 509 510 511
        plain_table_options.user_key_len = kPlainTableVariableLength;
        plain_table_options.bloom_bits_per_key = bloom_bits;
        plain_table_options.huge_page_tlb_size = huge_page_tlb_size;
        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 515
            &expect_bloom_not_match, plain_table_options,
            0 /* column_family_id */, kDefaultColumnFamilyName));
516

517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549
        DestroyAndReopen(&options);
        ASSERT_OK(Put("0000000000000bar", "b"));
        ASSERT_OK(Put("1000000000000foo", "v1"));
        dbfull()->TEST_FlushMemTable();

        ASSERT_OK(Put("1000000000000foo", "v2"));
        dbfull()->TEST_FlushMemTable();
        ASSERT_EQ("v2", Get("1000000000000foo"));

        ASSERT_OK(Put("0000000000000eee", "v3"));
        dbfull()->TEST_FlushMemTable();
        ASSERT_EQ("v3", Get("0000000000000eee"));

        ASSERT_OK(Delete("0000000000000bar"));
        dbfull()->TEST_FlushMemTable();
        ASSERT_EQ("NOT_FOUND", Get("0000000000000bar"));

        ASSERT_OK(Put("0000000000000eee", "v5"));
        ASSERT_OK(Put("9000000000000eee", "v5"));
        dbfull()->TEST_FlushMemTable();
        ASSERT_EQ("v5", Get("0000000000000eee"));

        // Test Bloom Filter
        if (bloom_bits > 0) {
          // Neither key nor value should exist.
          expect_bloom_not_match = true;
          ASSERT_EQ("NOT_FOUND", Get("5_not00000000bar"));
          // Key doesn't exist any more but prefix exists.
          if (total_order) {
            ASSERT_EQ("NOT_FOUND", Get("1000000000000not"));
            ASSERT_EQ("NOT_FOUND", Get("0000000000000not"));
          }
          expect_bloom_not_match = false;
550 551
        }
      }
552 553
      }
    }
554
    }
555
  }
S
Siying Dong 已提交
556 557
}

558
TEST_P(PlainTableDBTest, Immortal) {
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
  for (EncodingType encoding_type : {kPlain, kPrefix}) {
    Options options = CurrentOptions();
    options.create_if_missing = true;
    options.max_open_files = -1;
    // Set only one bucket to force bucket conflict.
    // Test index interval for the same prefix to be 1, 2 and 4
    PlainTableOptions plain_table_options;
    plain_table_options.hash_table_ratio = 0.75;
    plain_table_options.index_sparseness = 16;
    plain_table_options.user_key_len = kPlainTableVariableLength;
    plain_table_options.bloom_bits_per_key = 10;
    plain_table_options.encoding_type = encoding_type;
    options.table_factory.reset(NewPlainTableFactory(plain_table_options));

    DestroyAndReopen(&options);
    ASSERT_OK(Put("0000000000000bar", "b"));
    ASSERT_OK(Put("1000000000000foo", "v1"));
    dbfull()->TEST_FlushMemTable();

    int copied = 0;
    rocksdb::SyncPoint::GetInstance()->SetCallBack(
        "GetContext::SaveValue::PinSelf", [&](void* /*arg*/) { copied++; });
    rocksdb::SyncPoint::GetInstance()->EnableProcessing();
    ASSERT_EQ("b", Get("0000000000000bar"));
    ASSERT_EQ("v1", Get("1000000000000foo"));
    ASSERT_EQ(2, copied);
    copied = 0;

    Close();
    ASSERT_OK(ReopenForReadOnly(&options));

    ASSERT_EQ("b", Get("0000000000000bar"));
    ASSERT_EQ("v1", Get("1000000000000foo"));
    ASSERT_EQ("NOT_FOUND", Get("1000000000000bar"));
    if (mmap_mode()) {
      ASSERT_EQ(0, copied);
    } else {
      ASSERT_EQ(2, copied);
    }
    rocksdb::SyncPoint::GetInstance()->DisableProcessing();
  }
}

602
TEST_P(PlainTableDBTest, Iterator) {
603 604
  for (size_t huge_page_tlb_size = 0; huge_page_tlb_size <= 2 * 1024 * 1024;
       huge_page_tlb_size += 2 * 1024 * 1024) {
605
    for (EncodingType encoding_type : {kPlain, kPrefix}) {
606 607
    for (int bloom_bits = 0; bloom_bits <= 117; bloom_bits += 117) {
      for (int total_order = 0; total_order <= 1; total_order++) {
608 609 610
        if (encoding_type == kPrefix && total_order == 1) {
          continue;
        }
611 612 613 614 615 616 617
        bool expect_bloom_not_match = false;
        Options options = CurrentOptions();
        options.create_if_missing = true;
        // Set only one bucket to force bucket conflict.
        // Test index interval for the same prefix to be 1, 2 and 4
        if (total_order) {
          options.prefix_extractor = nullptr;
S
Stanislau Hlebik 已提交
618 619 620 621 622 623 624 625 626

          PlainTableOptions plain_table_options;
          plain_table_options.user_key_len = 16;
          plain_table_options.bloom_bits_per_key = bloom_bits;
          plain_table_options.hash_table_ratio = 0;
          plain_table_options.index_sparseness = 2;
          plain_table_options.huge_page_tlb_size = huge_page_tlb_size;
          plain_table_options.encoding_type = encoding_type;

627
          options.table_factory.reset(new TestPlainTableFactory(
628 629
              &expect_bloom_not_match, plain_table_options,
              0 /* column_family_id */, kDefaultColumnFamilyName));
630
        } else {
S
Stanislau Hlebik 已提交
631 632 633 634 635 636 637 638
          PlainTableOptions plain_table_options;
          plain_table_options.user_key_len = 16;
          plain_table_options.bloom_bits_per_key = bloom_bits;
          plain_table_options.hash_table_ratio = 0.75;
          plain_table_options.index_sparseness = 16;
          plain_table_options.huge_page_tlb_size = huge_page_tlb_size;
          plain_table_options.encoding_type = encoding_type;

639
          options.table_factory.reset(new TestPlainTableFactory(
640 641
              &expect_bloom_not_match, plain_table_options,
              0 /* column_family_id */, kDefaultColumnFamilyName));
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
        }
        DestroyAndReopen(&options);

        ASSERT_OK(Put("1000000000foo002", "v_2"));
        ASSERT_OK(Put("0000000000000bar", "random"));
        ASSERT_OK(Put("1000000000foo001", "v1"));
        ASSERT_OK(Put("3000000000000bar", "bar_v"));
        ASSERT_OK(Put("1000000000foo003", "v__3"));
        ASSERT_OK(Put("1000000000foo004", "v__4"));
        ASSERT_OK(Put("1000000000foo005", "v__5"));
        ASSERT_OK(Put("1000000000foo007", "v__7"));
        ASSERT_OK(Put("1000000000foo008", "v__8"));
        dbfull()->TEST_FlushMemTable();
        ASSERT_EQ("v1", Get("1000000000foo001"));
        ASSERT_EQ("v__3", Get("1000000000foo003"));
        Iterator* iter = dbfull()->NewIterator(ReadOptions());
        iter->Seek("1000000000foo000");
        ASSERT_TRUE(iter->Valid());
        ASSERT_EQ("1000000000foo001", iter->key().ToString());
        ASSERT_EQ("v1", iter->value().ToString());
662

663 664 665 666
        iter->Next();
        ASSERT_TRUE(iter->Valid());
        ASSERT_EQ("1000000000foo002", iter->key().ToString());
        ASSERT_EQ("v_2", iter->value().ToString());
667

668 669 670 671
        iter->Next();
        ASSERT_TRUE(iter->Valid());
        ASSERT_EQ("1000000000foo003", iter->key().ToString());
        ASSERT_EQ("v__3", iter->value().ToString());
672

673 674 675 676
        iter->Next();
        ASSERT_TRUE(iter->Valid());
        ASSERT_EQ("1000000000foo004", iter->key().ToString());
        ASSERT_EQ("v__4", iter->value().ToString());
677

678 679 680 681
        iter->Seek("3000000000000bar");
        ASSERT_TRUE(iter->Valid());
        ASSERT_EQ("3000000000000bar", iter->key().ToString());
        ASSERT_EQ("bar_v", iter->value().ToString());
682

683 684 685 686
        iter->Seek("1000000000foo000");
        ASSERT_TRUE(iter->Valid());
        ASSERT_EQ("1000000000foo001", iter->key().ToString());
        ASSERT_EQ("v1", iter->value().ToString());
687

688 689 690 691
        iter->Seek("1000000000foo005");
        ASSERT_TRUE(iter->Valid());
        ASSERT_EQ("1000000000foo005", iter->key().ToString());
        ASSERT_EQ("v__5", iter->value().ToString());
692

693 694 695 696
        iter->Seek("1000000000foo006");
        ASSERT_TRUE(iter->Valid());
        ASSERT_EQ("1000000000foo007", iter->key().ToString());
        ASSERT_EQ("v__7", iter->value().ToString());
697

698
        iter->Seek("1000000000foo008");
699
        ASSERT_TRUE(iter->Valid());
700 701
        ASSERT_EQ("1000000000foo008", iter->key().ToString());
        ASSERT_EQ("v__8", iter->value().ToString());
702

703 704 705 706
        if (total_order == 0) {
          iter->Seek("1000000000foo009");
          ASSERT_TRUE(iter->Valid());
          ASSERT_EQ("3000000000000bar", iter->key().ToString());
707 708
        }

709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
        // Test Bloom Filter
        if (bloom_bits > 0) {
          if (!total_order) {
            // Neither key nor value should exist.
            expect_bloom_not_match = true;
            iter->Seek("2not000000000bar");
            ASSERT_TRUE(!iter->Valid());
            ASSERT_EQ("NOT_FOUND", Get("2not000000000bar"));
            expect_bloom_not_match = false;
          } else {
            expect_bloom_not_match = true;
            ASSERT_EQ("NOT_FOUND", Get("2not000000000bar"));
            expect_bloom_not_match = false;
          }
        }

        delete iter;
      }
727
    }
728
    }
729 730 731
  }
}

I
Igor Canadi 已提交
732
namespace {
733 734 735
std::string MakeLongKey(size_t length, char c) {
  return std::string(length, c);
}
I
Igor Canadi 已提交
736
}  // namespace
737

738
TEST_P(PlainTableDBTest, IteratorLargeKeys) {
739
  Options options = CurrentOptions();
S
Stanislau Hlebik 已提交
740 741 742 743 744 745 746

  PlainTableOptions plain_table_options;
  plain_table_options.user_key_len = 0;
  plain_table_options.bloom_bits_per_key = 0;
  plain_table_options.hash_table_ratio = 0;

  options.table_factory.reset(NewPlainTableFactory(plain_table_options));
747 748 749 750 751 752 753 754 755 756 757 758 759 760 761
  options.create_if_missing = true;
  options.prefix_extractor.reset();
  DestroyAndReopen(&options);

  std::string key_list[] = {
      MakeLongKey(30, '0'),
      MakeLongKey(16, '1'),
      MakeLongKey(32, '2'),
      MakeLongKey(60, '3'),
      MakeLongKey(90, '4'),
      MakeLongKey(50, '5'),
      MakeLongKey(26, '6')
  };

  for (size_t i = 0; i < 7; i++) {
762
    ASSERT_OK(Put(key_list[i], ToString(i)));
763 764 765 766
  }

  dbfull()->TEST_FlushMemTable();

767
  Iterator* iter = dbfull()->NewIterator(ReadOptions());
768 769 770 771 772
  iter->Seek(key_list[0]);

  for (size_t i = 0; i < 7; i++) {
    ASSERT_TRUE(iter->Valid());
    ASSERT_EQ(key_list[i], iter->key().ToString());
773
    ASSERT_EQ(ToString(i), iter->value().ToString());
774 775 776 777 778 779 780 781
    iter->Next();
  }

  ASSERT_TRUE(!iter->Valid());

  delete iter;
}

782 783 784 785 786 787
namespace {
std::string MakeLongKeyWithPrefix(size_t length, char c) {
  return "00000000" + std::string(length - 8, c);
}
}  // namespace

788
TEST_P(PlainTableDBTest, IteratorLargeKeysWithPrefix) {
789
  Options options = CurrentOptions();
S
Stanislau Hlebik 已提交
790 791 792 793 794 795 796 797 798 799

  PlainTableOptions plain_table_options;
  plain_table_options.user_key_len = 16;
  plain_table_options.bloom_bits_per_key = 0;
  plain_table_options.hash_table_ratio = 0.8;
  plain_table_options.index_sparseness = 3;
  plain_table_options.huge_page_tlb_size = 0;
  plain_table_options.encoding_type = kPrefix;

  options.table_factory.reset(NewPlainTableFactory(plain_table_options));
800 801 802 803 804 805 806 807 808 809
  options.create_if_missing = true;
  DestroyAndReopen(&options);

  std::string key_list[] = {
      MakeLongKeyWithPrefix(30, '0'), MakeLongKeyWithPrefix(16, '1'),
      MakeLongKeyWithPrefix(32, '2'), MakeLongKeyWithPrefix(60, '3'),
      MakeLongKeyWithPrefix(90, '4'), MakeLongKeyWithPrefix(50, '5'),
      MakeLongKeyWithPrefix(26, '6')};

  for (size_t i = 0; i < 7; i++) {
810
    ASSERT_OK(Put(key_list[i], ToString(i)));
811 812 813 814 815 816 817 818 819 820
  }

  dbfull()->TEST_FlushMemTable();

  Iterator* iter = dbfull()->NewIterator(ReadOptions());
  iter->Seek(key_list[0]);

  for (size_t i = 0; i < 7; i++) {
    ASSERT_TRUE(iter->Valid());
    ASSERT_EQ(key_list[i], iter->key().ToString());
821
    ASSERT_EQ(ToString(i), iter->value().ToString());
822 823 824 825 826 827 828 829
    iter->Next();
  }

  ASSERT_TRUE(!iter->Valid());

  delete iter;
}

830
TEST_P(PlainTableDBTest, IteratorReverseSuffixComparator) {
831 832 833 834
  Options options = CurrentOptions();
  options.create_if_missing = true;
  // Set only one bucket to force bucket conflict.
  // Test index interval for the same prefix to be 1, 2 and 4
835
  test::SimpleSuffixReverseComparator comp;
836 837 838
  options.comparator = &comp;
  DestroyAndReopen(&options);

S
Siying Dong 已提交
839 840 841 842 843 844 845 846 847 848 849 850
  ASSERT_OK(Put("1000000000foo002", "v_2"));
  ASSERT_OK(Put("0000000000000bar", "random"));
  ASSERT_OK(Put("1000000000foo001", "v1"));
  ASSERT_OK(Put("3000000000000bar", "bar_v"));
  ASSERT_OK(Put("1000000000foo003", "v__3"));
  ASSERT_OK(Put("1000000000foo004", "v__4"));
  ASSERT_OK(Put("1000000000foo005", "v__5"));
  ASSERT_OK(Put("1000000000foo007", "v__7"));
  ASSERT_OK(Put("1000000000foo008", "v__8"));
  dbfull()->TEST_FlushMemTable();
  ASSERT_EQ("v1", Get("1000000000foo001"));
  ASSERT_EQ("v__3", Get("1000000000foo003"));
851
  Iterator* iter = dbfull()->NewIterator(ReadOptions());
852
  iter->Seek("1000000000foo009");
S
Siying Dong 已提交
853
  ASSERT_TRUE(iter->Valid());
854 855
  ASSERT_EQ("1000000000foo008", iter->key().ToString());
  ASSERT_EQ("v__8", iter->value().ToString());
S
Siying Dong 已提交
856 857 858

  iter->Next();
  ASSERT_TRUE(iter->Valid());
859 860
  ASSERT_EQ("1000000000foo007", iter->key().ToString());
  ASSERT_EQ("v__7", iter->value().ToString());
S
Siying Dong 已提交
861 862 863

  iter->Next();
  ASSERT_TRUE(iter->Valid());
864 865
  ASSERT_EQ("1000000000foo005", iter->key().ToString());
  ASSERT_EQ("v__5", iter->value().ToString());
S
Siying Dong 已提交
866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883

  iter->Next();
  ASSERT_TRUE(iter->Valid());
  ASSERT_EQ("1000000000foo004", iter->key().ToString());
  ASSERT_EQ("v__4", iter->value().ToString());

  iter->Seek("3000000000000bar");
  ASSERT_TRUE(iter->Valid());
  ASSERT_EQ("3000000000000bar", iter->key().ToString());
  ASSERT_EQ("bar_v", iter->value().ToString());

  iter->Seek("1000000000foo005");
  ASSERT_TRUE(iter->Valid());
  ASSERT_EQ("1000000000foo005", iter->key().ToString());
  ASSERT_EQ("v__5", iter->value().ToString());

  iter->Seek("1000000000foo006");
  ASSERT_TRUE(iter->Valid());
884 885
  ASSERT_EQ("1000000000foo005", iter->key().ToString());
  ASSERT_EQ("v__5", iter->value().ToString());
S
Siying Dong 已提交
886 887 888 889 890 891

  iter->Seek("1000000000foo008");
  ASSERT_TRUE(iter->Valid());
  ASSERT_EQ("1000000000foo008", iter->key().ToString());
  ASSERT_EQ("v__8", iter->value().ToString());

892
  iter->Seek("1000000000foo000");
S
Siying Dong 已提交
893 894 895 896 897 898
  ASSERT_TRUE(iter->Valid());
  ASSERT_EQ("3000000000000bar", iter->key().ToString());

  delete iter;
}

899
TEST_P(PlainTableDBTest, HashBucketConflict) {
900 901 902 903 904 905 906
  for (size_t huge_page_tlb_size = 0; huge_page_tlb_size <= 2 * 1024 * 1024;
       huge_page_tlb_size += 2 * 1024 * 1024) {
    for (unsigned char i = 1; i <= 3; i++) {
      Options options = CurrentOptions();
      options.create_if_missing = true;
      // Set only one bucket to force bucket conflict.
      // Test index interval for the same prefix to be 1, 2 and 4
S
Stanislau Hlebik 已提交
907 908 909 910 911 912 913 914 915 916

      PlainTableOptions plain_table_options;
      plain_table_options.user_key_len = 16;
      plain_table_options.bloom_bits_per_key = 0;
      plain_table_options.hash_table_ratio = 0;
      plain_table_options.index_sparseness = 2 ^ i;
      plain_table_options.huge_page_tlb_size = huge_page_tlb_size;

      options.table_factory.reset(NewPlainTableFactory(plain_table_options));

917 918 919 920 921 922 923 924
      DestroyAndReopen(&options);
      ASSERT_OK(Put("5000000000000fo0", "v1"));
      ASSERT_OK(Put("5000000000000fo1", "v2"));
      ASSERT_OK(Put("5000000000000fo2", "v"));
      ASSERT_OK(Put("2000000000000fo0", "v3"));
      ASSERT_OK(Put("2000000000000fo1", "v4"));
      ASSERT_OK(Put("2000000000000fo2", "v"));
      ASSERT_OK(Put("2000000000000fo3", "v"));
925

926
      dbfull()->TEST_FlushMemTable();
927

928 929 930 931
      ASSERT_EQ("v1", Get("5000000000000fo0"));
      ASSERT_EQ("v2", Get("5000000000000fo1"));
      ASSERT_EQ("v3", Get("2000000000000fo0"));
      ASSERT_EQ("v4", Get("2000000000000fo1"));
932

933 934 935 936
      ASSERT_EQ("NOT_FOUND", Get("5000000000000bar"));
      ASSERT_EQ("NOT_FOUND", Get("2000000000000bar"));
      ASSERT_EQ("NOT_FOUND", Get("5000000000000fo8"));
      ASSERT_EQ("NOT_FOUND", Get("2000000000000fo8"));
937

938 939
      ReadOptions ro;
      Iterator* iter = dbfull()->NewIterator(ro);
940

941 942 943 944 945 946 947 948 949 950
      iter->Seek("5000000000000fo0");
      ASSERT_TRUE(iter->Valid());
      ASSERT_EQ("5000000000000fo0", iter->key().ToString());
      iter->Next();
      ASSERT_TRUE(iter->Valid());
      ASSERT_EQ("5000000000000fo1", iter->key().ToString());

      iter->Seek("5000000000000fo1");
      ASSERT_TRUE(iter->Valid());
      ASSERT_EQ("5000000000000fo1", iter->key().ToString());
951

952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969
      iter->Seek("2000000000000fo0");
      ASSERT_TRUE(iter->Valid());
      ASSERT_EQ("2000000000000fo0", iter->key().ToString());
      iter->Next();
      ASSERT_TRUE(iter->Valid());
      ASSERT_EQ("2000000000000fo1", iter->key().ToString());

      iter->Seek("2000000000000fo1");
      ASSERT_TRUE(iter->Valid());
      ASSERT_EQ("2000000000000fo1", iter->key().ToString());

      iter->Seek("2000000000000bar");
      ASSERT_TRUE(iter->Valid());
      ASSERT_EQ("2000000000000fo0", iter->key().ToString());

      iter->Seek("5000000000000bar");
      ASSERT_TRUE(iter->Valid());
      ASSERT_EQ("5000000000000fo0", iter->key().ToString());
970

971 972 973
      iter->Seek("2000000000000fo8");
      ASSERT_TRUE(!iter->Valid() ||
                  options.comparator->Compare(iter->key(), "20000001") > 0);
974

975 976
      iter->Seek("5000000000000fo8");
      ASSERT_TRUE(!iter->Valid());
977

978 979
      iter->Seek("1000000000000fo2");
      ASSERT_TRUE(!iter->Valid());
980

981 982
      iter->Seek("3000000000000fo2");
      ASSERT_TRUE(!iter->Valid());
983

984 985 986 987 988
      iter->Seek("8000000000000fo2");
      ASSERT_TRUE(!iter->Valid());

      delete iter;
    }
989 990
  }
}
S
Siying Dong 已提交
991

992
TEST_P(PlainTableDBTest, HashBucketConflictReverseSuffixComparator) {
993 994 995 996 997
  for (size_t huge_page_tlb_size = 0; huge_page_tlb_size <= 2 * 1024 * 1024;
       huge_page_tlb_size += 2 * 1024 * 1024) {
    for (unsigned char i = 1; i <= 3; i++) {
      Options options = CurrentOptions();
      options.create_if_missing = true;
998
      test::SimpleSuffixReverseComparator comp;
999 1000 1001
      options.comparator = &comp;
      // Set only one bucket to force bucket conflict.
      // Test index interval for the same prefix to be 1, 2 and 4
S
Stanislau Hlebik 已提交
1002 1003 1004 1005 1006 1007 1008 1009 1010

      PlainTableOptions plain_table_options;
      plain_table_options.user_key_len = 16;
      plain_table_options.bloom_bits_per_key = 0;
      plain_table_options.hash_table_ratio = 0;
      plain_table_options.index_sparseness = 2 ^ i;
      plain_table_options.huge_page_tlb_size = huge_page_tlb_size;

      options.table_factory.reset(NewPlainTableFactory(plain_table_options));
1011 1012 1013 1014 1015 1016 1017 1018
      DestroyAndReopen(&options);
      ASSERT_OK(Put("5000000000000fo0", "v1"));
      ASSERT_OK(Put("5000000000000fo1", "v2"));
      ASSERT_OK(Put("5000000000000fo2", "v"));
      ASSERT_OK(Put("2000000000000fo0", "v3"));
      ASSERT_OK(Put("2000000000000fo1", "v4"));
      ASSERT_OK(Put("2000000000000fo2", "v"));
      ASSERT_OK(Put("2000000000000fo3", "v"));
1019

1020
      dbfull()->TEST_FlushMemTable();
1021

1022 1023 1024 1025
      ASSERT_EQ("v1", Get("5000000000000fo0"));
      ASSERT_EQ("v2", Get("5000000000000fo1"));
      ASSERT_EQ("v3", Get("2000000000000fo0"));
      ASSERT_EQ("v4", Get("2000000000000fo1"));
1026

1027 1028 1029 1030
      ASSERT_EQ("NOT_FOUND", Get("5000000000000bar"));
      ASSERT_EQ("NOT_FOUND", Get("2000000000000bar"));
      ASSERT_EQ("NOT_FOUND", Get("5000000000000fo8"));
      ASSERT_EQ("NOT_FOUND", Get("2000000000000fo8"));
1031

1032 1033
      ReadOptions ro;
      Iterator* iter = dbfull()->NewIterator(ro);
1034

1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051
      iter->Seek("5000000000000fo1");
      ASSERT_TRUE(iter->Valid());
      ASSERT_EQ("5000000000000fo1", iter->key().ToString());
      iter->Next();
      ASSERT_TRUE(iter->Valid());
      ASSERT_EQ("5000000000000fo0", iter->key().ToString());

      iter->Seek("5000000000000fo1");
      ASSERT_TRUE(iter->Valid());
      ASSERT_EQ("5000000000000fo1", iter->key().ToString());

      iter->Seek("2000000000000fo1");
      ASSERT_TRUE(iter->Valid());
      ASSERT_EQ("2000000000000fo1", iter->key().ToString());
      iter->Next();
      ASSERT_TRUE(iter->Valid());
      ASSERT_EQ("2000000000000fo0", iter->key().ToString());
1052

1053 1054 1055
      iter->Seek("2000000000000fo1");
      ASSERT_TRUE(iter->Valid());
      ASSERT_EQ("2000000000000fo1", iter->key().ToString());
1056

1057 1058 1059 1060 1061 1062 1063
      iter->Seek("2000000000000var");
      ASSERT_TRUE(iter->Valid());
      ASSERT_EQ("2000000000000fo3", iter->key().ToString());

      iter->Seek("5000000000000var");
      ASSERT_TRUE(iter->Valid());
      ASSERT_EQ("5000000000000fo2", iter->key().ToString());
1064

1065 1066 1067 1068 1069
      std::string seek_key = "2000000000000bar";
      iter->Seek(seek_key);
      ASSERT_TRUE(!iter->Valid() ||
                  options.prefix_extractor->Transform(iter->key()) !=
                      options.prefix_extractor->Transform(seek_key));
1070

1071 1072
      iter->Seek("1000000000000fo2");
      ASSERT_TRUE(!iter->Valid());
1073

1074 1075 1076 1077 1078 1079 1080 1081
      iter->Seek("3000000000000fo2");
      ASSERT_TRUE(!iter->Valid());

      iter->Seek("8000000000000fo2");
      ASSERT_TRUE(!iter->Valid());

      delete iter;
    }
1082 1083
  }
}
S
Siying Dong 已提交
1084

1085
TEST_P(PlainTableDBTest, NonExistingKeyToNonEmptyBucket) {
1086 1087 1088 1089
  Options options = CurrentOptions();
  options.create_if_missing = true;
  // Set only one bucket to force bucket conflict.
  // Test index interval for the same prefix to be 1, 2 and 4
S
Stanislau Hlebik 已提交
1090 1091 1092 1093 1094 1095 1096
  PlainTableOptions plain_table_options;
  plain_table_options.user_key_len = 16;
  plain_table_options.bloom_bits_per_key = 0;
  plain_table_options.hash_table_ratio = 0;
  plain_table_options.index_sparseness = 5;

  options.table_factory.reset(NewPlainTableFactory(plain_table_options));
1097 1098 1099 1100
  DestroyAndReopen(&options);
  ASSERT_OK(Put("5000000000000fo0", "v1"));
  ASSERT_OK(Put("5000000000000fo1", "v2"));
  ASSERT_OK(Put("5000000000000fo2", "v3"));
S
Siying Dong 已提交
1101 1102 1103

  dbfull()->TEST_FlushMemTable();

1104 1105 1106 1107 1108 1109 1110
  ASSERT_EQ("v1", Get("5000000000000fo0"));
  ASSERT_EQ("v2", Get("5000000000000fo1"));
  ASSERT_EQ("v3", Get("5000000000000fo2"));

  ASSERT_EQ("NOT_FOUND", Get("8000000000000bar"));
  ASSERT_EQ("NOT_FOUND", Get("1000000000000bar"));

1111
  Iterator* iter = dbfull()->NewIterator(ReadOptions());
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126

  iter->Seek("5000000000000bar");
  ASSERT_TRUE(iter->Valid());
  ASSERT_EQ("5000000000000fo0", iter->key().ToString());

  iter->Seek("5000000000000fo8");
  ASSERT_TRUE(!iter->Valid());

  iter->Seek("1000000000000fo2");
  ASSERT_TRUE(!iter->Valid());

  iter->Seek("8000000000000fo2");
  ASSERT_TRUE(!iter->Valid());

  delete iter;
S
Siying Dong 已提交
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140
}

static std::string Key(int i) {
  char buf[100];
  snprintf(buf, sizeof(buf), "key_______%06d", i);
  return std::string(buf);
}

static std::string RandomString(Random* rnd, int len) {
  std::string r;
  test::RandomString(rnd, len, &r);
  return r;
}

1141
TEST_P(PlainTableDBTest, CompactionTrigger) {
S
Siying Dong 已提交
1142
  Options options = CurrentOptions();
1143
  options.write_buffer_size = 120 << 10;  // 100KB
S
Siying Dong 已提交
1144 1145 1146 1147 1148 1149 1150 1151 1152
  options.num_levels = 3;
  options.level0_file_num_compaction_trigger = 3;
  Reopen(&options);

  Random rnd(301);

  for (int num = 0; num < options.level0_file_num_compaction_trigger - 1;
      num++) {
    std::vector<std::string> values;
1153 1154 1155
    // Write 120KB (10 values, each 12K)
    for (int i = 0; i < 10; i++) {
      values.push_back(RandomString(&rnd, 12000));
S
Siying Dong 已提交
1156 1157
      ASSERT_OK(Put(Key(i), values[i]));
    }
1158
    ASSERT_OK(Put(Key(999), ""));
S
Siying Dong 已提交
1159 1160 1161 1162 1163 1164 1165 1166 1167 1168
    dbfull()->TEST_WaitForFlushMemTable();
    ASSERT_EQ(NumTableFilesAtLevel(0), num + 1);
  }

  //generate one more file in level-0, and should trigger level-0 compaction
  std::vector<std::string> values;
  for (int i = 0; i < 12; i++) {
    values.push_back(RandomString(&rnd, 10000));
    ASSERT_OK(Put(Key(i), values[i]));
  }
1169
  ASSERT_OK(Put(Key(999), ""));
S
Siying Dong 已提交
1170 1171 1172 1173 1174 1175
  dbfull()->TEST_WaitForCompact();

  ASSERT_EQ(NumTableFilesAtLevel(0), 0);
  ASSERT_EQ(NumTableFilesAtLevel(1), 1);
}

1176
TEST_P(PlainTableDBTest, AdaptiveTable) {
1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189
  Options options = CurrentOptions();
  options.create_if_missing = true;

  options.table_factory.reset(NewPlainTableFactory());
  DestroyAndReopen(&options);

  ASSERT_OK(Put("1000000000000foo", "v1"));
  ASSERT_OK(Put("0000000000000bar", "v2"));
  ASSERT_OK(Put("1000000000000foo", "v3"));
  dbfull()->TEST_FlushMemTable();

  options.create_if_missing = false;
  std::shared_ptr<TableFactory> dummy_factory;
1190 1191 1192 1193
  std::shared_ptr<TableFactory> block_based_factory(
      NewBlockBasedTableFactory());
  options.table_factory.reset(NewAdaptiveTableFactory(
      block_based_factory, dummy_factory, dummy_factory));
1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218
  Reopen(&options);
  ASSERT_EQ("v3", Get("1000000000000foo"));
  ASSERT_EQ("v2", Get("0000000000000bar"));

  ASSERT_OK(Put("2000000000000foo", "v4"));
  ASSERT_OK(Put("3000000000000bar", "v5"));
  dbfull()->TEST_FlushMemTable();
  ASSERT_EQ("v4", Get("2000000000000foo"));
  ASSERT_EQ("v5", Get("3000000000000bar"));

  Reopen(&options);
  ASSERT_EQ("v3", Get("1000000000000foo"));
  ASSERT_EQ("v2", Get("0000000000000bar"));
  ASSERT_EQ("v4", Get("2000000000000foo"));
  ASSERT_EQ("v5", Get("3000000000000bar"));

  options.table_factory.reset(NewBlockBasedTableFactory());
  Reopen(&options);
  ASSERT_NE("v3", Get("1000000000000foo"));

  options.table_factory.reset(NewPlainTableFactory());
  Reopen(&options);
  ASSERT_NE("v5", Get("3000000000000bar"));
}

1219 1220
INSTANTIATE_TEST_CASE_P(PlainTableDBTest, PlainTableDBTest, ::testing::Bool());

S
Siying Dong 已提交
1221 1222 1223
}  // namespace rocksdb

int main(int argc, char** argv) {
I
Igor Sugak 已提交
1224 1225
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
S
Siying Dong 已提交
1226
}
1227 1228 1229 1230

#else
#include <stdio.h>

1231
int main(int /*argc*/, char** /*argv*/) {
1232 1233 1234 1235 1236
  fprintf(stderr, "SKIPPED as plain table is not supported in ROCKSDB_LITE\n");
  return 0;
}

#endif  // !ROCKSDB_LITE