Coverage Report

Created: 2026-05-31 07:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rocksdb/table/block_based/block_prefetcher.cc
Line
Count
Source
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/block_prefetcher.h"
10
11
#include "rocksdb/file_system.h"
12
#include "table/block_based/block_based_table_reader.h"
13
14
namespace ROCKSDB_NAMESPACE {
15
void BlockPrefetcher::PrefetchIfNeeded(
16
    const BlockBasedTable::Rep* rep, const BlockHandle& handle,
17
    const size_t readahead_size, bool is_for_compaction,
18
    const bool no_sequential_checking, const ReadOptions& read_options,
19
    const std::function<void(bool, uint64_t&, uint64_t&)>& readaheadsize_cb,
20
49.0k
    bool is_async_io_prefetch) {
21
49.0k
  if (read_options.read_tier == ReadTier::kBlockCacheTier) {
22
    // Disable prefetching when IO disallowed. (Note that we haven't allocated
23
    // any buffers yet despite the various tracked settings.)
24
0
    return;
25
0
  }
26
27
49.0k
  ReadaheadParams readahead_params;
28
49.0k
  readahead_params.initial_readahead_size = readahead_size;
29
49.0k
  readahead_params.max_readahead_size = readahead_size;
30
49.0k
  readahead_params.num_buffers = is_async_io_prefetch ? 2 : 1;
31
32
49.0k
  const size_t len = BlockBasedTable::BlockSizeWithTrailer(handle);
33
49.0k
  const size_t offset = handle.offset();
34
49.0k
  if (is_for_compaction) {
35
20.4k
    if (!rep->file->use_direct_io() && compaction_readahead_size_ > 0) {
36
      // If FS supports prefetching (readahead_limit_ will be non zero in that
37
      // case) and current block exists in prefetch buffer then return.
38
20.4k
      if (offset + len <= readahead_limit_) {
39
0
        return;
40
0
      }
41
20.4k
      IOOptions opts;
42
20.4k
      IODebugContext dbg;
43
20.4k
      Status s = rep->file->PrepareIOOptions(read_options, opts, &dbg);
44
20.4k
      if (!s.ok()) {
45
0
        return;
46
0
      }
47
20.4k
      if (rep->fs_prefetch_support) {
48
20.4k
        s = rep->file->Prefetch(opts, offset, len + compaction_readahead_size_);
49
20.4k
        if (s.ok()) {
50
20.4k
          readahead_limit_ = offset + len + compaction_readahead_size_;
51
20.4k
          return;
52
20.4k
        } else if (!s.IsNotSupported()) {
53
0
          return;
54
0
        }
55
        // If FS prefetch returned NotSupported despite feature bit being set,
56
        // fall through to use internal prefetch buffer.
57
20.4k
      }
58
20.4k
    }
59
    // If FS prefetch is not supported, fall back to use internal prefetch
60
    // buffer.
61
    //
62
    // num_file_reads is used  by FilePrefetchBuffer only when
63
    // implicit_auto_readahead is set.
64
0
    readahead_params.initial_readahead_size = compaction_readahead_size_;
65
0
    readahead_params.max_readahead_size = compaction_readahead_size_;
66
0
    rep->CreateFilePrefetchBufferIfNotExists(
67
0
        readahead_params, &prefetch_buffer_,
68
0
        /*readaheadsize_cb=*/nullptr,
69
0
        /*usage=*/FilePrefetchBufferUsage::kCompactionPrefetch);
70
0
    return;
71
20.4k
  }
72
73
  // Explicit user requested readahead.
74
28.6k
  if (readahead_size > 0) {
75
0
    rep->CreateFilePrefetchBufferIfNotExists(
76
0
        readahead_params, &prefetch_buffer_, readaheadsize_cb,
77
0
        /*usage=*/FilePrefetchBufferUsage::kUserScanPrefetch);
78
0
    return;
79
0
  }
80
81
  // Implicit readahead.
82
83
  // If max_auto_readahead_size is set to be 0 by user, no data will be
84
  // prefetched.
85
28.6k
  size_t max_auto_readahead_size = rep->table_options.max_auto_readahead_size;
86
28.6k
  if (max_auto_readahead_size == 0 || initial_auto_readahead_size_ == 0) {
87
0
    return;
88
0
  }
89
90
28.6k
  if (initial_auto_readahead_size_ > max_auto_readahead_size) {
91
0
    initial_auto_readahead_size_ = max_auto_readahead_size;
92
0
  }
93
94
28.6k
  readahead_params.initial_readahead_size = initial_auto_readahead_size_;
95
28.6k
  readahead_params.max_readahead_size = max_auto_readahead_size;
96
28.6k
  readahead_params.implicit_auto_readahead = true;
97
28.6k
  readahead_params.num_file_reads_for_auto_readahead =
98
28.6k
      rep->table_options.num_file_reads_for_auto_readahead;
99
100
  // In case of no_sequential_checking, it will skip the num_file_reads_ and
101
  // will always creates the FilePrefetchBuffer.
102
28.6k
  if (no_sequential_checking) {
103
0
    rep->CreateFilePrefetchBufferIfNotExists(
104
0
        readahead_params, &prefetch_buffer_, readaheadsize_cb,
105
0
        /*usage=*/FilePrefetchBufferUsage::kUserScanPrefetch);
106
0
    return;
107
0
  }
108
109
  // If FS supports prefetching (readahead_limit_ will be non zero in that case)
110
  // and current block exists in prefetch buffer then return.
111
28.6k
  if (offset + len <= readahead_limit_) {
112
1.77k
    UpdateReadPattern(offset, len);
113
1.77k
    return;
114
1.77k
  }
115
116
26.8k
  if (!IsBlockSequential(offset)) {
117
1.12k
    UpdateReadPattern(offset, len);
118
1.12k
    ResetValues(rep->table_options.initial_auto_readahead_size);
119
1.12k
    return;
120
1.12k
  }
121
25.7k
  UpdateReadPattern(offset, len);
122
123
  // Implicit auto readahead, which will be enabled if the number of reads
124
  // reached `table_options.num_file_reads_for_auto_readahead` (default: 2)  and
125
  // scans are sequential.
126
25.7k
  num_file_reads_++;
127
25.7k
  if (num_file_reads_ <= rep->table_options.num_file_reads_for_auto_readahead) {
128
25.0k
    return;
129
25.0k
  }
130
131
659
  readahead_params.num_file_reads = num_file_reads_;
132
659
  if (rep->file->use_direct_io()) {
133
0
    rep->CreateFilePrefetchBufferIfNotExists(
134
0
        readahead_params, &prefetch_buffer_, readaheadsize_cb,
135
0
        /*usage=*/FilePrefetchBufferUsage::kUserScanPrefetch);
136
0
    return;
137
0
  }
138
139
659
  if (readahead_size_ > max_auto_readahead_size) {
140
0
    readahead_size_ = max_auto_readahead_size;
141
0
  }
142
143
  // If prefetch is not supported, fall back to use internal prefetch buffer.
144
659
  IOOptions opts;
145
659
  Status s = rep->file->PrepareIOOptions(read_options, opts);
146
659
  if (!s.ok()) {
147
0
    return;
148
0
  }
149
150
688
  if (rep->fs_prefetch_support) {
151
688
    s = rep->file->Prefetch(
152
688
        opts, handle.offset(),
153
688
        BlockBasedTable::BlockSizeWithTrailer(handle) + readahead_size_);
154
688
    if (s.ok()) {
155
688
      readahead_limit_ = offset + len + readahead_size_;
156
      // Keep exponentially increasing readahead size until
157
      // max_auto_readahead_size.
158
688
      readahead_size_ = std::min(max_auto_readahead_size, readahead_size_ * 2);
159
688
      return;
160
688
    }
161
688
  }
162
  // If FS prefetch is not supported or returned NotSupported, fall back to use
163
  // internal prefetch buffer.
164
18.4E
  rep->CreateFilePrefetchBufferIfNotExists(
165
18.4E
      readahead_params, &prefetch_buffer_, readaheadsize_cb,
166
18.4E
      /*usage=*/FilePrefetchBufferUsage::kUserScanPrefetch);
167
18.4E
}
168
}  // namespace ROCKSDB_NAMESPACE