Coverage Report

Created: 2026-02-14 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rocksdb/table/block_fetcher.h
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
10
#pragma once
11
#include "file/file_util.h"
12
#include "memory/memory_allocator_impl.h"
13
#include "table/block_based/block.h"
14
#include "table/block_based/block_type.h"
15
#include "table/format.h"
16
#include "table/persistent_cache_options.h"
17
#include "util/cast_util.h"
18
19
namespace ROCKSDB_NAMESPACE {
20
21
// Retrieves a single block of a given file. Utilizes the prefetch buffer and/or
22
// persistent cache provided (if any) to try to avoid reading from the file
23
// directly. Note that both the prefetch buffer and the persistent cache are
24
// optional; also, note that the persistent cache may be configured to store
25
// either compressed or uncompressed blocks.
26
//
27
// If the retrieved block is compressed and the do_uncompress flag is set,
28
// BlockFetcher uncompresses the block (using the uncompression dictionary,
29
// if provided, to prime the compression algorithm), and returns the resulting
30
// uncompressed block data. Otherwise, it returns the original block.
31
//
32
// Two read options affect the behavior of BlockFetcher: if verify_checksums is
33
// true, the checksum of the (original) block is checked; if fill_cache is true,
34
// the block is added to the persistent cache if needed.
35
//
36
// Memory for uncompressed and compressed blocks is allocated as needed
37
// using memory_allocator and memory_allocator_compressed, respectively
38
// (if provided; otherwise, the default allocator is used).
39
40
class BlockFetcher {
41
 public:
42
  BlockFetcher(RandomAccessFileReader* file,
43
               FilePrefetchBuffer* prefetch_buffer,
44
               const Footer& footer /* ref retained */,
45
               const ReadOptions& read_options,
46
               const BlockHandle& handle /* ref retained */,
47
               BlockContents* contents,
48
               const ImmutableOptions& ioptions /* ref retained */,
49
               bool do_uncompress, bool maybe_compressed, BlockType block_type,
50
               UnownedPtr<Decompressor> decompressor,
51
               const PersistentCacheOptions& cache_options /* ref retained */,
52
               MemoryAllocator* memory_allocator = nullptr,
53
               MemoryAllocator* memory_allocator_compressed = nullptr,
54
               bool for_compaction = false)
55
109k
      : file_(file),
56
109k
        prefetch_buffer_(prefetch_buffer),
57
109k
        footer_(footer),
58
109k
        read_options_(read_options),
59
109k
        handle_(handle),
60
109k
        contents_(contents),
61
109k
        ioptions_(ioptions),
62
109k
        do_uncompress_(do_uncompress),
63
109k
        maybe_compressed_(maybe_compressed),
64
109k
        block_type_(block_type),
65
109k
        block_size_(static_cast<size_t>(handle_.size())),
66
109k
        block_size_with_trailer_(block_size_ + footer.GetBlockTrailerSize()),
67
109k
        decompressor_(decompressor),
68
109k
        cache_options_(cache_options),
69
109k
        memory_allocator_(memory_allocator),
70
109k
        memory_allocator_compressed_(memory_allocator_compressed),
71
109k
        for_compaction_(for_compaction) {
72
109k
    io_status_.PermitUncheckedError();  // TODO(AR) can we improve on this?
73
109k
    if (CheckFSFeatureSupport(ioptions_.fs.get(), FSSupportedOps::kFSBuffer)) {
74
0
      use_fs_scratch_ = true;
75
0
    }
76
109k
    if (CheckFSFeatureSupport(ioptions_.fs.get(),
77
109k
                              FSSupportedOps::kVerifyAndReconstructRead)) {
78
0
      retry_corrupt_read_ = true;
79
0
    }
80
109k
  }
81
82
  IOStatus ReadBlockContents();
83
  IOStatus ReadAsyncBlockContents();
84
85
0
  inline CompressionType compression_type() const {
86
0
    return decomp_args_.compression_type;
87
0
  }
88
147k
  inline CompressionType& compression_type() {
89
147k
    return decomp_args_.compression_type;
90
147k
  }
91
0
  inline size_t GetBlockSizeWithTrailer() const {
92
0
    return block_size_with_trailer_;
93
0
  }
94
0
  inline Slice& GetCompressedBlock() {
95
0
    assert(compression_type() != kNoCompression);
96
0
    return slice_;
97
0
  }
98
99
#ifndef NDEBUG
100
  int TEST_GetNumStackBufMemcpy() const { return num_stack_buf_memcpy_; }
101
  int TEST_GetNumHeapBufMemcpy() const { return num_heap_buf_memcpy_; }
102
  int TEST_GetNumCompressedBufMemcpy() const {
103
    return num_compressed_buf_memcpy_;
104
  }
105
106
#endif
107
 private:
108
#ifndef NDEBUG
109
  int num_stack_buf_memcpy_ = 0;
110
  int num_heap_buf_memcpy_ = 0;
111
  int num_compressed_buf_memcpy_ = 0;
112
113
#endif
114
  static const uint32_t kDefaultStackBufferSize = 5000;
115
116
  RandomAccessFileReader* file_;
117
  FilePrefetchBuffer* prefetch_buffer_;
118
  const Footer& footer_;
119
  const ReadOptions read_options_;
120
  const BlockHandle& handle_;
121
  BlockContents* contents_;
122
  const ImmutableOptions& ioptions_;
123
  const bool do_uncompress_;
124
  const bool maybe_compressed_;
125
  const BlockType block_type_;
126
  const size_t block_size_;
127
  const size_t block_size_with_trailer_;
128
  UnownedPtr<Decompressor> decompressor_;
129
  const PersistentCacheOptions& cache_options_;
130
  MemoryAllocator* memory_allocator_;
131
  MemoryAllocator* memory_allocator_compressed_;
132
  IOStatus io_status_;
133
  Slice slice_;
134
  char* used_buf_ = nullptr;
135
  AlignedBuf direct_io_buf_;
136
  CacheAllocationPtr heap_buf_;
137
  CacheAllocationPtr compressed_buf_;
138
  char stack_buf_[kDefaultStackBufferSize];
139
  bool got_from_prefetch_buffer_ = false;
140
  bool for_compaction_ = false;
141
  bool use_fs_scratch_ = false;
142
  bool retry_corrupt_read_ = false;
143
  FSAllocationPtr fs_buf_;
144
  Decompressor::Args decomp_args_;
145
146
  // return true if found
147
  bool TryGetUncompressBlockFromPersistentCache();
148
  // return true if found
149
  bool TryGetFromPrefetchBuffer();
150
  bool TryGetSerializedBlockFromPersistentCache();
151
  void PrepareBufferForBlockFromFile();
152
  // Copy content from used_buf_ to new heap_buf_.
153
  void CopyBufferToHeapBuf();
154
  // Copy content from used_buf_ to new compressed_buf_.
155
  void CopyBufferToCompressedBuf();
156
  void GetBlockContents();
157
  void InsertCompressedBlockToPersistentCacheIfNeeded();
158
  void InsertUncompressedBlockToPersistentCacheIfNeeded();
159
  void ProcessTrailerIfPresent();
160
  void ReadBlock(bool retry);
161
162
0
  void ReleaseFileSystemProvidedBuffer(FSReadRequest* read_req) {
163
0
    if (use_fs_scratch_) {
164
      // Free the scratch buffer allocated by FileSystem.
165
0
      if (read_req->fs_scratch != nullptr) {
166
0
        read_req->fs_scratch.reset();
167
0
        read_req->fs_scratch = nullptr;
168
0
      }
169
0
    }
170
0
  }
171
};
172
}  // namespace ROCKSDB_NAMESPACE