| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678 |
- // 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/sst_file_dumper.h"
- #include <chrono>
- #include <cinttypes>
- #include <iostream>
- #include <map>
- #include <memory>
- #include <sstream>
- #include <vector>
- #include "db/blob/blob_index.h"
- #include "db/memtable.h"
- #include "db/wide/wide_column_serialization.h"
- #include "db/wide/wide_columns_helper.h"
- #include "db/write_batch_internal.h"
- #include "options/cf_options.h"
- #include "port/port.h"
- #include "rocksdb/db.h"
- #include "rocksdb/env.h"
- #include "rocksdb/iterator.h"
- #include "rocksdb/slice_transform.h"
- #include "rocksdb/status.h"
- #include "rocksdb/table_properties.h"
- #include "rocksdb/utilities/ldb_cmd.h"
- #include "table/block_based/block.h"
- #include "table/block_based/block_based_table_builder.h"
- #include "table/block_based/block_based_table_factory.h"
- #include "table/block_based/block_builder.h"
- #include "table/format.h"
- #include "table/meta_blocks.h"
- #include "table/plain/plain_table_factory.h"
- #include "table/table_reader.h"
- #include "util/compression.h"
- #include "util/random.h"
- #include "util/udt_util.h"
- namespace ROCKSDB_NAMESPACE {
- SstFileDumper::SstFileDumper(const Options& options,
- const std::string& file_path,
- Temperature file_temp, size_t readahead_size,
- bool verify_checksum, bool output_hex,
- bool decode_blob_index, const EnvOptions& soptions,
- bool silent)
- : file_name_(file_path),
- read_num_(0),
- file_temp_(file_temp),
- output_hex_(output_hex),
- decode_blob_index_(decode_blob_index),
- soptions_(soptions),
- silent_(silent),
- options_(options),
- ioptions_(options_),
- moptions_(ColumnFamilyOptions(options_)),
- // TODO: plumb Env::IOActivity, Env::IOPriority
- read_options_(verify_checksum, false),
- internal_comparator_(BytewiseComparator()) {
- read_options_.readahead_size = readahead_size;
- if (!silent_) {
- fprintf(stdout, "Process %s\n", file_path.c_str());
- }
- init_result_ = GetTableReader(file_name_);
- }
- const char* testFileName = "test_file_name";
- Status SstFileDumper::GetTableReader(const std::string& file_path) {
- // Warning about 'magic_number' being uninitialized shows up only in UBsan
- // builds. Though access is guarded by 's.ok()' checks, fix the issue to
- // avoid any warnings.
- uint64_t magic_number = Footer::kNullTableMagicNumber;
- // read table magic number
- Footer footer;
- const auto& fs = options_.env->GetFileSystem();
- std::unique_ptr<FSRandomAccessFile> file;
- uint64_t file_size = 0;
- FileOptions fopts = soptions_;
- fopts.temperature = file_temp_;
- Status s = fs->NewRandomAccessFile(file_path, fopts, &file, nullptr);
- if (s.ok()) {
- // check empty file
- // if true, skip further processing of this file
- s = fs->GetFileSize(file_path, IOOptions(), &file_size, nullptr);
- if (s.ok()) {
- if (file_size == 0) {
- return Status::Aborted(file_path, "Empty file");
- }
- }
- }
- file_.reset(new RandomAccessFileReader(std::move(file), file_path));
- FilePrefetchBuffer prefetch_buffer(ReadaheadParams(),
- !fopts.use_mmap_reads /* enable */,
- false /* track_min_offset */);
- if (s.ok()) {
- const uint64_t kSstDumpTailPrefetchSize = 512 * 1024;
- uint64_t prefetch_size = (file_size > kSstDumpTailPrefetchSize)
- ? kSstDumpTailPrefetchSize
- : file_size;
- uint64_t prefetch_off = file_size - prefetch_size;
- IOOptions opts;
- s = prefetch_buffer.Prefetch(opts, file_.get(), prefetch_off,
- static_cast<size_t>(prefetch_size));
- s = ReadFooterFromFile(opts, file_.get(), *fs, &prefetch_buffer, file_size,
- &footer);
- }
- if (s.ok()) {
- magic_number = footer.table_magic_number();
- }
- if (s.ok()) {
- if (magic_number == kPlainTableMagicNumber ||
- magic_number == kLegacyPlainTableMagicNumber ||
- magic_number == kCuckooTableMagicNumber) {
- soptions_.use_mmap_reads = true;
- fopts.use_mmap_reads = soptions_.use_mmap_reads;
- if (magic_number == kCuckooTableMagicNumber) {
- fopts = soptions_;
- fopts.temperature = file_temp_;
- }
- fs->NewRandomAccessFile(file_path, fopts, &file, nullptr);
- file_.reset(new RandomAccessFileReader(std::move(file), file_path));
- }
- // For old sst format, ReadTableProperties might fail but file can be read
- if (ReadTableProperties(magic_number, file_.get(), file_size,
- (magic_number == kBlockBasedTableMagicNumber)
- ? &prefetch_buffer
- : nullptr)
- .ok()) {
- s = SetTableOptionsByMagicNumber(magic_number);
- if (s.ok()) {
- if (table_properties_ && !table_properties_->comparator_name.empty()) {
- ConfigOptions config_options;
- const Comparator* user_comparator = nullptr;
- s = Comparator::CreateFromString(config_options,
- table_properties_->comparator_name,
- &user_comparator);
- if (s.ok()) {
- assert(user_comparator);
- internal_comparator_ = InternalKeyComparator(user_comparator);
- }
- }
- }
- } else {
- s = SetOldTableOptions();
- }
- options_.comparator = internal_comparator_.user_comparator();
- {
- Status status = ReadMetaIndexBlockInFile(
- file_.get(), file_size, magic_number, ImmutableOptions(options_),
- ReadOptions(), &meta_index_contents_);
- // Ignore any errors since this is required for a specific CLI option
- status.PermitUncheckedError();
- }
- }
- if (s.ok()) {
- s = NewTableReader(ioptions_, soptions_, internal_comparator_, file_size,
- &table_reader_);
- }
- return s;
- }
- Status SstFileDumper::NewTableReader(
- const ImmutableOptions& /*ioptions*/, const EnvOptions& /*soptions*/,
- const InternalKeyComparator& /*internal_comparator*/, uint64_t file_size,
- std::unique_ptr<TableReader>* /*table_reader*/) {
- auto t_opt = TableReaderOptions(
- ioptions_, moptions_.prefix_extractor,
- moptions_.compression_manager.get(), soptions_, internal_comparator_,
- 0 /* block_protection_bytes_per_key */, false /* skip_filters */,
- false /* immortal */, true /* force_direct_prefetch */, -1 /* level */,
- nullptr /* block_cache_tracer */, 0 /* max_file_size_for_l0_meta_pin */,
- "" /* cur_db_session_id */, 0 /* cur_file_num */, {} /* unique_id */,
- 0 /* largest_seqno */, 0 /* tail_size */,
- table_properties_ == nullptr
- ? true
- : static_cast<bool>(
- table_properties_->user_defined_timestamps_persisted));
- // Allow open file with global sequence number for backward compatibility.
- t_opt.largest_seqno = kMaxSequenceNumber;
- // We need to turn off pre-fetching of index and filter nodes for
- // BlockBasedTable
- if (options_.table_factory->IsInstanceOf(
- TableFactory::kBlockBasedTableName())) {
- return options_.table_factory->NewTableReader(t_opt, std::move(file_),
- file_size, &table_reader_,
- /*enable_prefetch=*/false);
- }
- // For all other factory implementation
- return options_.table_factory->NewTableReader(t_opt, std::move(file_),
- file_size, &table_reader_);
- }
- Status SstFileDumper::VerifyChecksum() {
- assert(read_options_.verify_checksums);
- // We could pass specific readahead setting into read options if needed.
- return table_reader_->VerifyChecksum(read_options_,
- TableReaderCaller::kSSTDumpTool);
- }
- Status SstFileDumper::DumpTable(const std::string& out_filename) {
- std::unique_ptr<WritableFile> out_file;
- Env* env = options_.env;
- Status s = env->NewWritableFile(out_filename, &out_file, soptions_);
- if (s.ok()) {
- s = table_reader_->DumpTable(out_file.get());
- }
- if (!s.ok()) {
- // close the file before return error, ignore the close error if there's any
- out_file->Close().PermitUncheckedError();
- return s;
- }
- return out_file->Close();
- }
- Status SstFileDumper::CalculateCompressedTableSize(
- const TableBuilderOptions& tb_options, TableProperties* props,
- std::chrono::microseconds* write_time,
- std::chrono::microseconds* read_time) {
- std::unique_ptr<Env> env(NewMemEnv(options_.env));
- std::unique_ptr<WritableFileWriter> dest_writer;
- Status s =
- WritableFileWriter::Create(env->GetFileSystem(), testFileName,
- FileOptions(soptions_), &dest_writer, nullptr);
- if (!s.ok()) {
- return s;
- }
- std::chrono::steady_clock::time_point start =
- std::chrono::steady_clock::now();
- std::unique_ptr<TableBuilder> table_builder{
- tb_options.moptions.table_factory->NewTableBuilder(tb_options,
- dest_writer.get())};
- std::unique_ptr<InternalIterator> iter(table_reader_->NewIterator(
- read_options_, moptions_.prefix_extractor.get(), /*arena=*/nullptr,
- /*skip_filters=*/false, TableReaderCaller::kSSTDumpTool));
- for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
- table_builder->Add(iter->key(), iter->value());
- }
- s = iter->status();
- if (!s.ok()) {
- return s;
- }
- iter.reset();
- s = table_builder->Finish();
- *write_time = std::chrono::duration_cast<std::chrono::microseconds>(
- std::chrono::steady_clock::now() - start);
- if (!s.ok()) {
- return s;
- }
- s = dest_writer->Close({});
- if (!s.ok()) {
- return s;
- }
- dest_writer.reset();
- *props = table_builder->GetTableProperties();
- start = std::chrono::steady_clock::now();
- TableReaderOptions reader_options(ioptions_, moptions_.prefix_extractor,
- moptions_.compression_manager.get(),
- soptions_, internal_comparator_,
- 0 /* block_protection_bytes_per_key */);
- std::unique_ptr<RandomAccessFileReader> file_reader;
- s = RandomAccessFileReader::Create(env->GetFileSystem(), testFileName,
- soptions_, &file_reader, /*dbg=*/nullptr);
- if (!s.ok()) {
- return s;
- }
- std::unique_ptr<TableReader> table_reader;
- s = tb_options.moptions.table_factory->NewTableReader(
- reader_options, std::move(file_reader), table_builder->FileSize(),
- &table_reader);
- if (!s.ok()) {
- return s;
- }
- iter.reset(table_reader->NewIterator(
- read_options_, moptions_.prefix_extractor.get(), /*arena=*/nullptr,
- /*skip_filters=*/false, TableReaderCaller::kSSTDumpTool));
- for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
- }
- s = iter->status();
- if (!s.ok()) {
- return s;
- }
- iter.reset();
- table_reader.reset();
- file_reader.reset();
- *read_time = std::chrono::duration_cast<std::chrono::microseconds>(
- std::chrono::steady_clock::now() - start);
- return env->DeleteFile(testFileName);
- }
- Status SstFileDumper::ShowAllCompressionSizes(
- const std::vector<CompressionType>& compression_types,
- int32_t compress_level_from, int32_t compress_level_to) {
- #ifndef NDEBUG
- fprintf(stdout,
- "WARNING: Assertions are enabled; benchmarks unnecessarily slow\n");
- #endif
- BlockBasedTableOptions bbto;
- if (options_.table_factory->IsInstanceOf(
- TableFactory::kBlockBasedTableName())) {
- bbto = *(static_cast_with_check<BlockBasedTableFactory>(
- options_.table_factory.get()))
- ->GetOptions<BlockBasedTableOptions>();
- }
- for (CompressionType ctype : compression_types) {
- std::string cname;
- if (!GetStringFromCompressionType(&cname, ctype).ok()) {
- // Can produce names like "Reserved4F" for unrecognized values
- cname = CompressionTypeToString(ctype);
- }
- if (options_.compression_manager
- ? options_.compression_manager->SupportsCompressionType(ctype)
- : CompressionTypeSupported(ctype)) {
- CompressionOptions compress_opt = options_.compression_opts;
- fprintf(stdout,
- "Compression: %-24s Block Size: %" PRIu64 " Threads: %u\n",
- cname.c_str(), bbto.block_size, compress_opt.parallel_threads);
- for (int32_t j = compress_level_from; j <= compress_level_to; j++) {
- fprintf(stdout, "Cx level: %d", j);
- compress_opt.level = j;
- Status s = ShowCompressionSize(ctype, compress_opt);
- if (!s.ok()) {
- return s;
- }
- }
- } else {
- fprintf(stdout, "Unsupported compression type: %s.\n", cname.c_str());
- }
- }
- return Status::OK();
- }
- Status SstFileDumper::ShowCompressionSize(
- CompressionType compress_type, const CompressionOptions& compress_opt) {
- Options opts = options_; // Use compression_manager etc.
- opts.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
- opts.statistics->set_stats_level(StatsLevel::kAll);
- if (!opts.table_factory->IsInstanceOf(TableFactory::kBlockBasedTableName())) {
- // Currently need block-based table for compression
- opts.table_factory = std::make_shared<BlockBasedTableFactory>();
- }
- // Create internal Options types
- const ImmutableOptions imoptions(opts);
- const ColumnFamilyOptions cfo(opts);
- const MutableCFOptions moptions(cfo);
- // TODO: plumb Env::IOActivity, Env::IOPriority
- const ReadOptions read_options;
- const WriteOptions write_options;
- ROCKSDB_NAMESPACE::InternalKeyComparator ikc(opts.comparator);
- InternalTblPropCollFactories block_based_table_factories;
- std::string column_family_name;
- int unknown_level = -1;
- TableBuilderOptions tb_opts(
- imoptions, moptions, read_options, write_options, ikc,
- &block_based_table_factories, compress_type, compress_opt,
- TablePropertiesCollectorFactory::Context::kUnknownColumnFamily,
- column_family_name, unknown_level, kUnknownNewestKeyTime);
- TableProperties props;
- std::chrono::microseconds write_time;
- std::chrono::microseconds read_time;
- Status s =
- CalculateCompressedTableSize(tb_opts, &props, &write_time, &read_time);
- if (!s.ok()) {
- return s;
- }
- uint64_t num_data_blocks = props.num_data_blocks;
- fprintf(stdout, " Cx size: %10" PRIu64, props.data_size);
- fprintf(stdout, " Uncx size: %10" PRIu64, props.uncompressed_data_size);
- fprintf(stdout, " Ratio: %10s",
- std::to_string(static_cast<double>(props.uncompressed_data_size) /
- static_cast<double>(props.data_size))
- .c_str());
- fprintf(stdout, " Write usec: %10s ",
- std::to_string(write_time.count()).c_str());
- fprintf(stdout, " Read usec: %10s ",
- std::to_string(read_time.count()).c_str());
- const uint64_t compressed_blocks =
- opts.statistics->getAndResetTickerCount(NUMBER_BLOCK_COMPRESSED);
- const uint64_t not_compressed_blocks =
- opts.statistics->getAndResetTickerCount(
- NUMBER_BLOCK_COMPRESSION_REJECTED);
- // When the option enable_index_compression is true,
- // NUMBER_BLOCK_COMPRESSED is incremented for index block(s).
- if ((compressed_blocks + not_compressed_blocks) > num_data_blocks) {
- num_data_blocks = compressed_blocks + not_compressed_blocks;
- }
- const uint64_t ratio_not_compressed_blocks =
- (num_data_blocks - compressed_blocks) - not_compressed_blocks;
- const double compressed_pcnt =
- (0 == num_data_blocks) ? 0.0
- : ((static_cast<double>(compressed_blocks) /
- static_cast<double>(num_data_blocks)) *
- 100.0);
- const double ratio_not_compressed_pcnt =
- (0 == num_data_blocks)
- ? 0.0
- : ((static_cast<double>(ratio_not_compressed_blocks) /
- static_cast<double>(num_data_blocks)) *
- 100.0);
- const double not_compressed_pcnt =
- (0 == num_data_blocks) ? 0.0
- : ((static_cast<double>(not_compressed_blocks) /
- static_cast<double>(num_data_blocks)) *
- 100.0);
- fprintf(stdout, " Cx count: %6" PRIu64 " (%5.1f%%)", compressed_blocks,
- compressed_pcnt);
- fprintf(stdout, " Not cx for ratio: %6" PRIu64 " (%5.1f%%)",
- ratio_not_compressed_blocks, ratio_not_compressed_pcnt);
- fprintf(stdout, " Not cx otherwise: %6" PRIu64 " (%5.1f%%)\n",
- not_compressed_blocks, not_compressed_pcnt);
- return Status::OK();
- }
- // Reads TableProperties prior to opening table reader in order to set up
- // options.
- Status SstFileDumper::ReadTableProperties(uint64_t table_magic_number,
- RandomAccessFileReader* file,
- uint64_t file_size,
- FilePrefetchBuffer* prefetch_buffer) {
- Status s = ROCKSDB_NAMESPACE::ReadTableProperties(
- file, file_size, table_magic_number, ioptions_, read_options_,
- &table_properties_,
- /* memory_allocator= */ nullptr, prefetch_buffer);
- if (!s.ok()) {
- if (!silent_) {
- fprintf(stdout, "Not able to read table properties\n");
- }
- }
- return s;
- }
- Status SstFileDumper::SetTableOptionsByMagicNumber(
- uint64_t table_magic_number) {
- assert(table_properties_);
- if (table_magic_number == kBlockBasedTableMagicNumber ||
- table_magic_number == kLegacyBlockBasedTableMagicNumber) {
- // Preserve BlockBasedTableOptions on options_ when possible
- if (!options_.table_factory->IsInstanceOf(
- TableFactory::kBlockBasedTableName())) {
- options_.table_factory = std::make_shared<BlockBasedTableFactory>();
- }
- BlockBasedTableFactory* bbtf =
- static_cast_with_check<BlockBasedTableFactory>(
- options_.table_factory.get());
- // To force tail prefetching, we fake reporting two useful reads of 512KB
- // from the tail.
- // It needs at least two data points to warm up the stats.
- bbtf->tail_prefetch_stats()->RecordEffectiveSize(512 * 1024);
- bbtf->tail_prefetch_stats()->RecordEffectiveSize(512 * 1024);
- if (!silent_) {
- fprintf(stdout, "Sst file format: block-based\n");
- }
- auto& props = table_properties_->user_collected_properties;
- auto pos = props.find(BlockBasedTablePropertyNames::kIndexType);
- if (pos != props.end()) {
- auto index_type_on_file = static_cast<BlockBasedTableOptions::IndexType>(
- DecodeFixed32(pos->second.c_str()));
- if (index_type_on_file ==
- BlockBasedTableOptions::IndexType::kHashSearch) {
- options_.prefix_extractor.reset(NewNoopTransform());
- }
- }
- } else if (table_magic_number == kPlainTableMagicNumber ||
- table_magic_number == kLegacyPlainTableMagicNumber) {
- options_.allow_mmap_reads = true;
- PlainTableOptions plain_table_options;
- plain_table_options.user_key_len = kPlainTableVariableLength;
- plain_table_options.bloom_bits_per_key = 0;
- plain_table_options.hash_table_ratio = 0;
- plain_table_options.index_sparseness = 1;
- plain_table_options.huge_page_tlb_size = 0;
- plain_table_options.encoding_type = kPlain;
- plain_table_options.full_scan_mode = true;
- options_.table_factory.reset(NewPlainTableFactory(plain_table_options));
- if (!silent_) {
- fprintf(stdout, "Sst file format: plain table\n");
- }
- } else if (table_magic_number == kCuckooTableMagicNumber) {
- ioptions_.allow_mmap_reads = true;
- options_.table_factory.reset(NewCuckooTableFactory());
- if (!silent_) {
- fprintf(stdout, "Sst file format: cuckoo table\n");
- }
- } else {
- char error_msg_buffer[80];
- snprintf(error_msg_buffer, sizeof(error_msg_buffer) - 1,
- "Unsupported table magic number --- %lx",
- (long)table_magic_number);
- return Status::InvalidArgument(error_msg_buffer);
- }
- return Status::OK();
- }
- Status SstFileDumper::SetOldTableOptions() {
- assert(table_properties_ == nullptr);
- if (!options_.table_factory->IsInstanceOf(
- TableFactory::kBlockBasedTableName())) {
- options_.table_factory = std::make_shared<BlockBasedTableFactory>();
- }
- if (!silent_) {
- fprintf(stdout, "Sst file format: block-based(old version)\n");
- }
- return Status::OK();
- }
- Status SstFileDumper::ReadSequential(bool print_kv, uint64_t read_num_limit,
- bool has_from, const std::string& from_key,
- bool has_to, const std::string& to_key,
- bool use_from_as_prefix) {
- if (!table_reader_) {
- return init_result_;
- }
- InternalIterator* iter = table_reader_->NewIterator(
- read_options_, moptions_.prefix_extractor.get(),
- /*arena=*/nullptr, /*skip_filters=*/false,
- TableReaderCaller::kSSTDumpTool);
- const Comparator* ucmp = internal_comparator_.user_comparator();
- size_t ts_sz = ucmp->timestamp_size();
- OptSlice from_opt = has_from ? from_key : OptSlice{};
- OptSlice to_opt = has_to ? to_key : OptSlice{};
- std::string from_key_buf, to_key_buf;
- auto [from, to] = MaybeAddTimestampsToRange(from_opt, to_opt, ts_sz,
- &from_key_buf, &to_key_buf);
- uint64_t i = 0;
- if (from.has_value()) {
- InternalKey ikey;
- ikey.SetMinPossibleForUserKey(from.value());
- iter->Seek(ikey.Encode());
- } else {
- iter->SeekToFirst();
- }
- for (; iter->Valid(); iter->Next()) {
- Slice key = iter->key();
- Slice value = iter->value();
- ++i;
- if (read_num_limit > 0 && i > read_num_limit) {
- break;
- }
- ParsedInternalKey ikey;
- Status pik_status = ParseInternalKey(key, &ikey, true /* log_err_key */);
- if (!pik_status.ok()) {
- std::cerr << pik_status.getState() << "\n";
- continue;
- }
- // the key returned is not prefixed with out 'from' key
- if (use_from_as_prefix && !ikey.user_key.starts_with(from_key)) {
- break;
- }
- // If end marker was specified, we stop before it
- if (to.has_value() && ucmp->Compare(ikey.user_key, to.value()) >= 0) {
- break;
- }
- if (print_kv) {
- if (!decode_blob_index_ || ikey.type != kTypeBlobIndex) {
- if (ikey.type == kTypeWideColumnEntity) {
- std::ostringstream oss;
- const Status s = WideColumnsHelper::DumpSliceAsWideColumns(
- iter->value(), oss, output_hex_);
- if (!s.ok()) {
- fprintf(stderr, "%s => error deserializing wide columns\n",
- ikey.DebugString(true, output_hex_, ucmp).c_str());
- continue;
- }
- fprintf(stdout, "%s => %s\n",
- ikey.DebugString(true, output_hex_, ucmp).c_str(),
- oss.str().c_str());
- } else if (ikey.type == kTypeValuePreferredSeqno) {
- auto [unpacked_value, preferred_seqno] =
- ParsePackedValueWithSeqno(value);
- fprintf(stdout, "%s => %s, %llu\n",
- ikey.DebugString(true, output_hex_, ucmp).c_str(),
- unpacked_value.ToString(output_hex_).c_str(),
- static_cast<unsigned long long>(preferred_seqno));
- } else {
- fprintf(stdout, "%s => %s\n",
- ikey.DebugString(true, output_hex_, ucmp).c_str(),
- value.ToString(output_hex_).c_str());
- }
- } else {
- BlobIndex blob_index;
- const Status s = blob_index.DecodeFrom(value);
- if (!s.ok()) {
- fprintf(stderr, "%s => error decoding blob index\n",
- ikey.DebugString(true, output_hex_, ucmp).c_str());
- continue;
- }
- fprintf(stdout, "%s => %s\n",
- ikey.DebugString(true, output_hex_, ucmp).c_str(),
- blob_index.DebugString(output_hex_).c_str());
- }
- }
- }
- read_num_ += i;
- Status ret = iter->status();
- bool verify_num_entries =
- (read_num_limit == 0 ||
- read_num_limit == std::numeric_limits<uint64_t>::max()) &&
- !has_from && !has_to;
- if (verify_num_entries && ret.ok()) {
- // Compare the number of entries
- if (!table_properties_) {
- fprintf(stderr, "Table properties not available.");
- } else {
- // TODO: verify num_range_deletions
- if (i != table_properties_->num_entries -
- table_properties_->num_range_deletions) {
- std::ostringstream oss;
- oss << "Table property expects "
- << table_properties_->num_entries -
- table_properties_->num_range_deletions
- << " entries when excluding range deletions,"
- << " but scanning the table returned " << std::to_string(i)
- << " entries";
- ret = Status::Corruption(oss.str());
- }
- }
- }
- delete iter;
- return ret;
- }
- // Provides TableProperties to API user
- Status SstFileDumper::ReadTableProperties(
- std::shared_ptr<const TableProperties>* table_properties) {
- if (!table_reader_) {
- return init_result_;
- }
- *table_properties = table_reader_->GetTableProperties();
- return init_result_;
- }
- } // namespace ROCKSDB_NAMESPACE
|