/
GraphTreeHeap
/
museumdb2
Обзор
Документация
Войти
/
GraphTreeHeap
/
museumdb2
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
table/sst_file_reader.cc
332 строки
12 KB
Xingbo Wang
Add parser for raw table iterator keys (#14726)
13 май 2026, 02:26
13 май 2026, 02:26
cbd61a3
Код
Авторство
О чём код?
// 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 "rocksdb/sst_file_reader.h" #include "db/arena_wrapped_db_iter.h" #include "db/db_iter.h" #include "db/dbformat.h" #include "db/lookup_key.h" #include "file/random_access_file_reader.h" #include "options/cf_options.h" #include "rocksdb/env.h" #include "rocksdb/file_checksum.h" #include "rocksdb/file_system.h" #include "rocksdb/utilities/types_util.h" #include "table/get_context.h" #include "table/table_builder.h" #include "table/table_iterator.h" #include "table/table_reader.h" namespace ROCKSDB_NAMESPACE { struct SstFileReader::Rep { Options options; EnvOptions soptions; ImmutableOptions ioptions; MutableCFOptions moptions; // Keep a member variable for this, since `NewIterator()` uses a const // reference of `ReadOptions`. ReadOptions roptions_for_table_iter; std::unique_ptr<TableReader> table_reader; Rep(const Options& opts) : options(opts), soptions(options), ioptions(options), moptions(ColumnFamilyOptions(options)) { roptions_for_table_iter = ReadOptions(/*_verify_checksums=*/true, /*_fill_cache=*/false); } }; SstFileReader::SstFileReader(const Options& options) : rep_(new Rep(options)) {} SstFileReader::~SstFileReader() = default; Status SstFileReader::Open(const std::string& file_path) { auto r = rep_.get(); Status s; uint64_t file_size = 0; std::unique_ptr<FSRandomAccessFile> file; std::unique_ptr<RandomAccessFileReader> file_reader; FileOptions fopts(r->soptions); fopts.file_checksum_func_name = kNoFileChecksumFuncName; const auto& fs = r->options.env->GetFileSystem(); s = fs->GetFileSize(file_path, fopts.io_options, &file_size, nullptr); if (s.ok()) { s = fs->NewRandomAccessFile(file_path, fopts, &file, nullptr); } if (s.ok()) { file_reader.reset(new RandomAccessFileReader(std::move(file), file_path)); } if (s.ok()) { TableReaderOptions t_opt( r->ioptions, r->moptions.prefix_extractor, r->moptions.compression_manager.get(), r->soptions, r->ioptions.internal_comparator, r->moptions.block_protection_bytes_per_key, /*skip_filters*/ false, /*immortal*/ false, /*force_direct_prefetch*/ false, /*level*/ -1, /*block_cache_tracer*/ nullptr, /*max_file_size_for_l0_meta_pin*/ 0, /*cur_db_session_id*/ "", /*cur_file_num*/ 0, /* unique_id */ {}, /* largest_seqno */ 0, /* tail_size */ 0, r->ioptions.persist_user_defined_timestamps); // Allow open file with global sequence number for backward compatibility. t_opt.largest_seqno = kMaxSequenceNumber; s = r->options.table_factory->NewTableReader(t_opt, std::move(file_reader), file_size, &r->table_reader); } return s; } std::vector<Status> SstFileReader::MultiGet( const ReadOptions& roptions, const std::vector<Slice>& keys, std::vector<PinnableSlice>* values) { const auto num_keys = keys.size(); std::vector<Status> statuses(num_keys, Status::OK()); values->resize(num_keys); for (size_t i = 0; i < num_keys; ++i) { (*values)[i].Reset(); } auto r = rep_.get(); const Comparator* user_comparator = r->ioptions.internal_comparator.user_comparator(); Statistics* statistics = r->ioptions.stats; autovector<KeyContext, MultiGetContext::MAX_BATCH_SIZE> key_context; autovector<KeyContext*, MultiGetContext::MAX_BATCH_SIZE> sorted_keys; autovector<GetContext, MultiGetContext::MAX_BATCH_SIZE> get_ctx; autovector<MergeContext, MultiGetContext::MAX_BATCH_SIZE> merge_ctx; sorted_keys.resize(num_keys); for (size_t i = 0; i < num_keys; ++i) { PinnableSlice* val = &(*values)[i]; merge_ctx.emplace_back(); key_context.emplace_back(nullptr, keys[i], val, nullptr, nullptr /* timestamp */, &statuses[i]); get_ctx.emplace_back( user_comparator, r->ioptions.merge_operator.get(), nullptr /* logger */, statistics, GetContext::kNotFound, *key_context[i].key, val, nullptr /* columns */, nullptr /* timestamp */, nullptr /* value_found */, &merge_ctx[i], true, &key_context[i].max_covering_tombstone_seq, r->ioptions.clock); key_context[i].get_context = &get_ctx[i]; } for (size_t i = 0; i < num_keys; ++i) { sorted_keys[i] = &key_context[i]; } struct CompareKeyContext { explicit CompareKeyContext(const Comparator* comp) : comparator(comp) {} inline bool operator()(const KeyContext* lhs, const KeyContext* rhs) const { return comparator->CompareWithoutTimestamp(*(lhs->key), false, *(rhs->key), false) < 0; } const Comparator* comparator; }; std::sort(sorted_keys.begin(), sorted_keys.end(), CompareKeyContext(user_comparator)); const auto sequence = roptions.snapshot != nullptr ? roptions.snapshot->GetSequenceNumber() : kMaxSequenceNumber; MultiGetContext ctx(&sorted_keys, 0, num_keys, sequence, roptions, r->ioptions.fs.get(), nullptr); MultiGetRange range = ctx.GetMultiGetRange(); r->table_reader->MultiGet(roptions, &range, r->moptions.prefix_extractor.get(), false /* skip filters */); for (size_t i = 0; i < num_keys; ++i) { get_ctx[i].ReportCounters(); if (statuses[i].ok()) { switch (get_ctx[i].State()) { case GetContext::kFound: break; case GetContext::kNotFound: case GetContext::kDeleted: statuses[i] = Status::NotFound(); break; case GetContext::kMerge: statuses[i] = Status::MergeInProgress(); break; case GetContext::kCorrupt: statuses[i] = Status::Corruption(); break; case GetContext::kUnexpectedBlobIndex: case GetContext::kMergeOperatorFailed: statuses[i] = Status::Corruption(); break; }; } } return statuses; } std::vector<Status> SstFileReader::MultiGet(const ReadOptions& roptions, const std::vector<Slice>& keys, std::vector<std::string>* values) { std::vector<PinnableSlice> pin_values; std::vector<Status> statuses = MultiGet(roptions, keys, &pin_values); values->resize(keys.size()); for (size_t i = 0; i < keys.size(); ++i) { if (statuses[i].ok()) { (*values)[i].assign(pin_values[i].data(), pin_values[i].size()); } } return statuses; } Status SstFileReader::Get(const ReadOptions& roptions, const Slice& key, PinnableSlice* value) { auto r = rep_.get(); value->Reset(); const Comparator* user_comparator = r->ioptions.internal_comparator.user_comparator(); Statistics* statistics = r->ioptions.stats; Status status; MergeContext merge_context; SequenceNumber max_covering_tombstone_seq = 0; GetContext get_ctx(user_comparator, r->ioptions.merge_operator.get(), nullptr /* logger */, statistics, GetContext::kNotFound, key, value, nullptr /* columns */, nullptr /* timestamp */, nullptr /* value_found */, &merge_context, true, &max_covering_tombstone_seq, r->ioptions.clock); LookupKey lkey(key, kMaxSequenceNumber); status = r->table_reader->Get(roptions, lkey.internal_key(), &get_ctx, r->moptions.prefix_extractor.get(), false /* skip_filters */); get_ctx.ReportCounters(); if (status.ok()) { switch (get_ctx.State()) { case GetContext::kFound: break; case GetContext::kNotFound: case GetContext::kDeleted: status = Status::NotFound(); break; case GetContext::kMerge: status = Status::MergeInProgress(); break; case GetContext::kCorrupt: status = Status::Corruption(); break; case GetContext::kUnexpectedBlobIndex: case GetContext::kMergeOperatorFailed: status = Status::Corruption(); break; } } return status; } Status SstFileReader::Get(const ReadOptions& roptions, const Slice& key, std::string* value) { PinnableSlice pin_value; Status s = Get(roptions, key, &pin_value); if (s.ok()) { value->assign(pin_value.data(), pin_value.size()); } return s; } Iterator* SstFileReader::NewIterator(const ReadOptions& roptions) { assert(roptions.io_activity == Env::IOActivity::kUnknown); auto r = rep_.get(); auto sequence = roptions.snapshot != nullptr ? roptions.snapshot->GetSequenceNumber() : kMaxSequenceNumber; ArenaWrappedDBIter* res = new ArenaWrappedDBIter(); res->Init(r->options.env, roptions, r->ioptions, r->moptions, nullptr /* version */, sequence, 0 /* version_number */, nullptr /* read_callback */, nullptr /* cfh */, true /* expose_blob_index */, false /* allow_refresh */, /*active_mem=*/nullptr); auto internal_iter = r->table_reader->NewIterator( res->GetReadOptions(), r->moptions.prefix_extractor.get(), res->GetArena(), false /* skip_filters */, TableReaderCaller::kSSTFileReader); res->SetIterUnderDBIter(internal_iter); return res; } std::unique_ptr<Iterator> SstFileReader::NewTableIterator() { auto r = rep_.get(); InternalIterator* internal_iter = r->table_reader->NewIterator( r->roptions_for_table_iter, r->moptions.prefix_extractor.get(), /*arena*/ nullptr, false /* skip_filters */, TableReaderCaller::kSSTFileReader); assert(internal_iter); if (internal_iter == nullptr) { // Do not attempt to create a TableIterator if we cannot get a valid // InternalIterator. return nullptr; } return std::make_unique<TableIterator>(internal_iter); } Status SstFileReader::ParseTableIteratorKey(const Slice& raw_table_key, ParsedEntryInfo* parsed_key) const { return ParseEntry(raw_table_key, rep_->options.comparator, parsed_key); } std::shared_ptr<const TableProperties> SstFileReader::GetTableProperties() const { return rep_->table_reader->GetTableProperties(); } Status SstFileReader::VerifyChecksum(const ReadOptions& read_options) { assert(read_options.io_activity == Env::IOActivity::kUnknown); return rep_->table_reader->VerifyChecksum(read_options, TableReaderCaller::kSSTFileReader); } Status SstFileReader::VerifyNumEntries(const ReadOptions& read_options) { Rep* r = rep_.get(); std::unique_ptr<InternalIterator> internal_iter{r->table_reader->NewIterator( read_options, r->moptions.prefix_extractor.get(), nullptr, false /* skip_filters */, TableReaderCaller::kSSTFileReader)}; internal_iter->SeekToFirst(); Status s = internal_iter->status(); if (!s.ok()) { return s; } uint64_t num_read = 0; for (; internal_iter->Valid(); internal_iter->Next()) { ++num_read; } s = internal_iter->status(); if (!s.ok()) { return s; } std::shared_ptr<const TableProperties> tp = GetTableProperties(); if (!tp) { s = Status::Corruption("table properties not available"); } else { // TODO: verify num_range_deletions uint64_t expected = tp->num_entries - tp->num_range_deletions; if (num_read != expected) { std::ostringstream oss; oss << "Table property expects " << expected << " entries when excluding range deletions," << " but scanning the table returned " << std::to_string(num_read) << " entries"; s = Status::Corruption(oss.str()); } } return s; } } // namespace ROCKSDB_NAMESPACE