| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525 |
- // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
- // This source code is licensed under both the GPLv2 (found in the
- // COPYING file in the root directory) and Apache 2.0 License
- // (found in the LICENSE.Apache file in the root directory).
- #include "table/meta_blocks.h"
- #include <map>
- #include <string>
- #include "block_fetcher.h"
- #include "db/table_properties_collector.h"
- #include "file/random_access_file_reader.h"
- #include "rocksdb/table.h"
- #include "rocksdb/table_properties.h"
- #include "table/block_based/block.h"
- #include "table/format.h"
- #include "table/internal_iterator.h"
- #include "table/persistent_cache_helper.h"
- #include "table/table_properties_internal.h"
- #include "test_util/sync_point.h"
- #include "util/coding.h"
- namespace ROCKSDB_NAMESPACE {
- MetaIndexBuilder::MetaIndexBuilder()
- : meta_index_block_(new BlockBuilder(1 /* restart interval */)) {}
- void MetaIndexBuilder::Add(const std::string& key,
- const BlockHandle& handle) {
- std::string handle_encoding;
- handle.EncodeTo(&handle_encoding);
- meta_block_handles_.insert({key, handle_encoding});
- }
- Slice MetaIndexBuilder::Finish() {
- for (const auto& metablock : meta_block_handles_) {
- meta_index_block_->Add(metablock.first, metablock.second);
- }
- return meta_index_block_->Finish();
- }
- // Property block will be read sequentially and cached in a heap located
- // object, so there's no need for restart points. Thus we set the restart
- // interval to infinity to save space.
- PropertyBlockBuilder::PropertyBlockBuilder()
- : properties_block_(
- new BlockBuilder(port::kMaxInt32 /* restart interval */)) {}
- void PropertyBlockBuilder::Add(const std::string& name,
- const std::string& val) {
- props_.insert({name, val});
- }
- void PropertyBlockBuilder::Add(const std::string& name, uint64_t val) {
- assert(props_.find(name) == props_.end());
- std::string dst;
- PutVarint64(&dst, val);
- Add(name, dst);
- }
- void PropertyBlockBuilder::Add(
- const UserCollectedProperties& user_collected_properties) {
- for (const auto& prop : user_collected_properties) {
- Add(prop.first, prop.second);
- }
- }
- void PropertyBlockBuilder::AddTableProperty(const TableProperties& props) {
- TEST_SYNC_POINT_CALLBACK("PropertyBlockBuilder::AddTableProperty:Start",
- const_cast<TableProperties*>(&props));
- Add(TablePropertiesNames::kRawKeySize, props.raw_key_size);
- Add(TablePropertiesNames::kRawValueSize, props.raw_value_size);
- Add(TablePropertiesNames::kDataSize, props.data_size);
- Add(TablePropertiesNames::kIndexSize, props.index_size);
- if (props.index_partitions != 0) {
- Add(TablePropertiesNames::kIndexPartitions, props.index_partitions);
- Add(TablePropertiesNames::kTopLevelIndexSize, props.top_level_index_size);
- }
- Add(TablePropertiesNames::kIndexKeyIsUserKey, props.index_key_is_user_key);
- Add(TablePropertiesNames::kIndexValueIsDeltaEncoded,
- props.index_value_is_delta_encoded);
- Add(TablePropertiesNames::kNumEntries, props.num_entries);
- Add(TablePropertiesNames::kDeletedKeys, props.num_deletions);
- Add(TablePropertiesNames::kMergeOperands, props.num_merge_operands);
- Add(TablePropertiesNames::kNumRangeDeletions, props.num_range_deletions);
- Add(TablePropertiesNames::kNumDataBlocks, props.num_data_blocks);
- Add(TablePropertiesNames::kFilterSize, props.filter_size);
- Add(TablePropertiesNames::kFormatVersion, props.format_version);
- Add(TablePropertiesNames::kFixedKeyLen, props.fixed_key_len);
- Add(TablePropertiesNames::kColumnFamilyId, props.column_family_id);
- Add(TablePropertiesNames::kCreationTime, props.creation_time);
- Add(TablePropertiesNames::kOldestKeyTime, props.oldest_key_time);
- if (props.file_creation_time > 0) {
- Add(TablePropertiesNames::kFileCreationTime, props.file_creation_time);
- }
- if (!props.filter_policy_name.empty()) {
- Add(TablePropertiesNames::kFilterPolicy, props.filter_policy_name);
- }
- if (!props.comparator_name.empty()) {
- Add(TablePropertiesNames::kComparator, props.comparator_name);
- }
- if (!props.merge_operator_name.empty()) {
- Add(TablePropertiesNames::kMergeOperator, props.merge_operator_name);
- }
- if (!props.prefix_extractor_name.empty()) {
- Add(TablePropertiesNames::kPrefixExtractorName,
- props.prefix_extractor_name);
- }
- if (!props.property_collectors_names.empty()) {
- Add(TablePropertiesNames::kPropertyCollectors,
- props.property_collectors_names);
- }
- if (!props.column_family_name.empty()) {
- Add(TablePropertiesNames::kColumnFamilyName, props.column_family_name);
- }
- if (!props.compression_name.empty()) {
- Add(TablePropertiesNames::kCompression, props.compression_name);
- }
- if (!props.compression_options.empty()) {
- Add(TablePropertiesNames::kCompressionOptions, props.compression_options);
- }
- }
- Slice PropertyBlockBuilder::Finish() {
- for (const auto& prop : props_) {
- properties_block_->Add(prop.first, prop.second);
- }
- return properties_block_->Finish();
- }
- void LogPropertiesCollectionError(
- Logger* info_log, const std::string& method, const std::string& name) {
- assert(method == "Add" || method == "Finish");
- std::string msg =
- "Encountered error when calling TablePropertiesCollector::" +
- method + "() with collector name: " + name;
- ROCKS_LOG_ERROR(info_log, "%s", msg.c_str());
- }
- bool NotifyCollectTableCollectorsOnAdd(
- const Slice& key, const Slice& value, uint64_t file_size,
- const std::vector<std::unique_ptr<IntTblPropCollector>>& collectors,
- Logger* info_log) {
- bool all_succeeded = true;
- for (auto& collector : collectors) {
- Status s = collector->InternalAdd(key, value, file_size);
- all_succeeded = all_succeeded && s.ok();
- if (!s.ok()) {
- LogPropertiesCollectionError(info_log, "Add" /* method */,
- collector->Name());
- }
- }
- return all_succeeded;
- }
- void NotifyCollectTableCollectorsOnBlockAdd(
- const std::vector<std::unique_ptr<IntTblPropCollector>>& collectors,
- const uint64_t blockRawBytes, const uint64_t blockCompressedBytesFast,
- const uint64_t blockCompressedBytesSlow) {
- for (auto& collector : collectors) {
- collector->BlockAdd(blockRawBytes, blockCompressedBytesFast,
- blockCompressedBytesSlow);
- }
- }
- bool NotifyCollectTableCollectorsOnFinish(
- const std::vector<std::unique_ptr<IntTblPropCollector>>& collectors,
- Logger* info_log, PropertyBlockBuilder* builder) {
- bool all_succeeded = true;
- for (auto& collector : collectors) {
- UserCollectedProperties user_collected_properties;
- Status s = collector->Finish(&user_collected_properties);
- all_succeeded = all_succeeded && s.ok();
- if (!s.ok()) {
- LogPropertiesCollectionError(info_log, "Finish" /* method */,
- collector->Name());
- } else {
- builder->Add(user_collected_properties);
- }
- }
- return all_succeeded;
- }
- Status ReadProperties(const Slice& handle_value, RandomAccessFileReader* file,
- FilePrefetchBuffer* prefetch_buffer, const Footer& footer,
- const ImmutableCFOptions& ioptions,
- TableProperties** table_properties, bool verify_checksum,
- BlockHandle* ret_block_handle,
- CacheAllocationPtr* verification_buf,
- bool /*compression_type_missing*/,
- MemoryAllocator* memory_allocator) {
- assert(table_properties);
- Slice v = handle_value;
- BlockHandle handle;
- if (!handle.DecodeFrom(&v).ok()) {
- return Status::InvalidArgument("Failed to decode properties block handle");
- }
- BlockContents block_contents;
- ReadOptions read_options;
- read_options.verify_checksums = verify_checksum;
- Status s;
- PersistentCacheOptions cache_options;
- BlockFetcher block_fetcher(
- file, prefetch_buffer, footer, read_options, handle, &block_contents,
- ioptions, false /* decompress */, false /*maybe_compressed*/,
- BlockType::kProperties, UncompressionDict::GetEmptyDict(), cache_options,
- memory_allocator);
- s = block_fetcher.ReadBlockContents();
- // property block is never compressed. Need to add uncompress logic if we are
- // to compress it..
- if (!s.ok()) {
- return s;
- }
- Block properties_block(std::move(block_contents),
- kDisableGlobalSequenceNumber);
- DataBlockIter iter;
- properties_block.NewDataIterator(BytewiseComparator(), BytewiseComparator(),
- &iter);
- auto new_table_properties = new TableProperties();
- // All pre-defined properties of type uint64_t
- std::unordered_map<std::string, uint64_t*> predefined_uint64_properties = {
- {TablePropertiesNames::kDataSize, &new_table_properties->data_size},
- {TablePropertiesNames::kIndexSize, &new_table_properties->index_size},
- {TablePropertiesNames::kIndexPartitions,
- &new_table_properties->index_partitions},
- {TablePropertiesNames::kTopLevelIndexSize,
- &new_table_properties->top_level_index_size},
- {TablePropertiesNames::kIndexKeyIsUserKey,
- &new_table_properties->index_key_is_user_key},
- {TablePropertiesNames::kIndexValueIsDeltaEncoded,
- &new_table_properties->index_value_is_delta_encoded},
- {TablePropertiesNames::kFilterSize, &new_table_properties->filter_size},
- {TablePropertiesNames::kRawKeySize, &new_table_properties->raw_key_size},
- {TablePropertiesNames::kRawValueSize,
- &new_table_properties->raw_value_size},
- {TablePropertiesNames::kNumDataBlocks,
- &new_table_properties->num_data_blocks},
- {TablePropertiesNames::kNumEntries, &new_table_properties->num_entries},
- {TablePropertiesNames::kDeletedKeys,
- &new_table_properties->num_deletions},
- {TablePropertiesNames::kMergeOperands,
- &new_table_properties->num_merge_operands},
- {TablePropertiesNames::kNumRangeDeletions,
- &new_table_properties->num_range_deletions},
- {TablePropertiesNames::kFormatVersion,
- &new_table_properties->format_version},
- {TablePropertiesNames::kFixedKeyLen,
- &new_table_properties->fixed_key_len},
- {TablePropertiesNames::kColumnFamilyId,
- &new_table_properties->column_family_id},
- {TablePropertiesNames::kCreationTime,
- &new_table_properties->creation_time},
- {TablePropertiesNames::kOldestKeyTime,
- &new_table_properties->oldest_key_time},
- {TablePropertiesNames::kFileCreationTime,
- &new_table_properties->file_creation_time},
- };
- std::string last_key;
- for (iter.SeekToFirstOrReport(); iter.Valid(); iter.NextOrReport()) {
- s = iter.status();
- if (!s.ok()) {
- break;
- }
- auto key = iter.key().ToString();
- // properties block should be strictly sorted with no duplicate key.
- if (!last_key.empty() &&
- BytewiseComparator()->Compare(key, last_key) <= 0) {
- s = Status::Corruption("properties unsorted");
- break;
- }
- last_key = key;
- auto raw_val = iter.value();
- auto pos = predefined_uint64_properties.find(key);
- new_table_properties->properties_offsets.insert(
- {key, handle.offset() + iter.ValueOffset()});
- if (pos != predefined_uint64_properties.end()) {
- if (key == TablePropertiesNames::kDeletedKeys ||
- key == TablePropertiesNames::kMergeOperands) {
- // Insert in user-collected properties for API backwards compatibility
- new_table_properties->user_collected_properties.insert(
- {key, raw_val.ToString()});
- }
- // handle predefined rocksdb properties
- uint64_t val;
- if (!GetVarint64(&raw_val, &val)) {
- // skip malformed value
- auto error_msg =
- "Detect malformed value in properties meta-block:"
- "\tkey: " + key + "\tval: " + raw_val.ToString();
- ROCKS_LOG_ERROR(ioptions.info_log, "%s", error_msg.c_str());
- continue;
- }
- *(pos->second) = val;
- } else if (key == TablePropertiesNames::kFilterPolicy) {
- new_table_properties->filter_policy_name = raw_val.ToString();
- } else if (key == TablePropertiesNames::kColumnFamilyName) {
- new_table_properties->column_family_name = raw_val.ToString();
- } else if (key == TablePropertiesNames::kComparator) {
- new_table_properties->comparator_name = raw_val.ToString();
- } else if (key == TablePropertiesNames::kMergeOperator) {
- new_table_properties->merge_operator_name = raw_val.ToString();
- } else if (key == TablePropertiesNames::kPrefixExtractorName) {
- new_table_properties->prefix_extractor_name = raw_val.ToString();
- } else if (key == TablePropertiesNames::kPropertyCollectors) {
- new_table_properties->property_collectors_names = raw_val.ToString();
- } else if (key == TablePropertiesNames::kCompression) {
- new_table_properties->compression_name = raw_val.ToString();
- } else if (key == TablePropertiesNames::kCompressionOptions) {
- new_table_properties->compression_options = raw_val.ToString();
- } else {
- // handle user-collected properties
- new_table_properties->user_collected_properties.insert(
- {key, raw_val.ToString()});
- }
- }
- if (s.ok()) {
- *table_properties = new_table_properties;
- if (ret_block_handle != nullptr) {
- *ret_block_handle = handle;
- }
- if (verification_buf != nullptr) {
- size_t len = static_cast<size_t>(handle.size() + kBlockTrailerSize);
- *verification_buf =
- ROCKSDB_NAMESPACE::AllocateBlock(len, memory_allocator);
- if (verification_buf->get() != nullptr) {
- memcpy(verification_buf->get(), block_contents.data.data(), len);
- }
- }
- } else {
- delete new_table_properties;
- }
- return s;
- }
- Status ReadTableProperties(RandomAccessFileReader* file, uint64_t file_size,
- uint64_t table_magic_number,
- const ImmutableCFOptions& ioptions,
- TableProperties** properties,
- bool compression_type_missing,
- MemoryAllocator* memory_allocator) {
- // -- Read metaindex block
- Footer footer;
- auto s = ReadFooterFromFile(file, nullptr /* prefetch_buffer */, file_size,
- &footer, table_magic_number);
- if (!s.ok()) {
- return s;
- }
- auto metaindex_handle = footer.metaindex_handle();
- BlockContents metaindex_contents;
- ReadOptions read_options;
- read_options.verify_checksums = false;
- PersistentCacheOptions cache_options;
- BlockFetcher block_fetcher(
- file, nullptr /* prefetch_buffer */, footer, read_options,
- metaindex_handle, &metaindex_contents, ioptions, false /* decompress */,
- false /*maybe_compressed*/, BlockType::kMetaIndex,
- UncompressionDict::GetEmptyDict(), cache_options, memory_allocator);
- s = block_fetcher.ReadBlockContents();
- if (!s.ok()) {
- return s;
- }
- // property blocks are never compressed. Need to add uncompress logic if we
- // are to compress it.
- Block metaindex_block(std::move(metaindex_contents),
- kDisableGlobalSequenceNumber);
- std::unique_ptr<InternalIterator> meta_iter(metaindex_block.NewDataIterator(
- BytewiseComparator(), BytewiseComparator()));
- // -- Read property block
- bool found_properties_block = true;
- s = SeekToPropertiesBlock(meta_iter.get(), &found_properties_block);
- if (!s.ok()) {
- return s;
- }
- TableProperties table_properties;
- if (found_properties_block == true) {
- s = ReadProperties(
- meta_iter->value(), file, nullptr /* prefetch_buffer */, footer,
- ioptions, properties, false /* verify_checksum */,
- nullptr /* ret_block_hanel */, nullptr /* ret_block_contents */,
- compression_type_missing, memory_allocator);
- } else {
- s = Status::NotFound();
- }
- return s;
- }
- Status FindMetaBlock(InternalIterator* meta_index_iter,
- const std::string& meta_block_name,
- BlockHandle* block_handle) {
- meta_index_iter->Seek(meta_block_name);
- if (meta_index_iter->status().ok() && meta_index_iter->Valid() &&
- meta_index_iter->key() == meta_block_name) {
- Slice v = meta_index_iter->value();
- return block_handle->DecodeFrom(&v);
- } else {
- return Status::Corruption("Cannot find the meta block", meta_block_name);
- }
- }
- Status FindMetaBlock(RandomAccessFileReader* file, uint64_t file_size,
- uint64_t table_magic_number,
- const ImmutableCFOptions& ioptions,
- const std::string& meta_block_name,
- BlockHandle* block_handle,
- bool /*compression_type_missing*/,
- MemoryAllocator* memory_allocator) {
- Footer footer;
- auto s = ReadFooterFromFile(file, nullptr /* prefetch_buffer */, file_size,
- &footer, table_magic_number);
- if (!s.ok()) {
- return s;
- }
- auto metaindex_handle = footer.metaindex_handle();
- BlockContents metaindex_contents;
- ReadOptions read_options;
- read_options.verify_checksums = false;
- PersistentCacheOptions cache_options;
- BlockFetcher block_fetcher(
- file, nullptr /* prefetch_buffer */, footer, read_options,
- metaindex_handle, &metaindex_contents, ioptions,
- false /* do decompression */, false /*maybe_compressed*/,
- BlockType::kMetaIndex, UncompressionDict::GetEmptyDict(), cache_options,
- memory_allocator);
- s = block_fetcher.ReadBlockContents();
- if (!s.ok()) {
- return s;
- }
- // meta blocks are never compressed. Need to add uncompress logic if we are to
- // compress it.
- Block metaindex_block(std::move(metaindex_contents),
- kDisableGlobalSequenceNumber);
- std::unique_ptr<InternalIterator> meta_iter;
- meta_iter.reset(metaindex_block.NewDataIterator(BytewiseComparator(),
- BytewiseComparator()));
- return FindMetaBlock(meta_iter.get(), meta_block_name, block_handle);
- }
- Status ReadMetaBlock(RandomAccessFileReader* file,
- FilePrefetchBuffer* prefetch_buffer, uint64_t file_size,
- uint64_t table_magic_number,
- const ImmutableCFOptions& ioptions,
- const std::string& meta_block_name, BlockType block_type,
- BlockContents* contents, bool /*compression_type_missing*/,
- MemoryAllocator* memory_allocator) {
- Status status;
- Footer footer;
- status = ReadFooterFromFile(file, prefetch_buffer, file_size, &footer,
- table_magic_number);
- if (!status.ok()) {
- return status;
- }
- // Reading metaindex block
- auto metaindex_handle = footer.metaindex_handle();
- BlockContents metaindex_contents;
- ReadOptions read_options;
- read_options.verify_checksums = false;
- PersistentCacheOptions cache_options;
- BlockFetcher block_fetcher(
- file, prefetch_buffer, footer, read_options, metaindex_handle,
- &metaindex_contents, ioptions, false /* decompress */,
- false /*maybe_compressed*/, BlockType::kMetaIndex,
- UncompressionDict::GetEmptyDict(), cache_options, memory_allocator);
- status = block_fetcher.ReadBlockContents();
- if (!status.ok()) {
- return status;
- }
- // meta block is never compressed. Need to add uncompress logic if we are to
- // compress it.
- // Finding metablock
- Block metaindex_block(std::move(metaindex_contents),
- kDisableGlobalSequenceNumber);
- std::unique_ptr<InternalIterator> meta_iter;
- meta_iter.reset(metaindex_block.NewDataIterator(BytewiseComparator(),
- BytewiseComparator()));
- BlockHandle block_handle;
- status = FindMetaBlock(meta_iter.get(), meta_block_name, &block_handle);
- if (!status.ok()) {
- return status;
- }
- // Reading metablock
- BlockFetcher block_fetcher2(
- file, prefetch_buffer, footer, read_options, block_handle, contents,
- ioptions, false /* decompress */, false /*maybe_compressed*/, block_type,
- UncompressionDict::GetEmptyDict(), cache_options, memory_allocator);
- return block_fetcher2.ReadBlockContents();
- }
- } // namespace ROCKSDB_NAMESPACE
|