Coverage Report

Created: 2024-07-27 06:53

/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