/src/rocksdb/table/meta_blocks.cc
Line | Count | Source (jump to first uncovered line) |
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 | | #include "table/meta_blocks.h" |
6 | | |
7 | | #include <map> |
8 | | #include <string> |
9 | | |
10 | | #include "block_fetcher.h" |
11 | | #include "db/table_properties_collector.h" |
12 | | #include "file/random_access_file_reader.h" |
13 | | #include "logging/logging.h" |
14 | | #include "rocksdb/options.h" |
15 | | #include "rocksdb/table.h" |
16 | | #include "rocksdb/table_properties.h" |
17 | | #include "table/block_based/block.h" |
18 | | #include "table/block_based/reader_common.h" |
19 | | #include "table/format.h" |
20 | | #include "table/internal_iterator.h" |
21 | | #include "table/persistent_cache_helper.h" |
22 | | #include "table/sst_file_writer_collectors.h" |
23 | | #include "table/table_properties_internal.h" |
24 | | #include "test_util/sync_point.h" |
25 | | #include "util/coding.h" |
26 | | |
27 | | namespace ROCKSDB_NAMESPACE { |
28 | | |
29 | | const std::string kPropertiesBlockName = "rocksdb.properties"; |
30 | | // NB: only used with format_version >= 6 |
31 | | const std::string kIndexBlockName = "rocksdb.index"; |
32 | | // Old property block name for backward compatibility |
33 | | const std::string kPropertiesBlockOldName = "rocksdb.stats"; |
34 | | const std::string kCompressionDictBlockName = "rocksdb.compression_dict"; |
35 | | const std::string kRangeDelBlockName = "rocksdb.range_del"; |
36 | | |
37 | | MetaIndexBuilder::MetaIndexBuilder() |
38 | 4.48k | : meta_index_block_(new BlockBuilder(1 /* restart interval */)) {} |
39 | | |
40 | 11.8k | void MetaIndexBuilder::Add(const std::string& key, const BlockHandle& handle) { |
41 | 11.8k | std::string handle_encoding; |
42 | 11.8k | handle.EncodeTo(&handle_encoding); |
43 | 11.8k | meta_block_handles_.insert({key, handle_encoding}); |
44 | 11.8k | } |
45 | | |
46 | 4.48k | Slice MetaIndexBuilder::Finish() { |
47 | 11.8k | for (const auto& metablock : meta_block_handles_) { |
48 | 11.8k | meta_index_block_->Add(metablock.first, metablock.second); |
49 | 11.8k | } |
50 | 4.48k | return meta_index_block_->Finish(); |
51 | 4.48k | } |
52 | | |
53 | | // Property block will be read sequentially and cached in a heap located |
54 | | // object, so there's no need for restart points. Thus we set the restart |
55 | | // interval to infinity to save space. |
56 | | PropertyBlockBuilder::PropertyBlockBuilder() |
57 | | : properties_block_(new BlockBuilder( |
58 | 4.48k | std::numeric_limits<int32_t>::max() /* restart interval */)) {} |
59 | | |
60 | | void PropertyBlockBuilder::Add(const std::string& name, |
61 | 147k | const std::string& val) { |
62 | 147k | props_.insert({name, val}); |
63 | 147k | } |
64 | | |
65 | 89.6k | void PropertyBlockBuilder::Add(const std::string& name, uint64_t val) { |
66 | 89.6k | assert(props_.find(name) == props_.end()); |
67 | | |
68 | 89.6k | std::string dst; |
69 | 89.6k | PutVarint64(&dst, val); |
70 | | |
71 | 89.6k | Add(name, dst); |
72 | 89.6k | } |
73 | | |
74 | | void PropertyBlockBuilder::Add( |
75 | 4.48k | const UserCollectedProperties& user_collected_properties) { |
76 | 13.4k | for (const auto& prop : user_collected_properties) { |
77 | 13.4k | Add(prop.first, prop.second); |
78 | 13.4k | } |
79 | 4.48k | } |
80 | | |
81 | 4.48k | void PropertyBlockBuilder::AddTableProperty(const TableProperties& props) { |
82 | 4.48k | TEST_SYNC_POINT_CALLBACK("PropertyBlockBuilder::AddTableProperty:Start", |
83 | 4.48k | const_cast<TableProperties*>(&props)); |
84 | | |
85 | 4.48k | Add(TablePropertiesNames::kOriginalFileNumber, props.orig_file_number); |
86 | 4.48k | Add(TablePropertiesNames::kRawKeySize, props.raw_key_size); |
87 | 4.48k | Add(TablePropertiesNames::kRawValueSize, props.raw_value_size); |
88 | 4.48k | Add(TablePropertiesNames::kDataSize, props.data_size); |
89 | 4.48k | Add(TablePropertiesNames::kIndexSize, props.index_size); |
90 | 4.48k | if (props.index_partitions != 0) { |
91 | 0 | Add(TablePropertiesNames::kIndexPartitions, props.index_partitions); |
92 | 0 | Add(TablePropertiesNames::kTopLevelIndexSize, props.top_level_index_size); |
93 | 0 | } |
94 | 4.48k | Add(TablePropertiesNames::kIndexKeyIsUserKey, props.index_key_is_user_key); |
95 | 4.48k | Add(TablePropertiesNames::kIndexValueIsDeltaEncoded, |
96 | 4.48k | props.index_value_is_delta_encoded); |
97 | 4.48k | Add(TablePropertiesNames::kNumEntries, props.num_entries); |
98 | 4.48k | Add(TablePropertiesNames::kNumFilterEntries, props.num_filter_entries); |
99 | 4.48k | Add(TablePropertiesNames::kDeletedKeys, props.num_deletions); |
100 | 4.48k | Add(TablePropertiesNames::kMergeOperands, props.num_merge_operands); |
101 | 4.48k | Add(TablePropertiesNames::kNumRangeDeletions, props.num_range_deletions); |
102 | 4.48k | Add(TablePropertiesNames::kNumDataBlocks, props.num_data_blocks); |
103 | 4.48k | Add(TablePropertiesNames::kFilterSize, props.filter_size); |
104 | 4.48k | Add(TablePropertiesNames::kFormatVersion, props.format_version); |
105 | 4.48k | Add(TablePropertiesNames::kFixedKeyLen, props.fixed_key_len); |
106 | 4.48k | Add(TablePropertiesNames::kColumnFamilyId, props.column_family_id); |
107 | 4.48k | Add(TablePropertiesNames::kCreationTime, props.creation_time); |
108 | 4.48k | Add(TablePropertiesNames::kOldestKeyTime, props.oldest_key_time); |
109 | 4.48k | if (props.file_creation_time > 0) { |
110 | 0 | Add(TablePropertiesNames::kFileCreationTime, props.file_creation_time); |
111 | 0 | } |
112 | 4.48k | if (props.slow_compression_estimated_data_size > 0) { |
113 | 0 | Add(TablePropertiesNames::kSlowCompressionEstimatedDataSize, |
114 | 0 | props.slow_compression_estimated_data_size); |
115 | 0 | } |
116 | 4.48k | if (props.fast_compression_estimated_data_size > 0) { |
117 | 0 | Add(TablePropertiesNames::kFastCompressionEstimatedDataSize, |
118 | 0 | props.fast_compression_estimated_data_size); |
119 | 0 | } |
120 | 4.48k | Add(TablePropertiesNames::kTailStartOffset, props.tail_start_offset); |
121 | 4.48k | if (props.user_defined_timestamps_persisted == 0) { |
122 | 0 | Add(TablePropertiesNames::kUserDefinedTimestampsPersisted, |
123 | 0 | props.user_defined_timestamps_persisted); |
124 | 0 | } |
125 | 4.48k | if (!props.db_id.empty()) { |
126 | 4.48k | Add(TablePropertiesNames::kDbId, props.db_id); |
127 | 4.48k | } |
128 | 4.48k | if (!props.db_session_id.empty()) { |
129 | 4.48k | Add(TablePropertiesNames::kDbSessionId, props.db_session_id); |
130 | 4.48k | } |
131 | 4.48k | if (!props.db_host_id.empty()) { |
132 | 4.48k | Add(TablePropertiesNames::kDbHostId, props.db_host_id); |
133 | 4.48k | } |
134 | | |
135 | 4.48k | if (!props.filter_policy_name.empty()) { |
136 | 0 | Add(TablePropertiesNames::kFilterPolicy, props.filter_policy_name); |
137 | 0 | } |
138 | 4.48k | if (!props.comparator_name.empty()) { |
139 | 4.48k | Add(TablePropertiesNames::kComparator, props.comparator_name); |
140 | 4.48k | } |
141 | | |
142 | 4.48k | if (!props.merge_operator_name.empty()) { |
143 | 4.48k | Add(TablePropertiesNames::kMergeOperator, props.merge_operator_name); |
144 | 4.48k | } |
145 | 4.48k | if (!props.prefix_extractor_name.empty()) { |
146 | 4.48k | Add(TablePropertiesNames::kPrefixExtractorName, |
147 | 4.48k | props.prefix_extractor_name); |
148 | 4.48k | } |
149 | 4.48k | if (!props.property_collectors_names.empty()) { |
150 | 4.48k | Add(TablePropertiesNames::kPropertyCollectors, |
151 | 4.48k | props.property_collectors_names); |
152 | 4.48k | } |
153 | 4.48k | if (!props.column_family_name.empty()) { |
154 | 4.48k | Add(TablePropertiesNames::kColumnFamilyName, props.column_family_name); |
155 | 4.48k | } |
156 | | |
157 | 4.48k | if (!props.compression_name.empty()) { |
158 | 4.48k | Add(TablePropertiesNames::kCompression, props.compression_name); |
159 | 4.48k | } |
160 | 4.48k | if (!props.compression_options.empty()) { |
161 | 4.48k | Add(TablePropertiesNames::kCompressionOptions, props.compression_options); |
162 | 4.48k | } |
163 | 4.48k | if (!props.seqno_to_time_mapping.empty()) { |
164 | 0 | Add(TablePropertiesNames::kSequenceNumberTimeMapping, |
165 | 0 | props.seqno_to_time_mapping); |
166 | 0 | } |
167 | 4.48k | } |
168 | | |
169 | 4.48k | Slice PropertyBlockBuilder::Finish() { |
170 | 147k | for (const auto& prop : props_) { |
171 | 147k | properties_block_->Add(prop.first, prop.second); |
172 | 147k | } |
173 | | |
174 | 4.48k | return properties_block_->Finish(); |
175 | 4.48k | } |
176 | | |
177 | | void LogPropertiesCollectionError(Logger* info_log, const std::string& method, |
178 | 0 | const std::string& name) { |
179 | 0 | assert(method == "Add" || method == "Finish"); |
180 | |
|
181 | 0 | std::string msg = |
182 | 0 | "Encountered error when calling TablePropertiesCollector::" + method + |
183 | 0 | "() with collector name: " + name; |
184 | 0 | ROCKS_LOG_ERROR(info_log, "%s", msg.c_str()); |
185 | 0 | } |
186 | | |
187 | | bool NotifyCollectTableCollectorsOnAdd( |
188 | | const Slice& key, const Slice& value, uint64_t file_size, |
189 | | const std::vector<std::unique_ptr<InternalTblPropColl>>& collectors, |
190 | 165k | Logger* info_log) { |
191 | 165k | bool all_succeeded = true; |
192 | 165k | for (auto& collector : collectors) { |
193 | 165k | Status s = collector->InternalAdd(key, value, file_size); |
194 | 165k | all_succeeded = all_succeeded && s.ok(); |
195 | 165k | if (!s.ok()) { |
196 | 0 | LogPropertiesCollectionError(info_log, "Add" /* method */, |
197 | 0 | collector->Name()); |
198 | 0 | } |
199 | 165k | } |
200 | 165k | return all_succeeded; |
201 | 165k | } |
202 | | |
203 | | void NotifyCollectTableCollectorsOnBlockAdd( |
204 | | const std::vector<std::unique_ptr<InternalTblPropColl>>& collectors, |
205 | | const uint64_t block_uncomp_bytes, |
206 | | const uint64_t block_compressed_bytes_fast, |
207 | 13.3k | const uint64_t block_compressed_bytes_slow) { |
208 | 13.3k | for (auto& collector : collectors) { |
209 | 13.3k | collector->BlockAdd(block_uncomp_bytes, block_compressed_bytes_fast, |
210 | 13.3k | block_compressed_bytes_slow); |
211 | 13.3k | } |
212 | 13.3k | } |
213 | | |
214 | | bool NotifyCollectTableCollectorsOnFinish( |
215 | | const std::vector<std::unique_ptr<InternalTblPropColl>>& collectors, |
216 | | Logger* info_log, PropertyBlockBuilder* builder, |
217 | | UserCollectedProperties& user_collected_properties, |
218 | 4.48k | UserCollectedProperties& readable_properties) { |
219 | 4.48k | bool all_succeeded = true; |
220 | 4.48k | for (auto& collector : collectors) { |
221 | 4.48k | Status s = collector->Finish(&user_collected_properties); |
222 | 4.48k | if (s.ok()) { |
223 | 4.48k | for (const auto& prop : collector->GetReadableProperties()) { |
224 | 0 | readable_properties.insert(prop); |
225 | 0 | } |
226 | 4.48k | builder->Add(user_collected_properties); |
227 | 4.48k | } else { |
228 | 0 | LogPropertiesCollectionError(info_log, "Finish" /* method */, |
229 | 0 | collector->Name()); |
230 | 0 | if (all_succeeded) { |
231 | 0 | all_succeeded = false; |
232 | 0 | } |
233 | 0 | } |
234 | 4.48k | } |
235 | 4.48k | return all_succeeded; |
236 | 4.48k | } |
237 | | |
238 | | // FIXME: should be a parameter for reading table properties to use persistent |
239 | | // cache? |
240 | | Status ReadTablePropertiesHelper( |
241 | | const ReadOptions& ro, const BlockHandle& handle, |
242 | | RandomAccessFileReader* file, FilePrefetchBuffer* prefetch_buffer, |
243 | | const Footer& footer, const ImmutableOptions& ioptions, |
244 | | std::unique_ptr<TableProperties>* table_properties, |
245 | 4.48k | MemoryAllocator* memory_allocator) { |
246 | 4.48k | assert(table_properties); |
247 | | |
248 | | // If this is an external SST file ingested with write_global_seqno set to |
249 | | // true, then we expect the checksum mismatch because checksum was written |
250 | | // by SstFileWriter, but its global seqno in the properties block may have |
251 | | // been changed during ingestion. For this reason, we initially read |
252 | | // and process without checksum verification, then later try checksum |
253 | | // verification so that if it fails, we can copy to a temporary buffer with |
254 | | // global seqno set to its original value, i.e. 0, and attempt checksum |
255 | | // verification again. |
256 | 4.48k | ReadOptions modified_ro = ro; |
257 | 4.48k | modified_ro.verify_checksums = false; |
258 | 4.48k | BlockContents block_contents; |
259 | 4.48k | BlockFetcher block_fetcher(file, prefetch_buffer, footer, modified_ro, handle, |
260 | 4.48k | &block_contents, ioptions, false /* decompress */, |
261 | 4.48k | false /*maybe_compressed*/, BlockType::kProperties, |
262 | 4.48k | UncompressionDict::GetEmptyDict(), |
263 | 4.48k | PersistentCacheOptions::kEmpty, memory_allocator); |
264 | 4.48k | Status s = block_fetcher.ReadBlockContents(); |
265 | 4.48k | if (!s.ok()) { |
266 | 0 | return s; |
267 | 0 | } |
268 | | |
269 | | // Unfortunately, Block::size() might not equal block_contents.data.size(), |
270 | | // and Block hides block_contents |
271 | 4.48k | uint64_t block_size = block_contents.data.size(); |
272 | 4.48k | Block properties_block(std::move(block_contents)); |
273 | 4.48k | std::unique_ptr<MetaBlockIter> iter(properties_block.NewMetaIterator()); |
274 | | |
275 | 4.48k | std::unique_ptr<TableProperties> new_table_properties{new TableProperties}; |
276 | | // All pre-defined properties of type uint64_t |
277 | 4.48k | std::unordered_map<std::string, uint64_t*> predefined_uint64_properties = { |
278 | 4.48k | {TablePropertiesNames::kOriginalFileNumber, |
279 | 4.48k | &new_table_properties->orig_file_number}, |
280 | 4.48k | {TablePropertiesNames::kDataSize, &new_table_properties->data_size}, |
281 | 4.48k | {TablePropertiesNames::kIndexSize, &new_table_properties->index_size}, |
282 | 4.48k | {TablePropertiesNames::kIndexPartitions, |
283 | 4.48k | &new_table_properties->index_partitions}, |
284 | 4.48k | {TablePropertiesNames::kTopLevelIndexSize, |
285 | 4.48k | &new_table_properties->top_level_index_size}, |
286 | 4.48k | {TablePropertiesNames::kIndexKeyIsUserKey, |
287 | 4.48k | &new_table_properties->index_key_is_user_key}, |
288 | 4.48k | {TablePropertiesNames::kIndexValueIsDeltaEncoded, |
289 | 4.48k | &new_table_properties->index_value_is_delta_encoded}, |
290 | 4.48k | {TablePropertiesNames::kFilterSize, &new_table_properties->filter_size}, |
291 | 4.48k | {TablePropertiesNames::kRawKeySize, &new_table_properties->raw_key_size}, |
292 | 4.48k | {TablePropertiesNames::kRawValueSize, |
293 | 4.48k | &new_table_properties->raw_value_size}, |
294 | 4.48k | {TablePropertiesNames::kNumDataBlocks, |
295 | 4.48k | &new_table_properties->num_data_blocks}, |
296 | 4.48k | {TablePropertiesNames::kNumEntries, &new_table_properties->num_entries}, |
297 | 4.48k | {TablePropertiesNames::kNumFilterEntries, |
298 | 4.48k | &new_table_properties->num_filter_entries}, |
299 | 4.48k | {TablePropertiesNames::kDeletedKeys, |
300 | 4.48k | &new_table_properties->num_deletions}, |
301 | 4.48k | {TablePropertiesNames::kMergeOperands, |
302 | 4.48k | &new_table_properties->num_merge_operands}, |
303 | 4.48k | {TablePropertiesNames::kNumRangeDeletions, |
304 | 4.48k | &new_table_properties->num_range_deletions}, |
305 | 4.48k | {TablePropertiesNames::kFormatVersion, |
306 | 4.48k | &new_table_properties->format_version}, |
307 | 4.48k | {TablePropertiesNames::kFixedKeyLen, |
308 | 4.48k | &new_table_properties->fixed_key_len}, |
309 | 4.48k | {TablePropertiesNames::kColumnFamilyId, |
310 | 4.48k | &new_table_properties->column_family_id}, |
311 | 4.48k | {TablePropertiesNames::kCreationTime, |
312 | 4.48k | &new_table_properties->creation_time}, |
313 | 4.48k | {TablePropertiesNames::kOldestKeyTime, |
314 | 4.48k | &new_table_properties->oldest_key_time}, |
315 | 4.48k | {TablePropertiesNames::kFileCreationTime, |
316 | 4.48k | &new_table_properties->file_creation_time}, |
317 | 4.48k | {TablePropertiesNames::kSlowCompressionEstimatedDataSize, |
318 | 4.48k | &new_table_properties->slow_compression_estimated_data_size}, |
319 | 4.48k | {TablePropertiesNames::kFastCompressionEstimatedDataSize, |
320 | 4.48k | &new_table_properties->fast_compression_estimated_data_size}, |
321 | 4.48k | {TablePropertiesNames::kTailStartOffset, |
322 | 4.48k | &new_table_properties->tail_start_offset}, |
323 | 4.48k | {TablePropertiesNames::kUserDefinedTimestampsPersisted, |
324 | 4.48k | &new_table_properties->user_defined_timestamps_persisted}, |
325 | 4.48k | }; |
326 | | |
327 | 4.48k | std::string last_key; |
328 | 152k | for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { |
329 | 147k | s = iter->status(); |
330 | 147k | if (!s.ok()) { |
331 | 0 | break; |
332 | 0 | } |
333 | | |
334 | 147k | auto key = iter->key().ToString(); |
335 | | // properties block should be strictly sorted with no duplicate key. |
336 | 147k | if (!last_key.empty() && |
337 | 147k | BytewiseComparator()->Compare(key, last_key) <= 0) { |
338 | 0 | s = Status::Corruption("properties unsorted"); |
339 | 0 | break; |
340 | 0 | } |
341 | 147k | last_key = key; |
342 | | |
343 | 147k | auto raw_val = iter->value(); |
344 | 147k | auto pos = predefined_uint64_properties.find(key); |
345 | | |
346 | 147k | if (key == ExternalSstFilePropertyNames::kGlobalSeqno) { |
347 | 0 | new_table_properties->external_sst_file_global_seqno_offset = |
348 | 0 | handle.offset() + iter->ValueOffset(); |
349 | 0 | } |
350 | | |
351 | 147k | if (pos != predefined_uint64_properties.end()) { |
352 | 89.6k | if (key == TablePropertiesNames::kDeletedKeys || |
353 | 89.6k | key == TablePropertiesNames::kMergeOperands) { |
354 | | // Insert in user-collected properties for API backwards compatibility |
355 | 8.96k | new_table_properties->user_collected_properties.insert( |
356 | 8.96k | {key, raw_val.ToString()}); |
357 | 8.96k | } |
358 | | // handle predefined rocksdb properties |
359 | 89.6k | uint64_t val; |
360 | 89.6k | if (!GetVarint64(&raw_val, &val)) { |
361 | | // skip malformed value |
362 | 0 | auto error_msg = |
363 | 0 | "Detect malformed value in properties meta-block:" |
364 | 0 | "\tkey: " + |
365 | 0 | key + "\tval: " + raw_val.ToString(); |
366 | 0 | ROCKS_LOG_ERROR(ioptions.logger, "%s", error_msg.c_str()); |
367 | 0 | continue; |
368 | 0 | } |
369 | 89.6k | *(pos->second) = val; |
370 | 89.6k | } else if (key == TablePropertiesNames::kDbId) { |
371 | 4.48k | new_table_properties->db_id = raw_val.ToString(); |
372 | 53.8k | } else if (key == TablePropertiesNames::kDbSessionId) { |
373 | 4.48k | new_table_properties->db_session_id = raw_val.ToString(); |
374 | 49.3k | } else if (key == TablePropertiesNames::kDbHostId) { |
375 | 4.48k | new_table_properties->db_host_id = raw_val.ToString(); |
376 | 44.8k | } else if (key == TablePropertiesNames::kFilterPolicy) { |
377 | 0 | new_table_properties->filter_policy_name = raw_val.ToString(); |
378 | 44.8k | } else if (key == TablePropertiesNames::kColumnFamilyName) { |
379 | 4.48k | new_table_properties->column_family_name = raw_val.ToString(); |
380 | 40.3k | } else if (key == TablePropertiesNames::kComparator) { |
381 | 4.48k | new_table_properties->comparator_name = raw_val.ToString(); |
382 | 35.8k | } else if (key == TablePropertiesNames::kMergeOperator) { |
383 | 4.48k | new_table_properties->merge_operator_name = raw_val.ToString(); |
384 | 31.3k | } else if (key == TablePropertiesNames::kPrefixExtractorName) { |
385 | 4.48k | new_table_properties->prefix_extractor_name = raw_val.ToString(); |
386 | 26.9k | } else if (key == TablePropertiesNames::kPropertyCollectors) { |
387 | 4.48k | new_table_properties->property_collectors_names = raw_val.ToString(); |
388 | 22.4k | } else if (key == TablePropertiesNames::kCompression) { |
389 | 4.48k | new_table_properties->compression_name = raw_val.ToString(); |
390 | 17.9k | } else if (key == TablePropertiesNames::kCompressionOptions) { |
391 | 4.48k | new_table_properties->compression_options = raw_val.ToString(); |
392 | 13.4k | } else if (key == TablePropertiesNames::kSequenceNumberTimeMapping) { |
393 | 0 | new_table_properties->seqno_to_time_mapping = raw_val.ToString(); |
394 | 13.4k | } else { |
395 | | // handle user-collected properties |
396 | 13.4k | new_table_properties->user_collected_properties.insert( |
397 | 13.4k | {key, raw_val.ToString()}); |
398 | 13.4k | } |
399 | 147k | } |
400 | | |
401 | | // Modified version of BlockFetcher checksum verification |
402 | | // (See write_global_seqno comment above) |
403 | 4.48k | if (s.ok() && footer.GetBlockTrailerSize() > 0) { |
404 | 4.48k | s = VerifyBlockChecksum(footer, properties_block.data(), block_size, |
405 | 4.48k | file->file_name(), handle.offset()); |
406 | 4.48k | if (s.IsCorruption()) { |
407 | 0 | if (new_table_properties->external_sst_file_global_seqno_offset != 0) { |
408 | 0 | std::string tmp_buf(properties_block.data(), |
409 | 0 | block_fetcher.GetBlockSizeWithTrailer()); |
410 | 0 | uint64_t global_seqno_offset = |
411 | 0 | new_table_properties->external_sst_file_global_seqno_offset - |
412 | 0 | handle.offset(); |
413 | 0 | EncodeFixed64(&tmp_buf[static_cast<size_t>(global_seqno_offset)], 0); |
414 | 0 | s = VerifyBlockChecksum(footer, tmp_buf.data(), block_size, |
415 | 0 | file->file_name(), handle.offset()); |
416 | 0 | } |
417 | 0 | } |
418 | 4.48k | } |
419 | | |
420 | 4.48k | if (s.ok()) { |
421 | 4.48k | *table_properties = std::move(new_table_properties); |
422 | 4.48k | } |
423 | | |
424 | 4.48k | return s; |
425 | 4.48k | } |
426 | | |
427 | | Status ReadTableProperties(RandomAccessFileReader* file, uint64_t file_size, |
428 | | uint64_t table_magic_number, |
429 | | const ImmutableOptions& ioptions, |
430 | | const ReadOptions& read_options, |
431 | | std::unique_ptr<TableProperties>* properties, |
432 | | MemoryAllocator* memory_allocator, |
433 | 0 | FilePrefetchBuffer* prefetch_buffer) { |
434 | 0 | BlockHandle block_handle; |
435 | 0 | Footer footer; |
436 | 0 | Status s = |
437 | 0 | FindMetaBlockInFile(file, file_size, table_magic_number, ioptions, |
438 | 0 | read_options, kPropertiesBlockName, &block_handle, |
439 | 0 | memory_allocator, prefetch_buffer, &footer); |
440 | 0 | if (!s.ok()) { |
441 | 0 | return s; |
442 | 0 | } |
443 | | |
444 | 0 | if (!block_handle.IsNull()) { |
445 | 0 | s = ReadTablePropertiesHelper(read_options, block_handle, file, |
446 | 0 | prefetch_buffer, footer, ioptions, properties, |
447 | 0 | memory_allocator); |
448 | 0 | } else { |
449 | 0 | s = Status::NotFound(); |
450 | 0 | } |
451 | 0 | return s; |
452 | 0 | } |
453 | | |
454 | | Status FindOptionalMetaBlock(InternalIterator* meta_index_iter, |
455 | | const std::string& meta_block_name, |
456 | 17.9k | BlockHandle* block_handle) { |
457 | 17.9k | assert(block_handle != nullptr); |
458 | 17.9k | meta_index_iter->Seek(meta_block_name); |
459 | 17.9k | if (meta_index_iter->status().ok()) { |
460 | 17.9k | if (meta_index_iter->Valid() && meta_index_iter->key() == meta_block_name) { |
461 | 11.8k | Slice v = meta_index_iter->value(); |
462 | 11.8k | return block_handle->DecodeFrom(&v); |
463 | 11.8k | } else if (meta_block_name == kPropertiesBlockName) { |
464 | | // Have to try old name for compatibility |
465 | 0 | meta_index_iter->Seek(kPropertiesBlockOldName); |
466 | 0 | if (meta_index_iter->status().ok() && meta_index_iter->Valid() && |
467 | 0 | meta_index_iter->key() == kPropertiesBlockOldName) { |
468 | 0 | Slice v = meta_index_iter->value(); |
469 | 0 | return block_handle->DecodeFrom(&v); |
470 | 0 | } |
471 | 0 | } |
472 | 17.9k | } |
473 | | // else |
474 | 6.06k | *block_handle = BlockHandle::NullBlockHandle(); |
475 | 6.06k | return meta_index_iter->status(); |
476 | 17.9k | } |
477 | | |
478 | | Status FindMetaBlock(InternalIterator* meta_index_iter, |
479 | | const std::string& meta_block_name, |
480 | 4.48k | BlockHandle* block_handle) { |
481 | 4.48k | Status s = |
482 | 4.48k | FindOptionalMetaBlock(meta_index_iter, meta_block_name, block_handle); |
483 | 4.48k | if (s.ok() && block_handle->IsNull()) { |
484 | 0 | return Status::Corruption("Cannot find the meta block", meta_block_name); |
485 | 4.48k | } else { |
486 | 4.48k | return s; |
487 | 4.48k | } |
488 | 4.48k | } |
489 | | |
490 | | Status ReadMetaIndexBlockInFile(RandomAccessFileReader* file, |
491 | | uint64_t file_size, uint64_t table_magic_number, |
492 | | const ImmutableOptions& ioptions, |
493 | | const ReadOptions& read_options, |
494 | | BlockContents* metaindex_contents, |
495 | | MemoryAllocator* memory_allocator, |
496 | | FilePrefetchBuffer* prefetch_buffer, |
497 | 0 | Footer* footer_out) { |
498 | 0 | Footer footer; |
499 | 0 | IOOptions opts; |
500 | 0 | Status s; |
501 | 0 | s = file->PrepareIOOptions(read_options, opts); |
502 | 0 | if (!s.ok()) { |
503 | 0 | return s; |
504 | 0 | } |
505 | 0 | s = ReadFooterFromFile(opts, file, *ioptions.fs, prefetch_buffer, file_size, |
506 | 0 | &footer, table_magic_number); |
507 | 0 | if (!s.ok()) { |
508 | 0 | return s; |
509 | 0 | } |
510 | 0 | if (footer_out) { |
511 | 0 | *footer_out = footer; |
512 | 0 | } |
513 | |
|
514 | 0 | auto metaindex_handle = footer.metaindex_handle(); |
515 | 0 | return BlockFetcher(file, prefetch_buffer, footer, read_options, |
516 | 0 | metaindex_handle, metaindex_contents, ioptions, |
517 | 0 | false /* do decompression */, false /*maybe_compressed*/, |
518 | 0 | BlockType::kMetaIndex, UncompressionDict::GetEmptyDict(), |
519 | 0 | PersistentCacheOptions::kEmpty, memory_allocator) |
520 | 0 | .ReadBlockContents(); |
521 | 0 | } |
522 | | |
523 | | Status FindMetaBlockInFile( |
524 | | RandomAccessFileReader* file, uint64_t file_size, |
525 | | uint64_t table_magic_number, const ImmutableOptions& ioptions, |
526 | | const ReadOptions& read_options, const std::string& meta_block_name, |
527 | | BlockHandle* block_handle, MemoryAllocator* memory_allocator, |
528 | 0 | FilePrefetchBuffer* prefetch_buffer, Footer* footer_out) { |
529 | 0 | BlockContents metaindex_contents; |
530 | 0 | auto s = ReadMetaIndexBlockInFile( |
531 | 0 | file, file_size, table_magic_number, ioptions, read_options, |
532 | 0 | &metaindex_contents, memory_allocator, prefetch_buffer, footer_out); |
533 | 0 | if (!s.ok()) { |
534 | 0 | return s; |
535 | 0 | } |
536 | | // meta blocks are never compressed. Need to add uncompress logic if we are to |
537 | | // compress it. |
538 | 0 | Block metaindex_block(std::move(metaindex_contents)); |
539 | |
|
540 | 0 | std::unique_ptr<InternalIterator> meta_iter; |
541 | 0 | meta_iter.reset(metaindex_block.NewMetaIterator()); |
542 | |
|
543 | 0 | return FindMetaBlock(meta_iter.get(), meta_block_name, block_handle); |
544 | 0 | } |
545 | | |
546 | | Status ReadMetaBlock(RandomAccessFileReader* file, |
547 | | FilePrefetchBuffer* prefetch_buffer, uint64_t file_size, |
548 | | uint64_t table_magic_number, |
549 | | const ImmutableOptions& ioptions, |
550 | | const ReadOptions& read_options, |
551 | | const std::string& meta_block_name, BlockType block_type, |
552 | | BlockContents* contents, |
553 | 0 | MemoryAllocator* memory_allocator) { |
554 | | // TableProperties requires special handling because of checksum issues. |
555 | | // Call ReadTableProperties instead for that case. |
556 | 0 | assert(block_type != BlockType::kProperties); |
557 | |
|
558 | 0 | BlockHandle block_handle; |
559 | 0 | Footer footer; |
560 | 0 | Status status = |
561 | 0 | FindMetaBlockInFile(file, file_size, table_magic_number, ioptions, |
562 | 0 | read_options, meta_block_name, &block_handle, |
563 | 0 | memory_allocator, prefetch_buffer, &footer); |
564 | 0 | if (!status.ok()) { |
565 | 0 | return status; |
566 | 0 | } |
567 | | |
568 | 0 | return BlockFetcher(file, prefetch_buffer, footer, read_options, block_handle, |
569 | 0 | contents, ioptions, false /* decompress */, |
570 | 0 | false /*maybe_compressed*/, block_type, |
571 | 0 | UncompressionDict::GetEmptyDict(), |
572 | 0 | PersistentCacheOptions::kEmpty, memory_allocator) |
573 | 0 | .ReadBlockContents(); |
574 | 0 | } |
575 | | |
576 | | } // namespace ROCKSDB_NAMESPACE |