/Users/deen/code/yugabyte-db/src/yb/rocksdb/tools/sst_dump_tool.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 the BSD-style license found in the |
3 | | // LICENSE file in the root directory of this source tree. An additional grant |
4 | | // of patent rights can be found in the PATENTS file in the same directory. |
5 | | // |
6 | | // The following only applies to changes made to this file as part of YugaByte development. |
7 | | // |
8 | | // Portions Copyright (c) YugaByte, Inc. |
9 | | // |
10 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
11 | | // in compliance with the License. You may obtain a copy of the License at |
12 | | // |
13 | | // http://www.apache.org/licenses/LICENSE-2.0 |
14 | | // |
15 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
16 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
17 | | // or implied. See the License for the specific language governing permissions and limitations |
18 | | // under the License. |
19 | | // |
20 | | #ifndef ROCKSDB_LITE |
21 | | |
22 | | #include "yb/rocksdb/tools/sst_dump_tool_imp.h" |
23 | | |
24 | | #ifndef __STDC_FORMAT_MACROS |
25 | | #define __STDC_FORMAT_MACROS |
26 | | #endif |
27 | | |
28 | | #include <inttypes.h> |
29 | | #include <map> |
30 | | #include <sstream> |
31 | | #include <vector> |
32 | | |
33 | | #include "yb/rocksdb/db/filename.h" |
34 | | #include "yb/rocksdb/db/memtable.h" |
35 | | #include "yb/rocksdb/db/write_batch_internal.h" |
36 | | #include "yb/rocksdb/db.h" |
37 | | #include "yb/rocksdb/env.h" |
38 | | #include "yb/rocksdb/immutable_options.h" |
39 | | #include "yb/rocksdb/iterator.h" |
40 | | #include "yb/rocksdb/slice_transform.h" |
41 | | #include "yb/rocksdb/status.h" |
42 | | #include "yb/rocksdb/table_properties.h" |
43 | | #include "yb/rocksdb/table/block.h" |
44 | | #include "yb/rocksdb/table/block_based_table_builder.h" |
45 | | #include "yb/rocksdb/table/block_based_table_factory.h" |
46 | | #include "yb/rocksdb/table/block_builder.h" |
47 | | #include "yb/rocksdb/table/format.h" |
48 | | #include "yb/rocksdb/table/meta_blocks.h" |
49 | | #include "yb/rocksdb/table/plain_table_factory.h" |
50 | | #include "yb/rocksdb/tools/ldb_cmd.h" |
51 | | #include "yb/rocksdb/util/random.h" |
52 | | |
53 | | #include "yb/rocksdb/port/port.h" |
54 | | |
55 | | #include "yb/docdb/docdb_debug.h" |
56 | | |
57 | | #include "yb/util/status_log.h" |
58 | | |
59 | | using yb::docdb::StorageDbType; |
60 | | |
61 | | namespace rocksdb { |
62 | | |
63 | | using std::dynamic_pointer_cast; |
64 | | |
65 | | std::string DocDBKVFormatter::Format( |
66 | 0 | const yb::Slice&, const yb::Slice&, yb::docdb::StorageDbType) const { |
67 | 0 | CHECK(false) << "unimplemented"; |
68 | 0 | return ""; |
69 | 0 | } |
70 | | |
71 | | SstFileReader::SstFileReader( |
72 | | const std::string& file_path, bool verify_checksum, OutputFormat output_format, |
73 | | const DocDBKVFormatter* formatter) |
74 | | : file_name_(file_path), |
75 | | read_num_(0), |
76 | | verify_checksum_(verify_checksum), |
77 | | output_format_(output_format), |
78 | | docdb_kv_formatter_(formatter), |
79 | | ioptions_(options_), |
80 | 5 | internal_comparator_(std::make_shared<InternalKeyComparator>(BytewiseComparator())) { |
81 | 5 | fprintf(stdout, "Process %s\n", file_path.c_str()); |
82 | 5 | init_result_ = GetTableReader(file_name_); |
83 | 5 | } |
84 | | |
85 | 5 | SstFileReader::~SstFileReader() { |
86 | 5 | } |
87 | | |
88 | | extern const uint64_t kBlockBasedTableMagicNumber; |
89 | | extern const uint64_t kLegacyBlockBasedTableMagicNumber; |
90 | | extern const uint64_t kPlainTableMagicNumber; |
91 | | extern const uint64_t kLegacyPlainTableMagicNumber; |
92 | | |
93 | | const char* testFileName = "test_file_name"; |
94 | | |
95 | 5 | Status SstFileReader::GetTableReader(const std::string& file_path) { |
96 | 5 | uint64_t magic_number; |
97 | | |
98 | | // read table magic number |
99 | 5 | Footer footer; |
100 | | |
101 | 5 | unique_ptr<RandomAccessFile> file; |
102 | 5 | uint64_t file_size; |
103 | 5 | Status s = options_.env->NewRandomAccessFile(file_path, &file, soptions_); |
104 | 5 | if (s.ok()) { |
105 | 5 | s = options_.env->GetFileSize(file_path, &file_size); |
106 | 5 | } |
107 | | |
108 | 5 | file_.reset(new RandomAccessFileReader(std::move(file))); |
109 | | |
110 | 5 | if (s.ok()) { |
111 | 5 | s = ReadFooterFromFile(file_.get(), file_size, &footer); |
112 | 5 | } |
113 | 5 | if (s.ok()) { |
114 | 5 | magic_number = footer.table_magic_number(); |
115 | 5 | } |
116 | | |
117 | 5 | if (s.ok()) { |
118 | 5 | if (magic_number == kPlainTableMagicNumber || |
119 | 5 | magic_number == kLegacyPlainTableMagicNumber) { |
120 | 0 | soptions_.use_mmap_reads = true; |
121 | 0 | RETURN_NOT_OK(options_.env->NewRandomAccessFile(file_path, &file, soptions_)); |
122 | 0 | file_.reset(new RandomAccessFileReader(std::move(file))); |
123 | 0 | } |
124 | 5 | options_.comparator = internal_comparator_.get(); |
125 | | // For old sst format, ReadTableProperties might fail but file can be read |
126 | 5 | if (ReadTableProperties(magic_number, file_.get(), file_size).ok()) { |
127 | 5 | RETURN_NOT_OK(SetTableOptionsByMagicNumber(magic_number)); |
128 | 0 | } else { |
129 | 0 | RETURN_NOT_OK(SetOldTableOptions()); |
130 | 0 | } |
131 | 5 | } |
132 | | |
133 | 5 | if (s.ok()) { |
134 | 5 | s = NewTableReader(ioptions_, soptions_, *internal_comparator_, file_size, |
135 | 5 | &table_reader_); |
136 | 5 | if (s.ok() && table_reader_->IsSplitSst()) { |
137 | 5 | unique_ptr<RandomAccessFile> data_file; |
138 | 5 | RETURN_NOT_OK(options_.env->NewRandomAccessFile( |
139 | 5 | TableBaseToDataFileName(file_path), &data_file, soptions_)); |
140 | 5 | unique_ptr<RandomAccessFileReader> data_file_reader( |
141 | 5 | new RandomAccessFileReader(std::move(data_file))); |
142 | 5 | table_reader_->SetDataFileReader(std::move(data_file_reader)); |
143 | 5 | } |
144 | 5 | } |
145 | 5 | return s; |
146 | 5 | } |
147 | | |
148 | | Status SstFileReader::NewTableReader( |
149 | | const ImmutableCFOptions& ioptions, const EnvOptions& soptions, |
150 | | const InternalKeyComparator& internal_comparator, uint64_t file_size, |
151 | 5 | unique_ptr<TableReader>* table_reader) { |
152 | | // We need to turn off pre-fetching of index and filter nodes for |
153 | | // BlockBasedTable |
154 | 5 | shared_ptr<BlockBasedTableFactory> block_table_factory = |
155 | 5 | dynamic_pointer_cast<BlockBasedTableFactory>(options_.table_factory); |
156 | | |
157 | 5 | if (block_table_factory) { |
158 | 5 | return block_table_factory->NewTableReader( |
159 | 5 | TableReaderOptions(ioptions_, soptions_, internal_comparator_, |
160 | 5 | /*skip_filters=*/false), |
161 | 5 | std::move(file_), file_size, &table_reader_, DataIndexLoadMode::USE_CACHE, |
162 | 5 | PrefetchFilter::NO); |
163 | 5 | } |
164 | | |
165 | 0 | assert(!block_table_factory); |
166 | | |
167 | | // For all other factory implementation |
168 | 0 | return options_.table_factory->NewTableReader( |
169 | 0 | TableReaderOptions(ioptions_, soptions_, internal_comparator_), |
170 | 0 | std::move(file_), file_size, &table_reader_); |
171 | 0 | } |
172 | | |
173 | 3 | Status SstFileReader::DumpTable(const std::string& out_filename) { |
174 | 3 | unique_ptr<WritableFile> out_file; |
175 | 3 | Env* env = Env::Default(); |
176 | 3 | RETURN_NOT_OK(env->NewWritableFile(out_filename, &out_file, soptions_)); |
177 | 3 | Status s = table_reader_->DumpTable(out_file.get()); |
178 | 3 | RETURN_NOT_OK(out_file->Close()); |
179 | 3 | return s; |
180 | 3 | } |
181 | | |
182 | | uint64_t SstFileReader::CalculateCompressedTableSize( |
183 | 7 | const TableBuilderOptions& tb_options, size_t block_size) { |
184 | 7 | unique_ptr<WritableFile> out_file; |
185 | 7 | unique_ptr<Env> env(NewMemEnv(Env::Default())); |
186 | 7 | CHECK_OK(env->NewWritableFile(testFileName, &out_file, soptions_)); |
187 | 7 | unique_ptr<WritableFileWriter> dest_writer; |
188 | 7 | dest_writer.reset(new WritableFileWriter(std::move(out_file), soptions_)); |
189 | 7 | BlockBasedTableOptions table_options; |
190 | 7 | table_options.block_size = block_size; |
191 | 7 | BlockBasedTableFactory block_based_tf(table_options); |
192 | 7 | unique_ptr<TableBuilder> table_builder; |
193 | 7 | table_builder.reset(block_based_tf.NewTableBuilder( |
194 | 7 | tb_options, |
195 | 7 | TablePropertiesCollectorFactory::Context::kUnknownColumnFamily, |
196 | 7 | dest_writer.get())); |
197 | 7 | unique_ptr<InternalIterator> iter(table_reader_->NewIterator(ReadOptions())); |
198 | 7.17k | for (iter->SeekToFirst(); iter->Valid(); iter->Next()) { |
199 | 7.16k | if (!iter->status().ok()) { |
200 | 0 | fputs(iter->status().ToString().c_str(), stderr); |
201 | 0 | exit(1); |
202 | 0 | } |
203 | 7.16k | table_builder->Add(iter->key(), iter->value()); |
204 | 7.16k | } |
205 | 7 | Status s = table_builder->Finish(); |
206 | 7 | if (!s.ok()) { |
207 | 0 | fputs(s.ToString().c_str(), stderr); |
208 | 0 | exit(1); |
209 | 0 | } |
210 | 7 | uint64_t size = table_builder->TotalFileSize(); |
211 | 7 | CHECK_OK(env->DeleteFile(testFileName)); |
212 | 7 | return size; |
213 | 7 | } |
214 | | |
215 | 1 | int SstFileReader::ShowAllCompressionSizes(size_t block_size) { |
216 | 1 | ReadOptions read_options; |
217 | 1 | Options opts; |
218 | 1 | const ImmutableCFOptions imoptions(opts); |
219 | 1 | auto ikc = std::make_shared<rocksdb::InternalKeyComparator>(opts.comparator); |
220 | 1 | std::vector<std::unique_ptr<IntTblPropCollectorFactory> > |
221 | 1 | block_based_table_factories; |
222 | | |
223 | 1 | std::map<CompressionType, const char*> compress_type; |
224 | 1 | compress_type.insert( |
225 | 1 | std::make_pair(CompressionType::kNoCompression, "kNoCompression")); |
226 | 1 | compress_type.insert(std::make_pair(CompressionType::kSnappyCompression, |
227 | 1 | "kSnappyCompression")); |
228 | 1 | compress_type.insert( |
229 | 1 | std::make_pair(CompressionType::kZlibCompression, "kZlibCompression")); |
230 | 1 | compress_type.insert( |
231 | 1 | std::make_pair(CompressionType::kBZip2Compression, "kBZip2Compression")); |
232 | 1 | compress_type.insert( |
233 | 1 | std::make_pair(CompressionType::kLZ4Compression, "kLZ4Compression")); |
234 | 1 | compress_type.insert( |
235 | 1 | std::make_pair(CompressionType::kLZ4HCCompression, "kLZ4HCCompression")); |
236 | 1 | compress_type.insert(std::make_pair(CompressionType::kZSTDNotFinalCompression, |
237 | 1 | "kZSTDNotFinalCompression")); |
238 | | |
239 | 1 | fprintf(stdout, "Block Size: %" ROCKSDB_PRIszt "\n", block_size); |
240 | | |
241 | 1 | for (CompressionType i = CompressionType::kNoCompression; |
242 | 8 | i <= CompressionType::kZSTDNotFinalCompression; |
243 | 7 | i = (i == kLZ4HCCompression) ? kZSTDNotFinalCompression |
244 | 7 | : CompressionType(i + 1)) { |
245 | 7 | CompressionOptions compress_opt; |
246 | 7 | TableBuilderOptions tb_opts(imoptions, |
247 | 7 | ikc, |
248 | 7 | block_based_table_factories, |
249 | 7 | i, |
250 | 7 | compress_opt, |
251 | 7 | false); |
252 | 7 | uint64_t file_size = CalculateCompressedTableSize(tb_opts, block_size); |
253 | 7 | fprintf(stdout, "Compression: %s", compress_type.find(i)->second); |
254 | 7 | fprintf(stdout, " Size: %" PRIu64 "\n", file_size); |
255 | 7 | } |
256 | 1 | return 0; |
257 | 1 | } |
258 | | |
259 | | Status SstFileReader::ReadTableProperties(uint64_t table_magic_number, |
260 | | RandomAccessFileReader* file, |
261 | 5 | uint64_t file_size) { |
262 | 5 | TableProperties* table_properties = nullptr; |
263 | 5 | Status s = rocksdb::ReadTableProperties(file, file_size, table_magic_number, |
264 | 5 | options_.env, options_.info_log.get(), |
265 | 5 | &table_properties); |
266 | 5 | if (s.ok()) { |
267 | 5 | table_properties_.reset(table_properties); |
268 | 0 | } else { |
269 | 0 | fprintf(stdout, "Not able to read table properties\n"); |
270 | 0 | } |
271 | 5 | return s; |
272 | 5 | } |
273 | | |
274 | | Status SstFileReader::SetTableOptionsByMagicNumber( |
275 | 5 | uint64_t table_magic_number) { |
276 | 5 | assert(table_properties_); |
277 | 5 | if (table_magic_number == kBlockBasedTableMagicNumber || |
278 | 5 | table_magic_number == kLegacyBlockBasedTableMagicNumber) { |
279 | 5 | options_.table_factory = std::make_shared<BlockBasedTableFactory>(); |
280 | 5 | fprintf(stdout, "Sst file format: block-based\n"); |
281 | 5 | auto& props = table_properties_->user_collected_properties; |
282 | 5 | auto pos = props.find(BlockBasedTablePropertyNames::kIndexType); |
283 | 5 | if (pos != props.end()) { |
284 | 5 | auto index_type_on_file = static_cast<IndexType>(DecodeFixed32(pos->second.c_str())); |
285 | 5 | if (index_type_on_file == IndexType::kHashSearch) { |
286 | 0 | options_.prefix_extractor.reset(NewNoopTransform()); |
287 | 0 | } |
288 | 5 | } |
289 | 0 | } else if (table_magic_number == kPlainTableMagicNumber || |
290 | 0 | table_magic_number == kLegacyPlainTableMagicNumber) { |
291 | 0 | options_.allow_mmap_reads = true; |
292 | |
|
293 | 0 | PlainTableOptions plain_table_options; |
294 | 0 | plain_table_options.user_key_len = kPlainTableVariableLength; |
295 | 0 | plain_table_options.bloom_bits_per_key = 0; |
296 | 0 | plain_table_options.hash_table_ratio = 0; |
297 | 0 | plain_table_options.index_sparseness = 1; |
298 | 0 | plain_table_options.huge_page_tlb_size = 0; |
299 | 0 | plain_table_options.encoding_type = kPlain; |
300 | 0 | plain_table_options.full_scan_mode = true; |
301 | |
|
302 | 0 | options_.table_factory.reset(NewPlainTableFactory(plain_table_options)); |
303 | 0 | fprintf(stdout, "Sst file format: plain table\n"); |
304 | 0 | } else { |
305 | 0 | char error_msg_buffer[80]; |
306 | 0 | snprintf(error_msg_buffer, sizeof(error_msg_buffer) - 1, |
307 | 0 | "Unsupported table magic number --- %" PRIx64, table_magic_number); |
308 | 0 | return STATUS(InvalidArgument, error_msg_buffer); |
309 | 0 | } |
310 | | |
311 | 5 | return Status::OK(); |
312 | 5 | } |
313 | | |
314 | 0 | Status SstFileReader::SetOldTableOptions() { |
315 | 0 | assert(table_properties_ == nullptr); |
316 | 0 | options_.table_factory = std::make_shared<BlockBasedTableFactory>(); |
317 | 0 | fprintf(stdout, "Sst file format: block-based(old version)\n"); |
318 | |
|
319 | 0 | return Status::OK(); |
320 | 0 | } |
321 | | |
322 | | Status SstFileReader::ReadSequential(bool print_kv, |
323 | | uint64_t read_num, |
324 | | bool has_from, |
325 | | const std::string& from_key, |
326 | | bool has_to, |
327 | 1 | const std::string& to_key) { |
328 | 1 | if (!table_reader_) { |
329 | 0 | return init_result_; |
330 | 0 | } |
331 | | |
332 | 1 | InternalIterator* iter = |
333 | 1 | table_reader_->NewIterator(ReadOptions(verify_checksum_, false)); |
334 | 1 | uint64_t i = 0; |
335 | 1 | if (has_from) { |
336 | 0 | InternalKey ikey = InternalKey::MaxPossibleForUserKey(from_key); |
337 | 0 | iter->Seek(ikey.Encode()); |
338 | 1 | } else { |
339 | 1 | iter->SeekToFirst(); |
340 | 1 | } |
341 | 1.02k | for (; iter->Valid(); iter->Next()) { |
342 | 1.02k | Slice key = iter->key(); |
343 | 1.02k | Slice value = iter->value(); |
344 | 1.02k | ++i; |
345 | 1.02k | if (read_num > 0 && i > read_num) |
346 | 0 | break; |
347 | | |
348 | 1.02k | ParsedInternalKey ikey; |
349 | 1.02k | if (!ParseInternalKey(key, &ikey)) { |
350 | 0 | std::cerr << "Internal Key [" |
351 | 0 | << key.ToString(true /* in hex*/) |
352 | 0 | << "] parse error!\n"; |
353 | 0 | continue; |
354 | 0 | } |
355 | | |
356 | | // If end marker was specified, we stop before it |
357 | 1.02k | if (has_to && BytewiseComparator()->Compare(ikey.user_key, to_key) >= 0) { |
358 | 0 | break; |
359 | 0 | } |
360 | | |
361 | 1.02k | if (print_kv) { |
362 | 0 | switch (output_format_) { |
363 | 0 | case OutputFormat::kRaw: |
364 | 0 | case OutputFormat::kHex: { |
365 | 0 | bool output_hex = (output_format_ == OutputFormat::kHex); |
366 | 0 | fprintf( |
367 | 0 | stdout, "%s => %s\n", ikey.DebugString(output_hex).c_str(), |
368 | 0 | value.ToString(output_hex).c_str()); |
369 | 0 | break; |
370 | 0 | } |
371 | 0 | case OutputFormat::kDecodedRegularDB: |
372 | 0 | case OutputFormat::kDecodedIntentsDB: |
373 | 0 | auto storage_type = |
374 | 0 | (output_format_ == OutputFormat::kDecodedRegularDB ? StorageDbType::kRegular |
375 | 0 | : StorageDbType::kIntents); |
376 | 0 | fprintf(stdout, "%s", docdb_kv_formatter_->Format(key, value, storage_type).c_str()); |
377 | 0 | break; |
378 | 0 | } |
379 | 0 | } |
380 | 1.02k | } |
381 | | |
382 | 1 | read_num_ += i; |
383 | | |
384 | 1 | Status ret = iter->status(); |
385 | 1 | delete iter; |
386 | 1 | return ret; |
387 | 1 | } |
388 | | |
389 | | Status SstFileReader::ReadTableProperties( |
390 | 1 | std::shared_ptr<const TableProperties>* table_properties) { |
391 | 1 | if (!table_reader_) { |
392 | 0 | return init_result_; |
393 | 0 | } |
394 | | |
395 | 1 | *table_properties = table_reader_->GetTableProperties(); |
396 | 1 | return init_result_; |
397 | 1 | } |
398 | | |
399 | | namespace { |
400 | | |
401 | 0 | void print_help() { |
402 | 0 | fprintf(stderr, |
403 | 0 | "sst_dump [--command=check|scan|none|raw] [--verify_checksum] " |
404 | 0 | "--file=data_dir_OR_sst_file" |
405 | 0 | " [--output_format=raw|hex|decoded_regulardb|decoded_intentsdb]" |
406 | 0 | " [--input_key_hex]" |
407 | 0 | " [--from=<user_key>]" |
408 | 0 | " [--to=<user_key>]" |
409 | 0 | " [--read_num=NUM]" |
410 | 0 | " [--show_properties]" |
411 | 0 | " [--show_compression_sizes]" |
412 | 0 | " [--show_compression_sizes [--set_block_size=<block_size>]]\n"); |
413 | 0 | } |
414 | | |
415 | | } // namespace |
416 | | |
417 | 5 | int SSTDumpTool::Run(int argc, char** argv) { |
418 | 5 | const char* dir_or_file = nullptr; |
419 | 5 | uint64_t read_num = -1; |
420 | 5 | std::string command; |
421 | | |
422 | 5 | char junk; |
423 | 5 | uint64_t n; |
424 | 5 | bool verify_checksum = false; |
425 | 5 | OutputFormat output_format = OutputFormat::kRaw; |
426 | 5 | bool input_key_hex = false; |
427 | 5 | bool has_from = false; |
428 | 5 | bool has_to = false; |
429 | 5 | bool show_properties = false; |
430 | 5 | bool show_compression_sizes = false; |
431 | 5 | bool set_block_size = false; |
432 | 5 | std::string from_key; |
433 | 5 | std::string to_key; |
434 | 5 | std::string block_size_str; |
435 | 5 | size_t block_size; |
436 | 15 | for (int i = 1; i < argc; i++) { |
437 | 10 | if (strncmp(argv[i], "--file=", 7) == 0) { |
438 | 5 | dir_or_file = argv[i] + 7; |
439 | 5 | } else if (strncmp(argv[i], "--output_format=", 16) == 0) { |
440 | 0 | auto option = argv[i] + 16; |
441 | 0 | if (strcmp(option, "raw") == 0) { |
442 | 0 | output_format = OutputFormat::kRaw; |
443 | 0 | } else if (strcmp(option, "hex") == 0) { |
444 | 0 | output_format = OutputFormat::kHex; |
445 | 0 | } else if (strcmp(option, "decoded_regulardb") == 0) { |
446 | 0 | output_format = OutputFormat::kDecodedRegularDB; |
447 | 0 | } else if (strcmp(option, "decoded_intentsdb") == 0) { |
448 | 0 | output_format = OutputFormat::kDecodedIntentsDB; |
449 | 0 | } else { |
450 | 0 | print_help(); |
451 | 0 | exit(1); |
452 | 0 | } |
453 | 5 | } else if (strcmp(argv[i], "--input_key_hex") == 0) { |
454 | 0 | input_key_hex = true; |
455 | 5 | } else if (sscanf(argv[i], "--read_num=%" PRIu64 "%c", &n, &junk) == 1) { |
456 | 0 | read_num = n; |
457 | 5 | } else if (strcmp(argv[i], "--verify_checksum") == 0) { |
458 | 0 | verify_checksum = true; |
459 | 5 | } else if (strncmp(argv[i], "--command=", 10) == 0) { |
460 | 3 | command = argv[i] + 10; |
461 | 2 | } else if (strncmp(argv[i], "--from=", 7) == 0) { |
462 | 0 | from_key = argv[i] + 7; |
463 | 0 | has_from = true; |
464 | 2 | } else if (strncmp(argv[i], "--to=", 5) == 0) { |
465 | 0 | to_key = argv[i] + 5; |
466 | 0 | has_to = true; |
467 | 2 | } else if (strcmp(argv[i], "--show_properties") == 0) { |
468 | 1 | show_properties = true; |
469 | 1 | } else if (strcmp(argv[i], "--show_compression_sizes") == 0) { |
470 | 1 | show_compression_sizes = true; |
471 | 0 | } else if (strncmp(argv[i], "--set_block_size=", 17) == 0) { |
472 | 0 | set_block_size = true; |
473 | 0 | block_size_str = argv[i] + 17; |
474 | 0 | std::istringstream iss(block_size_str); |
475 | 0 | if (iss.fail()) { |
476 | 0 | fprintf(stderr, "block size must be numeric"); |
477 | 0 | exit(1); |
478 | 0 | } |
479 | 0 | iss >> block_size; |
480 | 0 | } else { |
481 | 0 | print_help(); |
482 | 0 | exit(1); |
483 | 0 | } |
484 | 10 | } |
485 | | |
486 | 5 | if (input_key_hex) { |
487 | 0 | if (has_from) { |
488 | 0 | from_key = rocksdb::LDBCommand::HexToString(from_key); |
489 | 0 | } |
490 | 0 | if (has_to) { |
491 | 0 | to_key = rocksdb::LDBCommand::HexToString(to_key); |
492 | 0 | } |
493 | 0 | } |
494 | | |
495 | 5 | if (dir_or_file == nullptr) { |
496 | 0 | print_help(); |
497 | 0 | exit(1); |
498 | 0 | } |
499 | | |
500 | 5 | std::vector<std::string> filenames; |
501 | 5 | rocksdb::Env* env = rocksdb::Env::Default(); |
502 | 5 | rocksdb::Status st = env->GetChildren(dir_or_file, &filenames); |
503 | 5 | bool dir = true; |
504 | 5 | if (!st.ok()) { |
505 | 5 | filenames.clear(); |
506 | 5 | filenames.push_back(dir_or_file); |
507 | 5 | dir = false; |
508 | 5 | } |
509 | | |
510 | 5 | fprintf(stdout, "from [%s] to [%s]\n", |
511 | 5 | rocksdb::Slice(from_key).ToString(true).c_str(), |
512 | 5 | rocksdb::Slice(to_key).ToString(true).c_str()); |
513 | | |
514 | 5 | uint64_t total_read = 0; |
515 | 9 | for (size_t i = 0; i < filenames.size(); i++) { |
516 | 5 | std::string filename = filenames.at(i); |
517 | 5 | if (filename.length() <= 4 || |
518 | 5 | filename.rfind(".sst") != filename.length() - 4) { |
519 | | // ignore |
520 | 0 | continue; |
521 | 0 | } |
522 | 5 | if (dir) { |
523 | 0 | filename = std::string(dir_or_file) + "/" + filename; |
524 | 0 | } |
525 | | |
526 | 5 | rocksdb::SstFileReader reader(filename, verify_checksum, output_format, formatter_); |
527 | 5 | if (!reader.getStatus().ok()) { |
528 | 0 | fprintf(stderr, "%s: %s\n", filename.c_str(), |
529 | 0 | reader.getStatus().ToString().c_str()); |
530 | 0 | exit(1); |
531 | 0 | } |
532 | | |
533 | 5 | if (show_compression_sizes) { |
534 | 1 | if (set_block_size) { |
535 | 0 | reader.ShowAllCompressionSizes(block_size); |
536 | 1 | } else { |
537 | 1 | reader.ShowAllCompressionSizes(16384); |
538 | 1 | } |
539 | 1 | return 0; |
540 | 1 | } |
541 | | |
542 | 4 | if (command == "raw") { |
543 | 3 | std::string out_filename = filename.substr(0, filename.length() - 4); |
544 | 3 | out_filename.append("_dump.txt"); |
545 | | |
546 | 3 | st = reader.DumpTable(out_filename); |
547 | 3 | if (!st.ok()) { |
548 | 0 | fprintf(stderr, "%s: %s\n", filename.c_str(), st.ToString().c_str()); |
549 | 0 | exit(1); |
550 | 3 | } else { |
551 | 3 | fprintf(stdout, "raw dump written to file %s\n", &out_filename[0]); |
552 | 3 | } |
553 | 3 | continue; |
554 | 1 | } |
555 | | |
556 | | // scan all files in give file path. |
557 | 1 | if (command == "" || command == "scan" || command == "check") { |
558 | 1 | st = reader.ReadSequential(command == "scan", |
559 | 1 | read_num > 0 ? (read_num - total_read) : |
560 | 0 | read_num, |
561 | 1 | has_from, from_key, has_to, to_key); |
562 | 1 | if (!st.ok()) { |
563 | 0 | fprintf(stderr, "%s: %s\n", filename.c_str(), |
564 | 0 | st.ToString().c_str()); |
565 | 0 | } |
566 | 1 | total_read += reader.GetReadNumber(); |
567 | 1 | if (read_num > 0 && total_read > read_num) { |
568 | 0 | break; |
569 | 0 | } |
570 | 1 | } |
571 | 1 | if (show_properties) { |
572 | 1 | const rocksdb::TableProperties* table_properties; |
573 | | |
574 | 1 | std::shared_ptr<const rocksdb::TableProperties> |
575 | 1 | table_properties_from_reader; |
576 | 1 | st = reader.ReadTableProperties(&table_properties_from_reader); |
577 | 1 | if (!st.ok()) { |
578 | 0 | fprintf(stderr, "%s: %s\n", filename.c_str(), st.ToString().c_str()); |
579 | 0 | fprintf(stderr, "Try to use initial table properties\n"); |
580 | 0 | table_properties = reader.GetInitTableProperties(); |
581 | 1 | } else { |
582 | 1 | table_properties = table_properties_from_reader.get(); |
583 | 1 | } |
584 | 1 | if (table_properties != nullptr) { |
585 | 1 | fprintf(stdout, |
586 | 1 | "Table Properties:\n" |
587 | 1 | "------------------------------\n" |
588 | 1 | " %s", |
589 | 1 | table_properties->ToString("\n ", ": ").c_str()); |
590 | 1 | fprintf(stdout, "# deleted keys: %" PRIu64 "\n", |
591 | 1 | rocksdb::GetDeletedKeys( |
592 | 1 | table_properties->user_collected_properties)); |
593 | 1 | fprintf(stdout, |
594 | 1 | " User collected properties:\n" |
595 | 1 | " ------------------------------\n"); |
596 | 5 | for (const auto& prop : table_properties->user_collected_properties) { |
597 | 5 | fprintf( |
598 | 5 | stdout, " %s: %s\n", prop.first.c_str(), Slice(prop.second).ToDebugString().c_str()); |
599 | 5 | } |
600 | 1 | } |
601 | 1 | } |
602 | 1 | } |
603 | 4 | return 0; |
604 | 5 | } |
605 | | } // namespace rocksdb |
606 | | |
607 | | #endif // ROCKSDB_LITE |