partitioned_index_iterator.cc 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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. #include "table/block_based/partitioned_index_iterator.h"
  10. namespace ROCKSDB_NAMESPACE {
  11. void PartitionedIndexIterator::Seek(const Slice& target) { SeekImpl(&target); }
  12. void PartitionedIndexIterator::SeekToFirst() { SeekImpl(nullptr); }
  13. void PartitionedIndexIterator::SeekImpl(const Slice* target) {
  14. SavePrevIndexValue();
  15. if (target) {
  16. index_iter_->Seek(*target);
  17. } else {
  18. index_iter_->SeekToFirst();
  19. }
  20. if (!index_iter_->Valid()) {
  21. ResetPartitionedIndexIter();
  22. return;
  23. }
  24. InitPartitionedIndexBlock();
  25. if (target) {
  26. block_iter_.Seek(*target);
  27. } else {
  28. block_iter_.SeekToFirst();
  29. }
  30. FindKeyForward();
  31. // We could check upper bound here, but that would be too complicated
  32. // and checking index upper bound is less useful than for data blocks.
  33. if (target) {
  34. assert(!Valid() || (table_->get_rep()->index_key_includes_seq
  35. ? (icomp_.Compare(*target, key()) <= 0)
  36. : (user_comparator_.Compare(ExtractUserKey(*target),
  37. key()) <= 0)));
  38. }
  39. }
  40. void PartitionedIndexIterator::SeekToLast() {
  41. SavePrevIndexValue();
  42. index_iter_->SeekToLast();
  43. if (!index_iter_->Valid()) {
  44. ResetPartitionedIndexIter();
  45. return;
  46. }
  47. InitPartitionedIndexBlock();
  48. block_iter_.SeekToLast();
  49. FindKeyBackward();
  50. }
  51. void PartitionedIndexIterator::Next() {
  52. assert(block_iter_points_to_real_block_);
  53. block_iter_.Next();
  54. FindKeyForward();
  55. }
  56. void PartitionedIndexIterator::Prev() {
  57. assert(block_iter_points_to_real_block_);
  58. block_iter_.Prev();
  59. FindKeyBackward();
  60. }
  61. void PartitionedIndexIterator::InitPartitionedIndexBlock() {
  62. BlockHandle partitioned_index_handle = index_iter_->value().handle;
  63. if (!block_iter_points_to_real_block_ ||
  64. partitioned_index_handle.offset() != prev_block_offset_ ||
  65. // if previous attempt of reading the block missed cache, try again
  66. block_iter_.status().IsIncomplete()) {
  67. if (block_iter_points_to_real_block_) {
  68. ResetPartitionedIndexIter();
  69. }
  70. auto* rep = table_->get_rep();
  71. bool is_for_compaction =
  72. lookup_context_.caller == TableReaderCaller::kCompaction;
  73. // Prefetch additional data for range scans (iterators).
  74. // Implicit auto readahead:
  75. // Enabled after 2 sequential IOs when ReadOptions.readahead_size == 0.
  76. // Explicit user requested readahead:
  77. // Enabled from the very first IO when ReadOptions.readahead_size is set.
  78. block_prefetcher_.PrefetchIfNeeded(
  79. rep, partitioned_index_handle, read_options_.readahead_size,
  80. is_for_compaction, /*no_sequential_checking=*/false, read_options_,
  81. /*readaheadsize_cb=*/nullptr, /*is_async_io_prefetch=*/false);
  82. Status s;
  83. table_->NewDataBlockIterator<IndexBlockIter>(
  84. read_options_, partitioned_index_handle, &block_iter_,
  85. BlockType::kIndex,
  86. /*get_context=*/nullptr, &lookup_context_,
  87. block_prefetcher_.prefetch_buffer(),
  88. /*for_compaction=*/is_for_compaction, /*async_read=*/false, s,
  89. /*use_block_cache_for_lookup=*/true);
  90. block_iter_points_to_real_block_ = true;
  91. // We could check upper bound here but it is complicated to reason about
  92. // upper bound in index iterator. On the other than, in large scans, index
  93. // iterators are moved much less frequently compared to data blocks. So
  94. // the upper bound check is skipped for simplicity.
  95. }
  96. }
  97. void PartitionedIndexIterator::FindKeyForward() {
  98. // This method's code is kept short to make it likely to be inlined.
  99. assert(block_iter_points_to_real_block_);
  100. if (!block_iter_.Valid()) {
  101. // This is the only call site of FindBlockForward(), but it's extracted into
  102. // a separate method to keep FindKeyForward() short and likely to be
  103. // inlined. When transitioning to a different block, we call
  104. // FindBlockForward(), which is much longer and is probably not inlined.
  105. FindBlockForward();
  106. } else {
  107. // This is the fast path that avoids a function call.
  108. }
  109. }
  110. void PartitionedIndexIterator::FindBlockForward() {
  111. // TODO the while loop inherits from two-level-iterator. We don't know
  112. // whether a block can be empty so it can be replaced by an "if".
  113. do {
  114. if (!block_iter_.status().ok()) {
  115. return;
  116. }
  117. ResetPartitionedIndexIter();
  118. index_iter_->Next();
  119. if (!index_iter_->Valid()) {
  120. return;
  121. }
  122. InitPartitionedIndexBlock();
  123. block_iter_.SeekToFirst();
  124. } while (!block_iter_.Valid());
  125. }
  126. void PartitionedIndexIterator::FindKeyBackward() {
  127. while (!block_iter_.Valid()) {
  128. if (!block_iter_.status().ok()) {
  129. return;
  130. }
  131. ResetPartitionedIndexIter();
  132. index_iter_->Prev();
  133. if (index_iter_->Valid()) {
  134. InitPartitionedIndexBlock();
  135. block_iter_.SeekToLast();
  136. } else {
  137. return;
  138. }
  139. }
  140. }
  141. } // namespace ROCKSDB_NAMESPACE