/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 |