file_indexer.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  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).
  5. //
  6. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  7. // Use of this source code is governed by a BSD-style license that can be
  8. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  9. #pragma once
  10. #include <cstdint>
  11. #include <functional>
  12. #include <limits>
  13. #include <vector>
  14. #include "memory/arena.h"
  15. #include "port/port.h"
  16. #include "util/autovector.h"
  17. namespace ROCKSDB_NAMESPACE {
  18. class Comparator;
  19. struct FileMetaData;
  20. struct FdWithKeyRange;
  21. struct FileLevel;
  22. // The file tree structure in Version is prebuilt and the range of each file
  23. // is known. On Version::Get(), it uses binary search to find a potential file
  24. // and then check if a target key can be found in the file by comparing the key
  25. // to each file's smallest and largest key. The results of these comparisons
  26. // can be reused beyond checking if a key falls into a file's range.
  27. // With some pre-calculated knowledge, each key comparison that has been done
  28. // can serve as a hint to narrow down further searches: if a key compared to
  29. // be smaller than a file's smallest or largest, that comparison can be used
  30. // to find out the right bound of next binary search. Similarly, if a key
  31. // compared to be larger than a file's smallest or largest, it can be utilized
  32. // to find out the left bound of next binary search.
  33. // With these hints: it can greatly reduce the range of binary search,
  34. // especially for bottom levels, given that one file most likely overlaps with
  35. // only N files from level below (where N is max_bytes_for_level_multiplier).
  36. // So on level L, we will only look at ~N files instead of N^L files on the
  37. // naive approach.
  38. class FileIndexer {
  39. public:
  40. explicit FileIndexer(const Comparator* ucmp);
  41. size_t NumLevelIndex() const;
  42. size_t LevelIndexSize(size_t level) const;
  43. // Return a file index range in the next level to search for a key based on
  44. // smallest and largest key comparison for the current file specified by
  45. // level and file_index. When *left_index < *right_index, both index should
  46. // be valid and fit in the vector size.
  47. void GetNextLevelIndex(const size_t level, const size_t file_index,
  48. const int cmp_smallest, const int cmp_largest,
  49. int32_t* left_bound, int32_t* right_bound) const;
  50. void UpdateIndex(Arena* arena, const size_t num_levels,
  51. std::vector<FileMetaData*>* const files);
  52. enum {
  53. // MSVC version 1800 still does not have constexpr for ::max()
  54. kLevelMaxIndex = ROCKSDB_NAMESPACE::port::kMaxInt32
  55. };
  56. private:
  57. size_t num_levels_;
  58. const Comparator* ucmp_;
  59. struct IndexUnit {
  60. IndexUnit()
  61. : smallest_lb(0), largest_lb(0), smallest_rb(-1), largest_rb(-1) {}
  62. // During file search, a key is compared against smallest and largest
  63. // from a FileMetaData. It can have 3 possible outcomes:
  64. // (1) key is smaller than smallest, implying it is also smaller than
  65. // larger. Precalculated index based on "smallest < smallest" can
  66. // be used to provide right bound.
  67. // (2) key is in between smallest and largest.
  68. // Precalculated index based on "smallest > greatest" can be used to
  69. // provide left bound.
  70. // Precalculated index based on "largest < smallest" can be used to
  71. // provide right bound.
  72. // (3) key is larger than largest, implying it is also larger than smallest.
  73. // Precalculated index based on "largest > largest" can be used to
  74. // provide left bound.
  75. //
  76. // As a result, we will need to do:
  77. // Compare smallest (<=) and largest keys from upper level file with
  78. // smallest key from lower level to get a right bound.
  79. // Compare smallest (>=) and largest keys from upper level file with
  80. // largest key from lower level to get a left bound.
  81. //
  82. // Example:
  83. // level 1: [50 - 60]
  84. // level 2: [1 - 40], [45 - 55], [58 - 80]
  85. // A key 35, compared to be less than 50, 3rd file on level 2 can be
  86. // skipped according to rule (1). LB = 0, RB = 1.
  87. // A key 53, sits in the middle 50 and 60. 1st file on level 2 can be
  88. // skipped according to rule (2)-a, but the 3rd file cannot be skipped
  89. // because 60 is greater than 58. LB = 1, RB = 2.
  90. // A key 70, compared to be larger than 60. 1st and 2nd file can be skipped
  91. // according to rule (3). LB = 2, RB = 2.
  92. //
  93. // Point to a left most file in a lower level that may contain a key,
  94. // which compares greater than smallest of a FileMetaData (upper level)
  95. int32_t smallest_lb;
  96. // Point to a left most file in a lower level that may contain a key,
  97. // which compares greater than largest of a FileMetaData (upper level)
  98. int32_t largest_lb;
  99. // Point to a right most file in a lower level that may contain a key,
  100. // which compares smaller than smallest of a FileMetaData (upper level)
  101. int32_t smallest_rb;
  102. // Point to a right most file in a lower level that may contain a key,
  103. // which compares smaller than largest of a FileMetaData (upper level)
  104. int32_t largest_rb;
  105. };
  106. // Data structure to store IndexUnits in a whole level
  107. struct IndexLevel {
  108. size_t num_index;
  109. IndexUnit* index_units;
  110. IndexLevel() : num_index(0), index_units(nullptr) {}
  111. };
  112. void CalculateLB(
  113. const std::vector<FileMetaData*>& upper_files,
  114. const std::vector<FileMetaData*>& lower_files, IndexLevel* index_level,
  115. std::function<int(const FileMetaData*, const FileMetaData*)> cmp_op,
  116. std::function<void(IndexUnit*, int32_t)> set_index);
  117. void CalculateRB(
  118. const std::vector<FileMetaData*>& upper_files,
  119. const std::vector<FileMetaData*>& lower_files, IndexLevel* index_level,
  120. std::function<int(const FileMetaData*, const FileMetaData*)> cmp_op,
  121. std::function<void(IndexUnit*, int32_t)> set_index);
  122. autovector<IndexLevel> next_level_index_;
  123. int32_t* level_rb_;
  124. };
  125. } // namespace ROCKSDB_NAMESPACE