| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 | //  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.//  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).//// 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.#include "db/file_indexer.h"#include <string>#include "db/dbformat.h"#include "db/version_edit.h"#include "port/stack_trace.h"#include "rocksdb/comparator.h"#include "test_util/testharness.h"#include "test_util/testutil.h"namespace ROCKSDB_NAMESPACE {class IntComparator : public Comparator { public:  int Compare(const Slice& a, const Slice& b) const override {    assert(a.size() == 8);    assert(b.size() == 8);    int64_t diff = *reinterpret_cast<const int64_t*>(a.data()) -                   *reinterpret_cast<const int64_t*>(b.data());    if (diff < 0) {      return -1;    } else if (diff == 0) {      return 0;    } else {      return 1;    }  }  const char* Name() const override { return "IntComparator"; }  void FindShortestSeparator(std::string* /*start*/,                             const Slice& /*limit*/) const override {}  void FindShortSuccessor(std::string* /*key*/) const override {}};class FileIndexerTest : public testing::Test { public:  FileIndexerTest()      : kNumLevels(4), files(new std::vector<FileMetaData*>[kNumLevels]) {}  ~FileIndexerTest() override {    ClearFiles();    delete[] files;  }  void AddFile(int level, int64_t smallest, int64_t largest) {    auto* f = new FileMetaData();    f->smallest = IntKey(smallest);    f->largest = IntKey(largest);    files[level].push_back(f);  }  InternalKey IntKey(int64_t v) {    return InternalKey(Slice(reinterpret_cast<char*>(&v), 8), 0, kTypeValue);  }  void ClearFiles() {    for (uint32_t i = 0; i < kNumLevels; ++i) {      for (auto* f : files[i]) {        delete f;      }      files[i].clear();    }  }  void GetNextLevelIndex(const uint32_t level, const uint32_t file_index,      const int cmp_smallest, const int cmp_largest, int32_t* left_index,      int32_t* right_index) {    *left_index = 100;    *right_index = 100;    indexer->GetNextLevelIndex(level, file_index, cmp_smallest, cmp_largest,                               left_index, right_index);  }  int32_t left = 100;  int32_t right = 100;  const uint32_t kNumLevels;  IntComparator ucmp;  FileIndexer* indexer;  std::vector<FileMetaData*>* files;};// Case 0: EmptyTEST_F(FileIndexerTest, Empty) {  Arena arena;  indexer = new FileIndexer(&ucmp);  indexer->UpdateIndex(&arena, 0, files);  delete indexer;}// Case 1: no overlap, files are on the left of next level filesTEST_F(FileIndexerTest, no_overlap_left) {  Arena arena;  indexer = new FileIndexer(&ucmp);  // level 1  AddFile(1, 100, 200);  AddFile(1, 300, 400);  AddFile(1, 500, 600);  // level 2  AddFile(2, 1500, 1600);  AddFile(2, 1601, 1699);  AddFile(2, 1700, 1800);  // level 3  AddFile(3, 2500, 2600);  AddFile(3, 2601, 2699);  AddFile(3, 2700, 2800);  indexer->UpdateIndex(&arena, kNumLevels, files);  for (uint32_t level = 1; level < 3; ++level) {    for (uint32_t f = 0; f < 3; ++f) {      GetNextLevelIndex(level, f, -1, -1, &left, &right);      ASSERT_EQ(0, left);      ASSERT_EQ(-1, right);      GetNextLevelIndex(level, f, 0, -1, &left, &right);      ASSERT_EQ(0, left);      ASSERT_EQ(-1, right);      GetNextLevelIndex(level, f, 1, -1, &left, &right);      ASSERT_EQ(0, left);      ASSERT_EQ(-1, right);      GetNextLevelIndex(level, f, 1, 0, &left, &right);      ASSERT_EQ(0, left);      ASSERT_EQ(-1, right);      GetNextLevelIndex(level, f, 1, 1, &left, &right);      ASSERT_EQ(0, left);      ASSERT_EQ(2, right);    }  }  delete indexer;  ClearFiles();}// Case 2: no overlap, files are on the right of next level filesTEST_F(FileIndexerTest, no_overlap_right) {  Arena arena;  indexer = new FileIndexer(&ucmp);  // level 1  AddFile(1, 2100, 2200);  AddFile(1, 2300, 2400);  AddFile(1, 2500, 2600);  // level 2  AddFile(2, 1500, 1600);  AddFile(2, 1501, 1699);  AddFile(2, 1700, 1800);  // level 3  AddFile(3, 500, 600);  AddFile(3, 501, 699);  AddFile(3, 700, 800);  indexer->UpdateIndex(&arena, kNumLevels, files);  for (uint32_t level = 1; level < 3; ++level) {    for (uint32_t f = 0; f < 3; ++f) {      GetNextLevelIndex(level, f, -1, -1, &left, &right);      ASSERT_EQ(f == 0 ? 0 : 3, left);      ASSERT_EQ(2, right);      GetNextLevelIndex(level, f, 0, -1, &left, &right);      ASSERT_EQ(3, left);      ASSERT_EQ(2, right);      GetNextLevelIndex(level, f, 1, -1, &left, &right);      ASSERT_EQ(3, left);      ASSERT_EQ(2, right);      GetNextLevelIndex(level, f, 1, -1, &left, &right);      ASSERT_EQ(3, left);      ASSERT_EQ(2, right);      GetNextLevelIndex(level, f, 1, 0, &left, &right);      ASSERT_EQ(3, left);      ASSERT_EQ(2, right);      GetNextLevelIndex(level, f, 1, 1, &left, &right);      ASSERT_EQ(3, left);      ASSERT_EQ(2, right);    }  }  delete indexer;}// Case 3: empty L2TEST_F(FileIndexerTest, empty_L2) {  Arena arena;  indexer = new FileIndexer(&ucmp);  for (uint32_t i = 1; i < kNumLevels; ++i) {    ASSERT_EQ(0U, indexer->LevelIndexSize(i));  }  // level 1  AddFile(1, 2100, 2200);  AddFile(1, 2300, 2400);  AddFile(1, 2500, 2600);  // level 3  AddFile(3, 500, 600);  AddFile(3, 501, 699);  AddFile(3, 700, 800);  indexer->UpdateIndex(&arena, kNumLevels, files);  for (uint32_t f = 0; f < 3; ++f) {    GetNextLevelIndex(1, f, -1, -1, &left, &right);    ASSERT_EQ(0, left);    ASSERT_EQ(-1, right);    GetNextLevelIndex(1, f, 0, -1, &left, &right);    ASSERT_EQ(0, left);    ASSERT_EQ(-1, right);    GetNextLevelIndex(1, f, 1, -1, &left, &right);    ASSERT_EQ(0, left);    ASSERT_EQ(-1, right);    GetNextLevelIndex(1, f, 1, -1, &left, &right);    ASSERT_EQ(0, left);    ASSERT_EQ(-1, right);    GetNextLevelIndex(1, f, 1, 0, &left, &right);    ASSERT_EQ(0, left);    ASSERT_EQ(-1, right);    GetNextLevelIndex(1, f, 1, 1, &left, &right);    ASSERT_EQ(0, left);    ASSERT_EQ(-1, right);  }  delete indexer;  ClearFiles();}// Case 4: mixedTEST_F(FileIndexerTest, mixed) {  Arena arena;  indexer = new FileIndexer(&ucmp);  // level 1  AddFile(1, 100, 200);  AddFile(1, 250, 400);  AddFile(1, 450, 500);  // level 2  AddFile(2, 100, 150);  // 0  AddFile(2, 200, 250);  // 1  AddFile(2, 251, 300);  // 2  AddFile(2, 301, 350);  // 3  AddFile(2, 500, 600);  // 4  // level 3  AddFile(3, 0, 50);  AddFile(3, 100, 200);  AddFile(3, 201, 250);  indexer->UpdateIndex(&arena, kNumLevels, files);  // level 1, 0  GetNextLevelIndex(1, 0, -1, -1, &left, &right);  ASSERT_EQ(0, left);  ASSERT_EQ(0, right);  GetNextLevelIndex(1, 0, 0, -1, &left, &right);  ASSERT_EQ(0, left);  ASSERT_EQ(0, right);  GetNextLevelIndex(1, 0, 1, -1, &left, &right);  ASSERT_EQ(0, left);  ASSERT_EQ(1, right);  GetNextLevelIndex(1, 0, 1, 0, &left, &right);  ASSERT_EQ(1, left);  ASSERT_EQ(1, right);  GetNextLevelIndex(1, 0, 1, 1, &left, &right);  ASSERT_EQ(1, left);  ASSERT_EQ(4, right);  // level 1, 1  GetNextLevelIndex(1, 1, -1, -1, &left, &right);  ASSERT_EQ(1, left);  ASSERT_EQ(1, right);  GetNextLevelIndex(1, 1, 0, -1, &left, &right);  ASSERT_EQ(1, left);  ASSERT_EQ(1, right);  GetNextLevelIndex(1, 1, 1, -1, &left, &right);  ASSERT_EQ(1, left);  ASSERT_EQ(3, right);  GetNextLevelIndex(1, 1, 1, 0, &left, &right);  ASSERT_EQ(4, left);  ASSERT_EQ(3, right);  GetNextLevelIndex(1, 1, 1, 1, &left, &right);  ASSERT_EQ(4, left);  ASSERT_EQ(4, right);  // level 1, 2  GetNextLevelIndex(1, 2, -1, -1, &left, &right);  ASSERT_EQ(4, left);  ASSERT_EQ(3, right);  GetNextLevelIndex(1, 2, 0, -1, &left, &right);  ASSERT_EQ(4, left);  ASSERT_EQ(3, right);  GetNextLevelIndex(1, 2, 1, -1, &left, &right);  ASSERT_EQ(4, left);  ASSERT_EQ(4, right);  GetNextLevelIndex(1, 2, 1, 0, &left, &right);  ASSERT_EQ(4, left);  ASSERT_EQ(4, right);  GetNextLevelIndex(1, 2, 1, 1, &left, &right);  ASSERT_EQ(4, left);  ASSERT_EQ(4, right);  // level 2, 0  GetNextLevelIndex(2, 0, -1, -1, &left, &right);  ASSERT_EQ(0, left);  ASSERT_EQ(1, right);  GetNextLevelIndex(2, 0, 0, -1, &left, &right);  ASSERT_EQ(1, left);  ASSERT_EQ(1, right);  GetNextLevelIndex(2, 0, 1, -1, &left, &right);  ASSERT_EQ(1, left);  ASSERT_EQ(1, right);  GetNextLevelIndex(2, 0, 1, 0, &left, &right);  ASSERT_EQ(1, left);  ASSERT_EQ(1, right);  GetNextLevelIndex(2, 0, 1, 1, &left, &right);  ASSERT_EQ(1, left);  ASSERT_EQ(2, right);  // level 2, 1  GetNextLevelIndex(2, 1, -1, -1, &left, &right);  ASSERT_EQ(1, left);  ASSERT_EQ(1, right);  GetNextLevelIndex(2, 1, 0, -1, &left, &right);  ASSERT_EQ(1, left);  ASSERT_EQ(1, right);  GetNextLevelIndex(2, 1, 1, -1, &left, &right);  ASSERT_EQ(1, left);  ASSERT_EQ(2, right);  GetNextLevelIndex(2, 1, 1, 0, &left, &right);  ASSERT_EQ(2, left);  ASSERT_EQ(2, right);  GetNextLevelIndex(2, 1, 1, 1, &left, &right);  ASSERT_EQ(2, left);  ASSERT_EQ(2, right);  // level 2, [2 - 4], no overlap  for (uint32_t f = 2; f <= 4; ++f) {    GetNextLevelIndex(2, f, -1, -1, &left, &right);    ASSERT_EQ(f == 2 ? 2 : 3, left);    ASSERT_EQ(2, right);    GetNextLevelIndex(2, f, 0, -1, &left, &right);    ASSERT_EQ(3, left);    ASSERT_EQ(2, right);    GetNextLevelIndex(2, f, 1, -1, &left, &right);    ASSERT_EQ(3, left);    ASSERT_EQ(2, right);    GetNextLevelIndex(2, f, 1, 0, &left, &right);    ASSERT_EQ(3, left);    ASSERT_EQ(2, right);    GetNextLevelIndex(2, f, 1, 1, &left, &right);    ASSERT_EQ(3, left);    ASSERT_EQ(2, right);  }  delete indexer;  ClearFiles();}}  // namespace ROCKSDB_NAMESPACEint main(int argc, char** argv) {  ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();  ::testing::InitGoogleTest(&argc, argv);  return RUN_ALL_TESTS();}
 |