YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/rocksdb/tools/ldb_cmd.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
#include "yb/rocksdb/tools/ldb_cmd.h"
22
23
#ifndef __STDC_FORMAT_MACROS
24
#define __STDC_FORMAT_MACROS
25
#endif
26
27
#include <inttypes.h>
28
29
#include <cstdlib>
30
#include <ctime>
31
#include <limits>
32
#include <sstream>
33
#include <string>
34
#include <stdexcept>
35
36
#include "yb/rocksdb/db/dbformat.h"
37
#include "yb/rocksdb/db/db_impl.h"
38
#include "yb/rocksdb/db/log_reader.h"
39
#include "yb/rocksdb/db/filename.h"
40
#include "yb/rocksdb/db/writebuffer.h"
41
#include "yb/rocksdb/db/write_batch_internal.h"
42
#include "yb/rocksdb/filter_policy.h"
43
#include "yb/rocksdb/write_batch.h"
44
#include "yb/rocksdb/cache.h"
45
#include "yb/rocksdb/table.h"
46
#include "yb/rocksdb/table_properties.h"
47
#include "yb/rocksdb/table/scoped_arena_iterator.h"
48
#include "yb/rocksdb/port/dirent.h"
49
#include "yb/rocksdb/tools/sst_dump_tool_imp.h"
50
#include "yb/rocksdb/util/coding.h"
51
#include "yb/rocksdb/utilities/ttl/db_ttl_impl.h"
52
53
#include "yb/util/status_log.h"
54
#include "yb/util/string_util.h"
55
56
namespace rocksdb {
57
58
using std::string;
59
60
const string LDBCommand::ARG_DB = "db";
61
const string LDBCommand::ARG_PATH = "path";
62
const string LDBCommand::ARG_HEX = "hex";
63
const string LDBCommand::ARG_KEY_HEX = "key_hex";
64
const string LDBCommand::ARG_VALUE_HEX = "value_hex";
65
const string LDBCommand::ARG_CF_NAME = "column_family";
66
const string LDBCommand::ARG_TTL = "ttl";
67
const string LDBCommand::ARG_TTL_START = "start_time";
68
const string LDBCommand::ARG_TTL_END = "end_time";
69
const string LDBCommand::ARG_TIMESTAMP = "timestamp";
70
const string LDBCommand::ARG_FROM = "from";
71
const string LDBCommand::ARG_TO = "to";
72
const string LDBCommand::ARG_MAX_KEYS = "max_keys";
73
const string LDBCommand::ARG_BLOOM_BITS = "bloom_bits";
74
const string LDBCommand::ARG_FIX_PREFIX_LEN = "fix_prefix_len";
75
const string LDBCommand::ARG_COMPRESSION_TYPE = "compression_type";
76
const string LDBCommand::ARG_BLOCK_SIZE = "block_size";
77
const string LDBCommand::ARG_AUTO_COMPACTION = "auto_compaction";
78
const string LDBCommand::ARG_DB_WRITE_BUFFER_SIZE = "db_write_buffer_size";
79
const string LDBCommand::ARG_WRITE_BUFFER_SIZE = "write_buffer_size";
80
const string LDBCommand::ARG_FILE_SIZE = "file_size";
81
const string LDBCommand::ARG_CREATE_IF_MISSING = "create_if_missing";
82
const string LDBCommand::ARG_NO_VALUE = "no_value";
83
const string LDBCommand::ARG_UNIVERSE_KEY_FILE = "key_file";
84
const string LDBCommand::ARG_ONLY_VERIFY_CHECKSUMS = "only_verify_checksums";
85
86
const char* LDBCommand::DELIM = " ==> ";
87
88
namespace {
89
90
void DumpWalFile(std::string wal_file, bool print_header, bool print_values,
91
                 LDBCommandExecuteResult* exec_state);
92
93
void DumpSstFile(std::string filename, bool output_hex, bool show_properties);
94
};
95
96
LDBCommand* LDBCommand::InitFromCmdLineArgs(
97
    int argc, char** argv, const Options& options,
98
    const LDBOptions& ldb_options,
99
4
    const std::vector<ColumnFamilyDescriptor>* column_families) {
100
4
  vector<string> args;
101
16
  for (int i = 1; i < argc; i++) {
102
12
    args.push_back(argv[i]);
103
12
  }
104
4
  return InitFromCmdLineArgs(args, options, ldb_options, column_families);
105
4
}
106
107
/**
108
 * Parse the command-line arguments and create the appropriate LDBCommand2
109
 * instance.
110
 * The command line arguments must be in the following format:
111
 * ./ldb --db=PATH_TO_DB [--commonOpt1=commonOpt1Val] ..
112
 *        COMMAND <PARAM1> <PARAM2> ... [-cmdSpecificOpt1=cmdSpecificOpt1Val] ..
113
 * This is similar to the command line format used by HBaseClientTool.
114
 * Command name is not included in args.
115
 * Returns nullptr if the command-line cannot be parsed.
116
 */
117
LDBCommand* LDBCommand::InitFromCmdLineArgs(
118
    const vector<string>& args, const Options& options,
119
    const LDBOptions& ldb_options,
120
12
    const std::vector<ColumnFamilyDescriptor>* column_families) {
121
  // --x=y command line arguments are added as x->y map entries.
122
12
  map<string, string> option_map;
123
124
  // Command-line arguments of the form --hex end up in this array as hex
125
12
  vector<string> flags;
126
127
  // Everything other than option_map and flags. Represents commands
128
  // and their parameters.  For eg: put key1 value1 go into this vector.
129
12
  vector<string> cmdTokens;
130
131
12
  const string OPTION_PREFIX = "--";
132
133
36
  for (const auto& arg : args) {
134
36
    if (arg[0] == '-' && arg[1] == '-') {
135
24
      auto pos = arg.find('=', 0);
136
24
      if (pos != string::npos) {
137
22
        string optionKey = arg.substr(OPTION_PREFIX.size(), pos - OPTION_PREFIX.size());
138
22
        option_map[optionKey] = arg.substr(pos + 1);
139
2
      } else {
140
2
        string optionKey = arg.substr(OPTION_PREFIX.size());
141
2
        flags.push_back(optionKey);
142
2
      }
143
12
    } else {
144
12
      cmdTokens.push_back(arg);
145
12
    }
146
36
  }
147
148
12
  if (cmdTokens.size() < 1) {
149
0
    fprintf(stderr, "Command not specified!");
150
0
    return nullptr;
151
0
  }
152
153
12
  string cmd = cmdTokens[0];
154
12
  vector<string> cmdParams(cmdTokens.begin()+1, cmdTokens.end());
155
12
  LDBCommand* command = LDBCommand::SelectCommand(
156
12
    cmd,
157
12
    cmdParams,
158
12
    option_map,
159
12
    flags
160
12
  );
161
162
12
  if (command) {
163
12
    command->SetDBOptions(options);
164
12
    command->SetLDBOptions(ldb_options);
165
12
  }
166
12
  return command;
167
12
}
168
169
LDBCommand* LDBCommand::SelectCommand(
170
    const std::string& cmd,
171
    const vector<string>& cmdParams,
172
    const map<string, string>& option_map,
173
    const vector<string>& flags
174
12
  ) {
175
176
12
  if (cmd == GetCommand::Name()) {
177
0
    return new GetCommand(cmdParams, option_map, flags);
178
12
  } else if (cmd == PutCommand::Name()) {
179
0
    return new PutCommand(cmdParams, option_map, flags);
180
12
  } else if (cmd == BatchPutCommand::Name()) {
181
0
    return new BatchPutCommand(cmdParams, option_map, flags);
182
12
  } else if (cmd == ScanCommand::Name()) {
183
2
    return new ScanCommand(cmdParams, option_map, flags);
184
10
  } else if (cmd == DeleteCommand::Name()) {
185
0
    return new DeleteCommand(cmdParams, option_map, flags);
186
10
  } else if (cmd == ApproxSizeCommand::Name()) {
187
0
    return new ApproxSizeCommand(cmdParams, option_map, flags);
188
10
  } else if (cmd == DBQuerierCommand::Name()) {
189
0
    return new DBQuerierCommand(cmdParams, option_map, flags);
190
10
  } else if (cmd == CompactorCommand::Name()) {
191
0
    return new CompactorCommand(cmdParams, option_map, flags);
192
10
  } else if (cmd == WALDumperCommand::Name()) {
193
0
    return new WALDumperCommand(cmdParams, option_map, flags);
194
10
  } else if (cmd == ReduceDBLevelsCommand::Name()) {
195
8
    return new ReduceDBLevelsCommand(cmdParams, option_map, flags);
196
2
  } else if (cmd == ChangeCompactionStyleCommand::Name()) {
197
0
    return new ChangeCompactionStyleCommand(cmdParams, option_map, flags);
198
2
  } else if (cmd == DBDumperCommand::Name()) {
199
0
    return new DBDumperCommand(cmdParams, option_map, flags);
200
2
  } else if (cmd == DBLoaderCommand::Name()) {
201
0
    return new DBLoaderCommand(cmdParams, option_map, flags);
202
2
  } else if (cmd == ManifestDumpCommand::Name()) {
203
0
    return new ManifestDumpCommand(cmdParams, option_map, flags);
204
2
  } else if (cmd == ListColumnFamiliesCommand::Name()) {
205
0
    return new ListColumnFamiliesCommand(cmdParams, option_map, flags);
206
2
  } else if (cmd == CreateColumnFamilyCommand::Name()) {
207
0
    return new CreateColumnFamilyCommand(cmdParams, option_map, flags);
208
2
  } else if (cmd == DBFileDumperCommand::Name()) {
209
0
    return new DBFileDumperCommand(cmdParams, option_map, flags);
210
2
  } else if (cmd == InternalDumpCommand::Name()) {
211
0
    return new InternalDumpCommand(cmdParams, option_map, flags);
212
2
  } else if (cmd == CheckConsistencyCommand::Name()) {
213
2
    return new CheckConsistencyCommand(cmdParams, option_map, flags);
214
2
  }
215
0
  return nullptr;
216
0
}
217
218
219
/**
220
 * Parses the specific integer option and fills in the value.
221
 * Returns true if the option is found.
222
 * Returns false if the option is not found or if there is an error parsing the
223
 * value.  If there is an error, the specified exec_state is also
224
 * updated.
225
 */
226
bool LDBCommand::ParseIntOption(const map<string, string>& options,
227
                                const string& option, int& value,
228
114
                                LDBCommandExecuteResult& exec_state) {
229
230
114
  map<string, string>::const_iterator itr = option_map_.find(option);
231
114
  if (itr != option_map_.end()) {
232
8
    try {
233
#if defined(CYGWIN)
234
      value = strtol(itr->second.c_str(), 0, 10);
235
#else
236
8
      value = stoi(itr->second);
237
8
#endif
238
8
      return true;
239
0
    } catch(const std::invalid_argument&) {
240
0
      exec_state =
241
0
          LDBCommandExecuteResult::Failed(option + " has an invalid value.");
242
0
    } catch(const std::out_of_range&) {
243
0
      exec_state = LDBCommandExecuteResult::Failed(
244
0
          option + " has a value out-of-range.");
245
0
    }
246
8
  }
247
106
  return false;
248
114
}
249
250
/**
251
 * Parses the specified option and fills in the value.
252
 * Returns true if the option is found.
253
 * Returns false otherwise.
254
 */
255
bool LDBCommand::ParseStringOption(const map<string, string>& options,
256
0
                                   const string& option, string* value) {
257
0
  auto itr = option_map_.find(option);
258
0
  if (itr != option_map_.end()) {
259
0
    *value = itr->second;
260
0
    return true;
261
0
  }
262
0
  return false;
263
0
}
264
265
17
Options LDBCommand::PrepareOptionsForOpenDB() {
266
17
  Options opt = options_;
267
17
  opt.create_if_missing = false;
268
269
17
  map<string, string>::const_iterator itr;
270
271
17
  BlockBasedTableOptions table_options;
272
17
  bool use_table_options = false;
273
17
  int bits;
274
17
  if (ParseIntOption(option_map_, ARG_BLOOM_BITS, bits, exec_state_)) {
275
0
    if (bits > 0) {
276
0
      use_table_options = true;
277
0
      table_options.filter_policy.reset(NewBloomFilterPolicy(bits));
278
0
    } else {
279
0
      exec_state_ =
280
0
          LDBCommandExecuteResult::Failed(ARG_BLOOM_BITS + " must be > 0.");
281
0
    }
282
0
  }
283
284
17
  int block_size;
285
17
  if (ParseIntOption(option_map_, ARG_BLOCK_SIZE, block_size, exec_state_)) {
286
0
    if (block_size > 0) {
287
0
      use_table_options = true;
288
0
      table_options.block_size = block_size;
289
0
    } else {
290
0
      exec_state_ =
291
0
          LDBCommandExecuteResult::Failed(ARG_BLOCK_SIZE + " must be > 0.");
292
0
    }
293
0
  }
294
295
17
  if (use_table_options) {
296
0
    opt.table_factory.reset(NewBlockBasedTableFactory(table_options));
297
0
  }
298
299
17
  itr = option_map_.find(ARG_AUTO_COMPACTION);
300
17
  if (itr != option_map_.end()) {
301
0
    opt.disable_auto_compactions = !StringToBool(itr->second);
302
0
  }
303
304
17
  itr = option_map_.find(ARG_COMPRESSION_TYPE);
305
17
  if (itr != option_map_.end()) {
306
0
    string comp = itr->second;
307
0
    if (comp == "no") {
308
0
      opt.compression = kNoCompression;
309
0
    } else if (comp == "snappy") {
310
0
      opt.compression = kSnappyCompression;
311
0
    } else if (comp == "zlib") {
312
0
      opt.compression = kZlibCompression;
313
0
    } else if (comp == "bzip2") {
314
0
      opt.compression = kBZip2Compression;
315
0
    } else if (comp == "lz4") {
316
0
      opt.compression = kLZ4Compression;
317
0
    } else if (comp == "lz4hc") {
318
0
      opt.compression = kLZ4HCCompression;
319
0
    } else if (comp == "zstd") {
320
0
      opt.compression = kZSTDNotFinalCompression;
321
0
    } else {
322
      // Unknown compression.
323
0
      exec_state_ =
324
0
          LDBCommandExecuteResult::Failed("Unknown compression level: " + comp);
325
0
    }
326
0
  }
327
328
17
  int db_write_buffer_size;
329
17
  if (ParseIntOption(option_map_, ARG_DB_WRITE_BUFFER_SIZE,
330
0
        db_write_buffer_size, exec_state_)) {
331
0
    if (db_write_buffer_size >= 0) {
332
0
      opt.db_write_buffer_size = db_write_buffer_size;
333
0
    } else {
334
0
      exec_state_ = LDBCommandExecuteResult::Failed(ARG_DB_WRITE_BUFFER_SIZE +
335
0
                                                    " must be >= 0.");
336
0
    }
337
0
  }
338
339
17
  int write_buffer_size;
340
17
  if (ParseIntOption(option_map_, ARG_WRITE_BUFFER_SIZE, write_buffer_size,
341
0
        exec_state_)) {
342
0
    if (write_buffer_size > 0) {
343
0
      opt.write_buffer_size = write_buffer_size;
344
0
    } else {
345
0
      exec_state_ = LDBCommandExecuteResult::Failed(ARG_WRITE_BUFFER_SIZE +
346
0
                                                    " must be > 0.");
347
0
    }
348
0
  }
349
350
17
  int file_size;
351
17
  if (ParseIntOption(option_map_, ARG_FILE_SIZE, file_size, exec_state_)) {
352
0
    if (file_size > 0) {
353
0
      opt.target_file_size_base = file_size;
354
0
    } else {
355
0
      exec_state_ =
356
0
          LDBCommandExecuteResult::Failed(ARG_FILE_SIZE + " must be > 0.");
357
0
    }
358
0
  }
359
360
17
  if (opt.db_paths.size() == 0) {
361
17
    opt.db_paths.emplace_back(db_path_, std::numeric_limits<uint64_t>::max());
362
17
  }
363
364
17
  int fix_prefix_len;
365
17
  if (ParseIntOption(option_map_, ARG_FIX_PREFIX_LEN, fix_prefix_len,
366
0
                     exec_state_)) {
367
0
    if (fix_prefix_len > 0) {
368
0
      opt.prefix_extractor.reset(
369
0
          NewFixedPrefixTransform(static_cast<size_t>(fix_prefix_len)));
370
0
    } else {
371
0
      exec_state_ =
372
0
          LDBCommandExecuteResult::Failed(ARG_FIX_PREFIX_LEN + " must be > 0.");
373
0
    }
374
0
  }
375
376
15
  opt.env = env_ ? env_.get() : Env::Default();
377
17
  opt.checkpoint_env = Env::Default();
378
379
17
  return opt;
380
17
}
381
382
bool LDBCommand::ParseKeyValue(const string& line, string* key, string* value,
383
0
                              bool is_key_hex, bool is_value_hex) {
384
0
  size_t pos = line.find(DELIM);
385
0
  if (pos != string::npos) {
386
0
    *key = line.substr(0, pos);
387
0
    *value = line.substr(pos + strlen(DELIM));
388
0
    if (is_key_hex) {
389
0
      *key = HexToString(*key);
390
0
    }
391
0
    if (is_value_hex) {
392
0
      *value = HexToString(*value);
393
0
    }
394
0
    return true;
395
0
  } else {
396
0
    return false;
397
0
  }
398
0
}
399
400
/**
401
 * Make sure that ONLY the command-line options and flags expected by this
402
 * command are specified on the command-line.  Extraneous options are usually
403
 * the result of user error.
404
 * Returns true if all checks pass.  Else returns false, and prints an
405
 * appropriate error msg to stderr.
406
 */
407
4
bool LDBCommand::ValidateCmdLineOptions() {
408
409
4
  for (map<string, string>::const_iterator itr = option_map_.begin();
410
10
        itr != option_map_.end(); ++itr) {
411
6
    if (find(valid_cmd_line_options_.begin(),
412
6
          valid_cmd_line_options_.end(), itr->first) ==
413
0
          valid_cmd_line_options_.end()) {
414
0
      fprintf(stderr, "Invalid command-line option %s\n", itr->first.c_str());
415
0
      return false;
416
0
    }
417
6
  }
418
419
4
  for (vector<string>::const_iterator itr = flags_.begin();
420
6
        itr != flags_.end(); ++itr) {
421
2
    if (find(valid_cmd_line_options_.begin(),
422
2
          valid_cmd_line_options_.end(), *itr) ==
423
0
          valid_cmd_line_options_.end()) {
424
0
      fprintf(stderr, "Invalid command-line flag %s\n", itr->c_str());
425
0
      return false;
426
0
    }
427
2
  }
428
429
4
  if (!NoDBOpen() && option_map_.find(ARG_DB) == option_map_.end() &&
430
0
      option_map_.find(ARG_PATH) == option_map_.end()) {
431
0
    fprintf(stderr, "Either %s or %s must be specified.\n", ARG_DB.c_str(),
432
0
            ARG_PATH.c_str());
433
0
    return false;
434
0
  }
435
436
4
  return true;
437
4
}
438
439
CompactorCommand::CompactorCommand(const vector<string>& params,
440
      const map<string, string>& options, const vector<string>& flags) :
441
    LDBCommand(options, flags, false,
442
               BuildCmdLineOptions({ARG_FROM, ARG_TO, ARG_HEX, ARG_KEY_HEX,
443
                                    ARG_VALUE_HEX, ARG_TTL})),
444
0
    null_from_(true), null_to_(true) {
445
446
0
  map<string, string>::const_iterator itr = options.find(ARG_FROM);
447
0
  if (itr != options.end()) {
448
0
    null_from_ = false;
449
0
    from_ = itr->second;
450
0
  }
451
452
0
  itr = options.find(ARG_TO);
453
0
  if (itr != options.end()) {
454
0
    null_to_ = false;
455
0
    to_ = itr->second;
456
0
  }
457
458
0
  if (is_key_hex_) {
459
0
    if (!null_from_) {
460
0
      from_ = HexToString(from_);
461
0
    }
462
0
    if (!null_to_) {
463
0
      to_ = HexToString(to_);
464
0
    }
465
0
  }
466
0
}
467
468
0
void CompactorCommand::Help(string& ret) {
469
0
  ret.append("  ");
470
0
  ret.append(CompactorCommand::Name());
471
0
  ret.append(HelpRangeCmdArgs());
472
0
  ret.append("\n");
473
0
}
474
475
0
void CompactorCommand::DoCommand() {
476
0
  if (!db_) {
477
0
    assert(GetExecuteState().IsFailed());
478
0
    return;
479
0
  }
480
481
0
  Slice* begin = nullptr;
482
0
  Slice* end = nullptr;
483
0
  if (!null_from_) {
484
0
    begin = new Slice(from_);
485
0
  }
486
0
  if (!null_to_) {
487
0
    end = new Slice(to_);
488
0
  }
489
490
0
  CompactRangeOptions cro;
491
0
  cro.bottommost_level_compaction = BottommostLevelCompaction::kForce;
492
493
0
  CHECK_OK(db_->CompactRange(cro, begin, end));
494
0
  exec_state_ = LDBCommandExecuteResult::Succeed("");
495
496
0
  delete begin;
497
0
  delete end;
498
0
}
499
500
// ----------------------------------------------------------------------------
501
502
const string DBLoaderCommand::ARG_DISABLE_WAL = "disable_wal";
503
const string DBLoaderCommand::ARG_BULK_LOAD = "bulk_load";
504
const string DBLoaderCommand::ARG_COMPACT = "compact";
505
506
DBLoaderCommand::DBLoaderCommand(const vector<string>& params,
507
      const map<string, string>& options, const vector<string>& flags) :
508
    LDBCommand(options, flags, false,
509
               BuildCmdLineOptions({ARG_HEX, ARG_KEY_HEX, ARG_VALUE_HEX,
510
                                    ARG_FROM, ARG_TO, ARG_CREATE_IF_MISSING,
511
                                    ARG_DISABLE_WAL, ARG_BULK_LOAD,
512
                                    ARG_COMPACT})),
513
    create_if_missing_(false), disable_wal_(false), bulk_load_(false),
514
0
    compact_(false) {
515
516
0
  create_if_missing_ = IsFlagPresent(flags, ARG_CREATE_IF_MISSING);
517
0
  disable_wal_ = IsFlagPresent(flags, ARG_DISABLE_WAL);
518
0
  bulk_load_ = IsFlagPresent(flags, ARG_BULK_LOAD);
519
0
  compact_ = IsFlagPresent(flags, ARG_COMPACT);
520
0
}
521
522
0
void DBLoaderCommand::Help(string& ret) {
523
0
  ret.append("  ");
524
0
  ret.append(DBLoaderCommand::Name());
525
0
  ret.append(" [--" + ARG_CREATE_IF_MISSING + "]");
526
0
  ret.append(" [--" + ARG_DISABLE_WAL + "]");
527
0
  ret.append(" [--" + ARG_BULK_LOAD + "]");
528
0
  ret.append(" [--" + ARG_COMPACT + "]");
529
0
  ret.append("\n");
530
0
}
531
532
0
Options DBLoaderCommand::PrepareOptionsForOpenDB() {
533
0
  Options opt = LDBCommand::PrepareOptionsForOpenDB();
534
0
  opt.create_if_missing = create_if_missing_;
535
0
  if (bulk_load_) {
536
0
    opt.PrepareForBulkLoad();
537
0
  }
538
0
  return opt;
539
0
}
540
541
0
void DBLoaderCommand::DoCommand() {
542
0
  if (!db_) {
543
0
    assert(GetExecuteState().IsFailed());
544
0
    return;
545
0
  }
546
547
0
  WriteOptions write_options;
548
0
  if (disable_wal_) {
549
0
    write_options.disableWAL = true;
550
0
  }
551
552
0
  int bad_lines = 0;
553
0
  string line;
554
0
  while (getline(std::cin, line, '\n')) {
555
0
    string key;
556
0
    string value;
557
0
    if (ParseKeyValue(line, &key, &value, is_key_hex_, is_value_hex_)) {
558
0
      CHECK_OK(db_->Put(write_options, GetCfHandle(), Slice(key), Slice(value)));
559
0
    } else if (0 == line.find("Keys in range:")) {
560
      // ignore this line
561
0
    } else if (0 == line.find("Created bg thread 0x")) {
562
      // ignore this line
563
0
    } else {
564
0
      bad_lines++;
565
0
    }
566
0
  }
567
568
0
  if (bad_lines > 0) {
569
0
    std::cout << "Warning: " << bad_lines << " bad lines ignored." << std::endl;
570
0
  }
571
0
  if (compact_) {
572
0
    CHECK_OK(db_->CompactRange(CompactRangeOptions(), GetCfHandle(), nullptr, nullptr));
573
0
  }
574
0
}
575
576
// ----------------------------------------------------------------------------
577
578
namespace {
579
580
0
void DumpManifestFile(std::string file, bool verbose, bool hex) {
581
0
  Options options;
582
0
  EnvOptions sopt;
583
0
  std::string dbname("dummy");
584
0
  std::shared_ptr<Cache> tc(NewLRUCache(options.max_open_files - 10,
585
0
                                        options.table_cache_numshardbits));
586
  // Notice we are using the default options not through SanitizeOptions(),
587
  // if VersionSet::DumpManifest() depends on any option done by
588
  // SanitizeOptions(), we need to initialize it manually.
589
0
  options.db_paths.emplace_back("dummy", 0);
590
0
  options.num_levels = 64;
591
0
  WriteController wc(options.delayed_write_rate);
592
0
  WriteBuffer wb(options.db_write_buffer_size);
593
0
  VersionSet versions(dbname, &options, sopt, tc.get(), &wb, &wc);
594
0
  Status s = versions.DumpManifest(options, file, verbose, hex);
595
0
  if (!s.ok()) {
596
0
    printf("Error in processing file %s %s\n", file.c_str(),
597
0
           s.ToString().c_str());
598
0
  }
599
0
}
600
601
}  // namespace
602
603
const string ManifestDumpCommand::ARG_VERBOSE = "verbose";
604
const string ManifestDumpCommand::ARG_JSON = "json";
605
const string ManifestDumpCommand::ARG_PATH = "path";
606
607
0
void ManifestDumpCommand::Help(string& ret) {
608
0
  ret.append("  ");
609
0
  ret.append(ManifestDumpCommand::Name());
610
0
  ret.append(" [--" + ARG_VERBOSE + "]");
611
0
  ret.append(" [--" + ARG_JSON + "]");
612
0
  ret.append(" [--" + ARG_PATH + "=<path_to_manifest_file>]");
613
0
  ret.append("\n");
614
0
}
615
616
ManifestDumpCommand::ManifestDumpCommand(const vector<string>& params,
617
      const map<string, string>& options, const vector<string>& flags) :
618
    LDBCommand(options, flags, false,
619
               BuildCmdLineOptions({ARG_VERBOSE, ARG_PATH, ARG_HEX, ARG_JSON})),
620
    verbose_(false),
621
0
    path_("") {
622
0
  verbose_ = IsFlagPresent(flags, ARG_VERBOSE);
623
624
0
  map<string, string>::const_iterator itr = options.find(ARG_PATH);
625
0
  if (itr != options.end()) {
626
0
    path_ = itr->second;
627
0
    if (path_.empty()) {
628
0
      exec_state_ = LDBCommandExecuteResult::Failed("--path: missing pathname");
629
0
    }
630
0
  }
631
0
}
632
633
0
void ManifestDumpCommand::DoCommand() {
634
635
0
  std::string manifestfile;
636
637
0
  if (!path_.empty()) {
638
0
    manifestfile = path_;
639
0
  } else {
640
0
    bool found = false;
641
    // We need to find the manifest file by searching the directory
642
    // containing the db for files of the form MANIFEST_[0-9]+
643
644
0
    auto CloseDir = [](DIR* p) { closedir(p); };
645
0
    std::unique_ptr<DIR, decltype(CloseDir)> d(opendir(db_path_.c_str()),
646
0
                                               CloseDir);
647
648
0
    if (d == nullptr) {
649
0
      exec_state_ =
650
0
          LDBCommandExecuteResult::Failed(db_path_ + " is not a directory");
651
0
      return;
652
0
    }
653
0
    struct dirent* entry;
654
0
    while ((entry = readdir(d.get())) != nullptr) {
655
0
      unsigned int match;
656
0
      uint64_t num;
657
0
      if (sscanf(entry->d_name, "MANIFEST-%" PRIu64 "%n", &num, &match) &&
658
0
          match == strlen(entry->d_name)) {
659
0
        if (!found) {
660
0
          manifestfile = db_path_ + "/" + std::string(entry->d_name);
661
0
          found = true;
662
0
        } else {
663
0
          exec_state_ = LDBCommandExecuteResult::Failed(
664
0
              "Multiple MANIFEST files found; use --path to select one");
665
0
          return;
666
0
        }
667
0
      }
668
0
    }
669
0
  }
670
671
0
  if (verbose_) {
672
0
    printf("Processing Manifest file %s\n", manifestfile.c_str());
673
0
  }
674
675
0
  DumpManifestFile(manifestfile, verbose_, is_key_hex_);
676
677
0
  if (verbose_) {
678
0
    printf("Processing Manifest file %s done\n", manifestfile.c_str());
679
0
  }
680
0
}
681
682
// ----------------------------------------------------------------------------
683
684
0
void ListColumnFamiliesCommand::Help(string& ret) {
685
0
  ret.append("  ");
686
0
  ret.append(ListColumnFamiliesCommand::Name());
687
0
  ret.append(" full_path_to_db_directory ");
688
0
  ret.append("\n");
689
0
}
690
691
ListColumnFamiliesCommand::ListColumnFamiliesCommand(
692
    const vector<string>& params, const map<string, string>& options,
693
    const vector<string>& flags)
694
0
    : LDBCommand(options, flags, false, {}) {
695
696
0
  if (params.size() != 1) {
697
0
    exec_state_ = LDBCommandExecuteResult::Failed(
698
0
        "dbname must be specified for the list_column_families command");
699
0
  } else {
700
0
    dbname_ = params[0];
701
0
  }
702
0
}
703
704
0
void ListColumnFamiliesCommand::DoCommand() {
705
0
  vector<string> column_families;
706
0
  Status s = DB::ListColumnFamilies(DBOptions(), dbname_, &column_families);
707
0
  if (!s.ok()) {
708
0
    printf("Error in processing db %s %s\n", dbname_.c_str(),
709
0
           s.ToString().c_str());
710
0
  } else {
711
0
    printf("Column families in %s: \n{", dbname_.c_str());
712
0
    bool first = true;
713
0
    for (auto cf : column_families) {
714
0
      if (!first) {
715
0
        printf(", ");
716
0
      }
717
0
      first = false;
718
0
      printf("%s", cf.c_str());
719
0
    }
720
0
    printf("}\n");
721
0
  }
722
0
}
723
724
0
void CreateColumnFamilyCommand::Help(string& ret) {
725
0
  ret.append("  ");
726
0
  ret.append(CreateColumnFamilyCommand::Name());
727
0
  ret.append(" --db=<db_path> <new_column_family_name>");
728
0
  ret.append("\n");
729
0
}
730
731
CreateColumnFamilyCommand::CreateColumnFamilyCommand(
732
    const vector<string>& params, const map<string, string>& options,
733
    const vector<string>& flags)
734
0
    : LDBCommand(options, flags, true, {ARG_DB}) {
735
0
  if (params.size() != 1) {
736
0
    exec_state_ = LDBCommandExecuteResult::Failed(
737
0
        "new column family name must be specified");
738
0
  } else {
739
0
    new_cf_name_ = params[0];
740
0
  }
741
0
}
742
743
0
void CreateColumnFamilyCommand::DoCommand() {
744
0
  ColumnFamilyHandle* new_cf_handle;
745
0
  Status st = db_->CreateColumnFamily(options_, new_cf_name_, &new_cf_handle);
746
0
  if (st.ok()) {
747
0
    fprintf(stdout, "OK\n");
748
0
  } else {
749
0
    exec_state_ = LDBCommandExecuteResult::Failed(
750
0
        "Fail to create new column family: " + st.ToString());
751
0
  }
752
0
  delete new_cf_handle;
753
0
  CloseDB();
754
0
}
755
756
// ----------------------------------------------------------------------------
757
758
namespace {
759
760
0
string ReadableTime(int unixtime) {
761
0
  char time_buffer[80];
762
0
  time_t rawtime = unixtime;
763
0
  struct tm tInfo;
764
0
  struct tm* timeinfo = localtime_r(&rawtime, &tInfo);
765
0
  assert(timeinfo == &tInfo);
766
0
  strftime(time_buffer, 80, "%c", timeinfo);
767
0
  return string(time_buffer);
768
0
}
769
770
// This function only called when it's the sane case of >1 buckets in time-range
771
// Also called only when timekv falls between ttl_start and ttl_end provided
772
void IncBucketCounts(vector<uint64_t>* bucket_counts, int ttl_start,
773
0
      int time_range, int bucket_size, int timekv, int num_buckets) {
774
0
  assert(time_range > 0 && timekv >= ttl_start && bucket_size > 0 &&
775
0
    timekv < (ttl_start + time_range) && num_buckets > 1);
776
0
  int bucket = (timekv - ttl_start) / bucket_size;
777
0
  (*bucket_counts)[bucket]++;
778
0
}
779
780
void PrintBucketCounts(const vector<uint64_t>& bucket_counts, int ttl_start,
781
0
      int ttl_end, int bucket_size, int num_buckets) {
782
0
  int time_point = ttl_start;
783
0
  for(int i = 0; i < num_buckets - 1; i++, time_point += bucket_size) {
784
0
    fprintf(stdout, "Keys in range %s to %s : %" PRIu64 "\n",
785
0
            ReadableTime(time_point).c_str(),
786
0
            ReadableTime(time_point + bucket_size).c_str(),
787
0
            bucket_counts[i]);
788
0
  }
789
0
  fprintf(stdout, "Keys in range %s to %s : %" PRIu64 "\n",
790
0
          ReadableTime(time_point).c_str(),
791
0
          ReadableTime(ttl_end).c_str(),
792
0
          bucket_counts[num_buckets - 1]);
793
0
}
794
795
}  // namespace
796
797
const string InternalDumpCommand::ARG_COUNT_ONLY = "count_only";
798
const string InternalDumpCommand::ARG_COUNT_DELIM = "count_delim";
799
const string InternalDumpCommand::ARG_STATS = "stats";
800
const string InternalDumpCommand::ARG_INPUT_KEY_HEX = "input_key_hex";
801
802
InternalDumpCommand::InternalDumpCommand(const vector<string>& params,
803
                                         const map<string, string>& options,
804
                                         const vector<string>& flags)
805
    : LDBCommand(
806
          options, flags, true,
807
          BuildCmdLineOptions({ARG_HEX, ARG_KEY_HEX, ARG_VALUE_HEX, ARG_FROM,
808
                               ARG_TO, ARG_MAX_KEYS, ARG_COUNT_ONLY,
809
                               ARG_COUNT_DELIM, ARG_STATS, ARG_INPUT_KEY_HEX})),
810
      has_from_(false),
811
      has_to_(false),
812
      max_keys_(-1),
813
      delim_("."),
814
      count_only_(false),
815
      count_delim_(false),
816
      print_stats_(false),
817
0
      is_input_key_hex_(false) {
818
0
  has_from_ = ParseStringOption(options, ARG_FROM, &from_);
819
0
  has_to_ = ParseStringOption(options, ARG_TO, &to_);
820
821
0
  ParseIntOption(options, ARG_MAX_KEYS, max_keys_, exec_state_);
822
0
  map<string, string>::const_iterator itr = options.find(ARG_COUNT_DELIM);
823
0
  if (itr != options.end()) {
824
0
    delim_ = itr->second;
825
0
    count_delim_ = true;
826
    // fprintf(stdout,"delim = %c\n",delim_[0]);
827
0
  } else {
828
0
    count_delim_ = IsFlagPresent(flags, ARG_COUNT_DELIM);
829
0
    delim_ = ".";
830
0
  }
831
832
0
  print_stats_ = IsFlagPresent(flags, ARG_STATS);
833
0
  count_only_ = IsFlagPresent(flags, ARG_COUNT_ONLY);
834
0
  is_input_key_hex_ = IsFlagPresent(flags, ARG_INPUT_KEY_HEX);
835
836
0
  if (is_input_key_hex_) {
837
0
    if (has_from_) {
838
0
      from_ = HexToString(from_);
839
0
    }
840
0
    if (has_to_) {
841
0
      to_ = HexToString(to_);
842
0
    }
843
0
  }
844
0
}
845
846
0
void InternalDumpCommand::Help(string& ret) {
847
0
  ret.append("  ");
848
0
  ret.append(InternalDumpCommand::Name());
849
0
  ret.append(HelpRangeCmdArgs());
850
0
  ret.append(" [--" + ARG_INPUT_KEY_HEX + "]");
851
0
  ret.append(" [--" + ARG_MAX_KEYS + "=<N>]");
852
0
  ret.append(" [--" + ARG_COUNT_ONLY + "]");
853
0
  ret.append(" [--" + ARG_COUNT_DELIM + "=<char>]");
854
0
  ret.append(" [--" + ARG_STATS + "]");
855
0
  ret.append("\n");
856
0
}
857
858
0
void InternalDumpCommand::DoCommand() {
859
0
  if (!db_) {
860
0
    assert(GetExecuteState().IsFailed());
861
0
    return;
862
0
  }
863
864
0
  if (print_stats_) {
865
0
    string stats;
866
0
    if (db_->GetProperty(GetCfHandle(), "rocksdb.stats", &stats)) {
867
0
      fprintf(stdout, "%s\n", stats.c_str());
868
0
    }
869
0
  }
870
871
  // Cast as DBImpl to get internal iterator
872
0
  DBImpl* idb = dynamic_cast<DBImpl*>(db_);
873
0
  if (!idb) {
874
0
    exec_state_ = LDBCommandExecuteResult::Failed("DB is not DBImpl");
875
0
    return;
876
0
  }
877
0
  string rtype1, rtype2, row, val;
878
0
  rtype2 = "";
879
0
  uint64_t c = 0;
880
0
  uint64_t s1 = 0, s2 = 0;
881
  // Setup internal key iterator
882
0
  Arena arena;
883
0
  ScopedArenaIterator iter(idb->NewInternalIterator(&arena));
884
0
  Status st = iter->status();
885
0
  if (!st.ok()) {
886
0
    exec_state_ =
887
0
        LDBCommandExecuteResult::Failed("Iterator error:" + st.ToString());
888
0
  }
889
890
0
  if (has_from_) {
891
0
    InternalKey ikey = InternalKey::MaxPossibleForUserKey(from_);
892
0
    iter->Seek(ikey.Encode());
893
0
  } else {
894
0
    iter->SeekToFirst();
895
0
  }
896
897
0
  int64_t count = 0;
898
0
  for (; iter->Valid(); iter->Next()) {
899
0
    ParsedInternalKey ikey;
900
0
    if (!ParseInternalKey(iter->key(), &ikey)) {
901
0
      fprintf(stderr, "Internal Key [%s] parse error!\n",
902
0
              iter->key().ToString(true /* in hex*/).data());
903
      // TODO: add error counter
904
0
      continue;
905
0
    }
906
907
    // If end marker was specified, we stop before it
908
0
    if (has_to_ && options_.comparator->Compare(ikey.user_key, to_) >= 0) {
909
0
      break;
910
0
    }
911
912
0
    ++count;
913
0
    int k;
914
0
    if (count_delim_) {
915
0
      rtype1 = "";
916
0
      s1 = 0;
917
0
      row = iter->key().ToString();
918
0
      val = iter->value().ToString();
919
0
      for (k = 0; row[k] != '\x01' && row[k] != '\0'; k++)
920
0
        s1++;
921
0
      for (k = 0; val[k] != '\x01' && val[k] != '\0'; k++)
922
0
        s1++;
923
0
      for (int j = 0; row[j] != delim_[0] && row[j] != '\0' && row[j] != '\x01'; j++)
924
0
        rtype1 += row[j];
925
0
      if (rtype2.compare("") && rtype2.compare(rtype1) != 0) {
926
0
        fprintf(stdout, "%s => count:%" PRIu64 "\tsize:%" PRIu64 "\n", rtype2.c_str(), c, s2);
927
0
        c = 1;
928
0
        s2 = s1;
929
0
        rtype2 = rtype1;
930
0
      } else {
931
0
        c++;
932
0
        s2 += s1;
933
0
        rtype2 = rtype1;
934
0
    }
935
0
  }
936
937
0
    if (!count_only_ && !count_delim_) {
938
0
      string key = ikey.DebugString(is_key_hex_);
939
0
      string value = iter->value().ToString(is_value_hex_);
940
0
      std::cout << key << " => " << value << "\n";
941
0
    }
942
943
    // Terminate if maximum number of keys have been dumped
944
0
    if (max_keys_ > 0 && count >= max_keys_) break;
945
0
  }
946
0
  if(count_delim_) {
947
0
    fprintf(stdout, "%s => count:%" PRIu64 "\tsize:%" PRIu64 "\n", rtype2.c_str(), c, s2);
948
0
  } else {
949
0
    fprintf(stdout, "Internal keys in range: %" PRId64 "\n", count);
950
0
  }
951
0
}
952
953
954
const string DBDumperCommand::ARG_COUNT_ONLY = "count_only";
955
const string DBDumperCommand::ARG_COUNT_DELIM = "count_delim";
956
const string DBDumperCommand::ARG_STATS = "stats";
957
const string DBDumperCommand::ARG_TTL_BUCKET = "bucket";
958
959
DBDumperCommand::DBDumperCommand(const vector<string>& params,
960
                                 const map<string, string>& options,
961
                                 const vector<string>& flags)
962
    : LDBCommand(options, flags, true,
963
                 BuildCmdLineOptions(
964
                     {ARG_TTL, ARG_HEX, ARG_KEY_HEX, ARG_VALUE_HEX, ARG_FROM,
965
                      ARG_TO, ARG_MAX_KEYS, ARG_COUNT_ONLY, ARG_COUNT_DELIM,
966
                      ARG_STATS, ARG_TTL_START, ARG_TTL_END, ARG_TTL_BUCKET,
967
                      ARG_TIMESTAMP, ARG_PATH})),
968
      null_from_(true),
969
      null_to_(true),
970
      max_keys_(-1),
971
      count_only_(false),
972
      count_delim_(false),
973
0
      print_stats_(false) {
974
0
  map<string, string>::const_iterator itr = options.find(ARG_FROM);
975
0
  if (itr != options.end()) {
976
0
    null_from_ = false;
977
0
    from_ = itr->second;
978
0
  }
979
980
0
  itr = options.find(ARG_TO);
981
0
  if (itr != options.end()) {
982
0
    null_to_ = false;
983
0
    to_ = itr->second;
984
0
  }
985
986
0
  itr = options.find(ARG_MAX_KEYS);
987
0
  if (itr != options.end()) {
988
0
    try {
989
#if defined(CYGWIN)
990
      max_keys_ = strtol(itr->second.c_str(), 0, 10);
991
#else
992
0
      max_keys_ = stoi(itr->second);
993
0
#endif
994
0
    } catch(const std::invalid_argument&) {
995
0
      exec_state_ = LDBCommandExecuteResult::Failed(ARG_MAX_KEYS +
996
0
                                                    " has an invalid value");
997
0
    } catch(const std::out_of_range&) {
998
0
      exec_state_ = LDBCommandExecuteResult::Failed(
999
0
          ARG_MAX_KEYS + " has a value out-of-range");
1000
0
    }
1001
0
  }
1002
0
  itr = options.find(ARG_COUNT_DELIM);
1003
0
  if (itr != options.end()) {
1004
0
    delim_ = itr->second;
1005
0
    count_delim_ = true;
1006
0
  } else {
1007
0
    count_delim_ = IsFlagPresent(flags, ARG_COUNT_DELIM);
1008
0
    delim_ = ".";
1009
0
  }
1010
1011
0
  print_stats_ = IsFlagPresent(flags, ARG_STATS);
1012
0
  count_only_ = IsFlagPresent(flags, ARG_COUNT_ONLY);
1013
1014
0
  if (is_key_hex_) {
1015
0
    if (!null_from_) {
1016
0
      from_ = HexToString(from_);
1017
0
    }
1018
0
    if (!null_to_) {
1019
0
      to_ = HexToString(to_);
1020
0
    }
1021
0
  }
1022
1023
0
  itr = options.find(ARG_PATH);
1024
0
  if (itr != options.end()) {
1025
0
    path_ = itr->second;
1026
0
  }
1027
0
}
1028
1029
0
void DBDumperCommand::Help(string& ret) {
1030
0
  ret.append("  ");
1031
0
  ret.append(DBDumperCommand::Name());
1032
0
  ret.append(HelpRangeCmdArgs());
1033
0
  ret.append(" [--" + ARG_TTL + "]");
1034
0
  ret.append(" [--" + ARG_MAX_KEYS + "=<N>]");
1035
0
  ret.append(" [--" + ARG_TIMESTAMP + "]");
1036
0
  ret.append(" [--" + ARG_COUNT_ONLY + "]");
1037
0
  ret.append(" [--" + ARG_COUNT_DELIM + "=<char>]");
1038
0
  ret.append(" [--" + ARG_STATS + "]");
1039
0
  ret.append(" [--" + ARG_TTL_BUCKET + "=<N>]");
1040
0
  ret.append(" [--" + ARG_TTL_START + "=<N>:- is inclusive]");
1041
0
  ret.append(" [--" + ARG_TTL_END + "=<N>:- is exclusive]");
1042
0
  ret.append(" [--" + ARG_PATH + "=<path_to_a_file>]");
1043
0
  ret.append("\n");
1044
0
}
1045
1046
/**
1047
 * Handles two separate cases:
1048
 *
1049
 * 1) --db is specified - just dump the database.
1050
 *
1051
 * 2) --path is specified - determine based on file extension what dumping
1052
 *    function to call. Please note that we intentionally use the extension
1053
 *    and avoid probing the file contents under the assumption that renaming
1054
 *    the files is not a supported scenario.
1055
 *
1056
 */
1057
0
void DBDumperCommand::DoCommand() {
1058
0
  if (!db_) {
1059
0
    assert(!path_.empty());
1060
0
    string fileName = GetFileNameFromPath(path_);
1061
0
    uint64_t number;
1062
0
    FileType type;
1063
1064
0
    exec_state_ = LDBCommandExecuteResult::Succeed("");
1065
1066
0
    if (!ParseFileName(fileName, &number, &type)) {
1067
0
      exec_state_ =
1068
0
          LDBCommandExecuteResult::Failed("Can't parse file type: " + path_);
1069
0
      return;
1070
0
    }
1071
1072
0
    switch (type) {
1073
0
      case kLogFile:
1074
0
        DumpWalFile(path_, /* print_header_ */ true, /* print_values_ */ true,
1075
0
                    &exec_state_);
1076
0
        break;
1077
0
      case kTableFile:
1078
0
        DumpSstFile(path_, is_key_hex_, /* show_properties */ true);
1079
0
        break;
1080
0
      case kDescriptorFile:
1081
0
        DumpManifestFile(path_, /* verbose_ */ false, is_key_hex_);
1082
0
        break;
1083
0
      default:
1084
0
        exec_state_ = LDBCommandExecuteResult::Failed(
1085
0
            "File type not supported: " + path_);
1086
0
        break;
1087
0
    }
1088
1089
0
  } else {
1090
0
    DoDumpCommand();
1091
0
  }
1092
0
}
1093
1094
0
void DBDumperCommand::DoDumpCommand() {
1095
0
  assert(nullptr != db_);
1096
0
  assert(path_.empty());
1097
1098
  // Parse command line args
1099
0
  uint64_t count = 0;
1100
0
  if (print_stats_) {
1101
0
    string stats;
1102
0
    if (db_->GetProperty("rocksdb.stats", &stats)) {
1103
0
      fprintf(stdout, "%s\n", stats.c_str());
1104
0
    }
1105
0
  }
1106
1107
  // Setup key iterator
1108
0
  Iterator* iter = db_->NewIterator(ReadOptions(), GetCfHandle());
1109
0
  Status st = iter->status();
1110
0
  if (!st.ok()) {
1111
0
    exec_state_ =
1112
0
        LDBCommandExecuteResult::Failed("Iterator error." + st.ToString());
1113
0
  }
1114
1115
0
  if (!null_from_) {
1116
0
    iter->Seek(from_);
1117
0
  } else {
1118
0
    iter->SeekToFirst();
1119
0
  }
1120
1121
0
  int max_keys = max_keys_;
1122
0
  int ttl_start;
1123
0
  if (!ParseIntOption(option_map_, ARG_TTL_START, ttl_start, exec_state_)) {
1124
0
    ttl_start = DBWithTTLImpl::kMinTimestamp;  // TTL introduction time
1125
0
  }
1126
0
  int ttl_end;
1127
0
  if (!ParseIntOption(option_map_, ARG_TTL_END, ttl_end, exec_state_)) {
1128
0
    ttl_end = DBWithTTLImpl::kMaxTimestamp;  // Max time allowed by TTL feature
1129
0
  }
1130
0
  if (ttl_end < ttl_start) {
1131
0
    fprintf(stderr, "Error: End time can't be less than start time\n");
1132
0
    delete iter;
1133
0
    return;
1134
0
  }
1135
0
  int time_range = ttl_end - ttl_start;
1136
0
  int bucket_size;
1137
0
  if (!ParseIntOption(option_map_, ARG_TTL_BUCKET, bucket_size, exec_state_) ||
1138
0
      bucket_size <= 0) {
1139
0
    bucket_size = time_range; // Will have just 1 bucket by default
1140
0
  }
1141
  // Creating variables for row count of each type
1142
0
  string rtype1, rtype2, row, val;
1143
0
  rtype2 = "";
1144
0
  uint64_t c = 0;
1145
0
  uint64_t s1 = 0, s2 = 0;
1146
1147
  // At this point, bucket_size=0 => time_range=0
1148
0
  int num_buckets = (bucket_size >= time_range)
1149
0
                        ? 1
1150
0
                        : ((time_range + bucket_size - 1) / bucket_size);
1151
0
  vector<uint64_t> bucket_counts(num_buckets, 0);
1152
0
  if (is_db_ttl_ && !count_only_ && timestamp_ && !count_delim_) {
1153
0
    fprintf(stdout, "Dumping key-values from %s to %s\n",
1154
0
            ReadableTime(ttl_start).c_str(), ReadableTime(ttl_end).c_str());
1155
0
  }
1156
1157
0
  for (; iter->Valid(); iter->Next()) {
1158
0
    int rawtime = 0;
1159
    // If end marker was specified, we stop before it
1160
0
    if (!null_to_ && (iter->key().ToString() >= to_))
1161
0
      break;
1162
    // Terminate if maximum number of keys have been dumped
1163
0
    if (max_keys == 0)
1164
0
      break;
1165
0
    if (is_db_ttl_) {
1166
0
      TtlIterator* it_ttl = dynamic_cast<TtlIterator*>(iter);
1167
0
      assert(it_ttl);
1168
0
      rawtime = it_ttl->timestamp();
1169
0
      if (rawtime < ttl_start || rawtime >= ttl_end) {
1170
0
        continue;
1171
0
      }
1172
0
    }
1173
0
    if (max_keys > 0) {
1174
0
      --max_keys;
1175
0
    }
1176
0
    if (is_db_ttl_ && num_buckets > 1) {
1177
0
      IncBucketCounts(&bucket_counts, ttl_start, time_range, bucket_size,
1178
0
                      rawtime, num_buckets);
1179
0
    }
1180
0
    ++count;
1181
0
    if (count_delim_) {
1182
0
      rtype1 = "";
1183
0
      row = iter->key().ToString();
1184
0
      val = iter->value().ToString();
1185
0
      s1 = row.size()+val.size();
1186
0
      for (int j = 0; row[j] != delim_[0] && row[j] != '\0'; j++)
1187
0
        rtype1 += row[j];
1188
0
      if (rtype2.compare("") && rtype2.compare(rtype1) != 0) {
1189
0
        fprintf(stdout, "%s => count:%" PRIu64 "\tsize:%" PRIu64 "\n", rtype2.c_str(), c, s2);
1190
0
        c = 1;
1191
0
        s2 = s1;
1192
0
        rtype2 = rtype1;
1193
0
      } else {
1194
0
          c++;
1195
0
          s2 += s1;
1196
0
          rtype2 = rtype1;
1197
0
      }
1198
1199
0
    }
1200
1201
1202
1203
0
    if (!count_only_ && !count_delim_) {
1204
0
      if (is_db_ttl_ && timestamp_) {
1205
0
        fprintf(stdout, "%s ", ReadableTime(rawtime).c_str());
1206
0
      }
1207
0
      string str = PrintKeyValue(iter->key().ToString(),
1208
0
                                 iter->value().ToString(), is_key_hex_,
1209
0
                                 is_value_hex_);
1210
0
      fprintf(stdout, "%s\n", str.c_str());
1211
0
    }
1212
0
  }
1213
1214
0
  if (num_buckets > 1 && is_db_ttl_) {
1215
0
    PrintBucketCounts(bucket_counts, ttl_start, ttl_end, bucket_size,
1216
0
                      num_buckets);
1217
0
  } else if(count_delim_) {
1218
0
    fprintf(stdout, "%s => count:%" PRIu64 "\tsize:%" PRIu64 "\n", rtype2.c_str(), c, s2);
1219
0
  } else {
1220
0
    fprintf(stdout, "Keys in range: %" PRIu64 "\n", count);
1221
0
  }
1222
  // Clean up
1223
0
  delete iter;
1224
0
}
1225
1226
const string ReduceDBLevelsCommand::ARG_NEW_LEVELS = "new_levels";
1227
const string  ReduceDBLevelsCommand::ARG_PRINT_OLD_LEVELS = "print_old_levels";
1228
1229
ReduceDBLevelsCommand::ReduceDBLevelsCommand(const vector<string>& params,
1230
      const map<string, string>& options, const vector<string>& flags) :
1231
    LDBCommand(options, flags, false,
1232
               BuildCmdLineOptions({ARG_NEW_LEVELS, ARG_PRINT_OLD_LEVELS})),
1233
    old_levels_(1 << 7),
1234
    new_levels_(-1),
1235
8
    print_old_levels_(false) {
1236
1237
1238
8
  ParseIntOption(option_map_, ARG_NEW_LEVELS, new_levels_, exec_state_);
1239
8
  print_old_levels_ = IsFlagPresent(flags, ARG_PRINT_OLD_LEVELS);
1240
1241
8
  if(new_levels_ <= 0) {
1242
0
    exec_state_ = LDBCommandExecuteResult::Failed(
1243
0
        " Use --" + ARG_NEW_LEVELS + " to specify a new level number\n");
1244
0
  }
1245
8
}
1246
1247
vector<string> ReduceDBLevelsCommand::PrepareArgs(const string& db_path,
1248
8
    int new_levels, bool print_old_level) {
1249
8
  vector<string> ret;
1250
8
  ret.push_back("reduce_levels");
1251
8
  ret.push_back("--" + ARG_DB + "=" + db_path);
1252
8
  ret.push_back("--" + ARG_NEW_LEVELS + "=" + rocksdb::ToString(new_levels));
1253
8
  if(print_old_level) {
1254
0
    ret.push_back("--" + ARG_PRINT_OLD_LEVELS);
1255
0
  }
1256
8
  return ret;
1257
8
}
1258
1259
0
void ReduceDBLevelsCommand::Help(string& ret) {
1260
0
  ret.append("  ");
1261
0
  ret.append(ReduceDBLevelsCommand::Name());
1262
0
  ret.append(" --" + ARG_NEW_LEVELS + "=<New number of levels>");
1263
0
  ret.append(" [--" + ARG_PRINT_OLD_LEVELS + "]");
1264
0
  ret.append("\n");
1265
0
}
1266
1267
13
Options ReduceDBLevelsCommand::PrepareOptionsForOpenDB() {
1268
13
  Options opt = LDBCommand::PrepareOptionsForOpenDB();
1269
13
  opt.num_levels = old_levels_;
1270
13
  opt.max_bytes_for_level_multiplier_additional.resize(opt.num_levels, 1);
1271
  // Disable size compaction
1272
13
  opt.max_bytes_for_level_base = 1ULL << 50;
1273
13
  opt.max_bytes_for_level_multiplier = 1;
1274
13
  return opt;
1275
13
}
1276
1277
Status ReduceDBLevelsCommand::GetOldNumOfLevels(Options& opt,
1278
8
    int* levels) {
1279
8
  EnvOptions soptions;
1280
8
  std::shared_ptr<Cache> tc(
1281
8
      NewLRUCache(opt.max_open_files - 10, opt.table_cache_numshardbits));
1282
8
  const InternalKeyComparator cmp(opt.comparator);
1283
8
  WriteController wc(opt.delayed_write_rate);
1284
8
  WriteBuffer wb(opt.db_write_buffer_size);
1285
8
  VersionSet versions(db_path_, &opt, soptions, tc.get(), &wb, &wc);
1286
8
  std::vector<ColumnFamilyDescriptor> dummy;
1287
8
  ColumnFamilyDescriptor dummy_descriptor(kDefaultColumnFamilyName,
1288
8
                                          ColumnFamilyOptions(opt));
1289
8
  dummy.push_back(dummy_descriptor);
1290
  // We rely the VersionSet::Recover to tell us the internal data structures
1291
  // in the db. And the Recover() should never do any change
1292
  // (like LogAndApply) to the manifest file.
1293
8
  Status st = versions.Recover(dummy);
1294
8
  if (!st.ok()) {
1295
0
    return st;
1296
0
  }
1297
8
  int max = -1;
1298
8
  auto default_cfd = versions.GetColumnFamilySet()->GetDefault();
1299
1.03k
  for (int i = 0; i < default_cfd->NumberLevels(); i++) {
1300
1.02k
    if (default_cfd->current()->storage_info()->NumLevelFiles(i)) {
1301
11
      max = i;
1302
11
    }
1303
1.02k
  }
1304
1305
8
  *levels = max + 1;
1306
8
  return st;
1307
8
}
1308
1309
8
void ReduceDBLevelsCommand::DoCommand() {
1310
8
  if (new_levels_ <= 1) {
1311
0
    exec_state_ =
1312
0
        LDBCommandExecuteResult::Failed("Invalid number of levels.\n");
1313
0
    return;
1314
0
  }
1315
1316
8
  Status st;
1317
8
  Options opt = PrepareOptionsForOpenDB();
1318
8
  int old_level_num = -1;
1319
8
  st = GetOldNumOfLevels(opt, &old_level_num);
1320
8
  if (!st.ok()) {
1321
0
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
1322
0
    return;
1323
0
  }
1324
1325
8
  if (print_old_levels_) {
1326
0
    fprintf(stdout, "The old number of levels in use is %d\n", old_level_num);
1327
0
  }
1328
1329
8
  if (old_level_num <= new_levels_) {
1330
3
    return;
1331
3
  }
1332
1333
5
  old_levels_ = old_level_num;
1334
1335
5
  OpenDB();
1336
5
  if (!db_) {
1337
0
    return;
1338
0
  }
1339
  // Compact the whole DB to put all files to the highest level.
1340
5
  fprintf(stdout, "Compacting the db...\n");
1341
5
  CHECK_OK(db_->CompactRange(CompactRangeOptions(), GetCfHandle(), nullptr, nullptr));
1342
5
  CloseDB();
1343
1344
5
  EnvOptions soptions;
1345
5
  st = VersionSet::ReduceNumberOfLevels(db_path_, &opt, soptions, new_levels_);
1346
5
  if (!st.ok()) {
1347
0
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
1348
0
    return;
1349
0
  }
1350
5
}
1351
1352
const string ChangeCompactionStyleCommand::ARG_OLD_COMPACTION_STYLE =
1353
  "old_compaction_style";
1354
const string ChangeCompactionStyleCommand::ARG_NEW_COMPACTION_STYLE =
1355
  "new_compaction_style";
1356
1357
ChangeCompactionStyleCommand::ChangeCompactionStyleCommand(
1358
      const vector<string>& params, const map<string, string>& options,
1359
      const vector<string>& flags) :
1360
    LDBCommand(options, flags, false,
1361
               BuildCmdLineOptions({ARG_OLD_COMPACTION_STYLE,
1362
                                    ARG_NEW_COMPACTION_STYLE})),
1363
    old_compaction_style_(-1),
1364
0
    new_compaction_style_(-1) {
1365
1366
0
  ParseIntOption(option_map_, ARG_OLD_COMPACTION_STYLE, old_compaction_style_,
1367
0
    exec_state_);
1368
0
  if (old_compaction_style_ != kCompactionStyleLevel &&
1369
0
     old_compaction_style_ != kCompactionStyleUniversal) {
1370
0
    exec_state_ = LDBCommandExecuteResult::Failed(
1371
0
        "Use --" + ARG_OLD_COMPACTION_STYLE + " to specify old compaction " +
1372
0
        "style. Check ldb help for proper compaction style value.\n");
1373
0
    return;
1374
0
  }
1375
1376
0
  ParseIntOption(option_map_, ARG_NEW_COMPACTION_STYLE, new_compaction_style_,
1377
0
    exec_state_);
1378
0
  if (new_compaction_style_ != kCompactionStyleLevel &&
1379
0
     new_compaction_style_ != kCompactionStyleUniversal) {
1380
0
    exec_state_ = LDBCommandExecuteResult::Failed(
1381
0
        "Use --" + ARG_NEW_COMPACTION_STYLE + " to specify new compaction " +
1382
0
        "style. Check ldb help for proper compaction style value.\n");
1383
0
    return;
1384
0
  }
1385
1386
0
  if (new_compaction_style_ == old_compaction_style_) {
1387
0
    exec_state_ = LDBCommandExecuteResult::Failed(
1388
0
        "Old compaction style is the same as new compaction style. "
1389
0
        "Nothing to do.\n");
1390
0
    return;
1391
0
  }
1392
1393
0
  if (old_compaction_style_ == kCompactionStyleUniversal &&
1394
0
      new_compaction_style_ == kCompactionStyleLevel) {
1395
0
    exec_state_ = LDBCommandExecuteResult::Failed(
1396
0
        "Convert from universal compaction to level compaction. "
1397
0
        "Nothing to do.\n");
1398
0
    return;
1399
0
  }
1400
0
}
1401
1402
0
void ChangeCompactionStyleCommand::Help(string& ret) {
1403
0
  ret.append("  ");
1404
0
  ret.append(ChangeCompactionStyleCommand::Name());
1405
0
  ret.append(" --" + ARG_OLD_COMPACTION_STYLE + "=<Old compaction style: 0 " +
1406
0
             "for level compaction, 1 for universal compaction>");
1407
0
  ret.append(" --" + ARG_NEW_COMPACTION_STYLE + "=<New compaction style: 0 " +
1408
0
             "for level compaction, 1 for universal compaction>");
1409
0
  ret.append("\n");
1410
0
}
1411
1412
0
Options ChangeCompactionStyleCommand::PrepareOptionsForOpenDB() {
1413
0
  Options opt = LDBCommand::PrepareOptionsForOpenDB();
1414
1415
0
  if (old_compaction_style_ == kCompactionStyleLevel &&
1416
0
      new_compaction_style_ == kCompactionStyleUniversal) {
1417
    // In order to convert from level compaction to universal compaction, we
1418
    // need to compact all data into a single file and move it to level 0.
1419
0
    opt.disable_auto_compactions = true;
1420
0
    opt.target_file_size_base = INT_MAX;
1421
0
    opt.target_file_size_multiplier = 1;
1422
0
    opt.max_bytes_for_level_base = INT_MAX;
1423
0
    opt.max_bytes_for_level_multiplier = 1;
1424
0
  }
1425
1426
0
  return opt;
1427
0
}
1428
1429
0
void ChangeCompactionStyleCommand::DoCommand() {
1430
  // print db stats before we have made any change
1431
0
  std::string property;
1432
0
  std::string files_per_level;
1433
0
  for (int i = 0; i < db_->NumberLevels(GetCfHandle()); i++) {
1434
0
    db_->GetProperty(GetCfHandle(),
1435
0
                     "rocksdb.num-files-at-level" + NumberToString(i),
1436
0
                     &property);
1437
1438
    // format print string
1439
0
    char buf[100];
1440
0
    snprintf(buf, sizeof(buf), "%s%s", (i ? "," : ""), property.c_str());
1441
0
    files_per_level += buf;
1442
0
  }
1443
0
  fprintf(stdout, "files per level before compaction: %s\n",
1444
0
          files_per_level.c_str());
1445
1446
  // manual compact into a single file and move the file to level 0
1447
0
  CompactRangeOptions compact_options;
1448
0
  compact_options.change_level = true;
1449
0
  compact_options.target_level = 0;
1450
0
  CHECK_OK(db_->CompactRange(compact_options, GetCfHandle(), nullptr, nullptr));
1451
1452
  // verify compaction result
1453
0
  files_per_level = "";
1454
0
  int num_files = 0;
1455
0
  for (int i = 0; i < db_->NumberLevels(); i++) {
1456
0
    db_->GetProperty(GetCfHandle(),
1457
0
                     "rocksdb.num-files-at-level" + NumberToString(i),
1458
0
                     &property);
1459
1460
    // format print string
1461
0
    char buf[100];
1462
0
    snprintf(buf, sizeof(buf), "%s%s", (i ? "," : ""), property.c_str());
1463
0
    files_per_level += buf;
1464
1465
0
    num_files = atoi(property.c_str());
1466
1467
    // level 0 should have only 1 file
1468
0
    if (i == 0 && num_files != 1) {
1469
0
      exec_state_ = LDBCommandExecuteResult::Failed(
1470
0
          "Number of db files at "
1471
0
          "level 0 after compaction is " +
1472
0
          ToString(num_files) + ", not 1.\n");
1473
0
      return;
1474
0
    }
1475
    // other levels should have no file
1476
0
    if (i > 0 && num_files != 0) {
1477
0
      exec_state_ = LDBCommandExecuteResult::Failed(
1478
0
          "Number of db files at "
1479
0
          "level " +
1480
0
          ToString(i) + " after compaction is " + ToString(num_files) +
1481
0
          ", not 0.\n");
1482
0
      return;
1483
0
    }
1484
0
  }
1485
1486
0
  fprintf(stdout, "files per level after compaction: %s\n",
1487
0
          files_per_level.c_str());
1488
0
}
1489
1490
// ----------------------------------------------------------------------------
1491
1492
namespace {
1493
1494
struct StdErrReporter : public log::Reader::Reporter {
1495
0
  void Corruption(size_t bytes, const Status& s) override {
1496
0
    std::cerr << "Corruption detected in log file " << s.ToString() << "\n";
1497
0
  }
1498
};
1499
1500
class InMemoryHandler : public WriteBatch::Handler {
1501
 public:
1502
0
  InMemoryHandler(std::stringstream& row, bool print_values) : Handler(), row_(row) {
1503
0
    print_values_ = print_values;
1504
0
  }
1505
1506
0
  void commonPutMerge(const Slice& key, const Slice& value) {
1507
0
    string k = LDBCommand::StringToHex(key.ToString());
1508
0
    if (print_values_) {
1509
0
      string v = LDBCommand::StringToHex(value.ToString());
1510
0
      row_ << k << " : ";
1511
0
      row_ << v << " ";
1512
0
    } else {
1513
0
      row_ << k << " ";
1514
0
    }
1515
0
  }
1516
1517
0
  void Put(const Slice& key, const Slice& value) override {
1518
0
    row_ << "PUT : ";
1519
0
    commonPutMerge(key, value);
1520
0
  }
1521
1522
0
  void Merge(const Slice& key, const Slice& value) override {
1523
0
    row_ << "MERGE : ";
1524
0
    commonPutMerge(key, value);
1525
0
  }
1526
1527
0
  void Delete(const Slice& key) override {
1528
0
    row_ << "DELETE : ";
1529
0
    row_ << LDBCommand::StringToHex(key.ToBuffer()) << " ";
1530
0
  }
1531
1532
0
  Status Frontiers(const UserFrontiers& range) override {
1533
0
    row_ << " MARGIN_RANGE : " << range.ToString() << " ";
1534
0
    return Status::OK();
1535
0
  }
1536
1537
0
  virtual ~InMemoryHandler() {}
1538
1539
 private:
1540
  std::stringstream & row_;
1541
  bool print_values_;
1542
};
1543
1544
void DumpWalFile(std::string wal_file, bool print_header, bool print_values,
1545
0
                 LDBCommandExecuteResult* exec_state) {
1546
0
  Env* env_ = Env::Default();
1547
0
  EnvOptions soptions;
1548
0
  unique_ptr<SequentialFileReader> wal_file_reader;
1549
1550
0
  Status status;
1551
0
  {
1552
0
    unique_ptr<SequentialFile> file;
1553
0
    status = env_->NewSequentialFile(wal_file, &file, soptions);
1554
0
    if (status.ok()) {
1555
0
      wal_file_reader.reset(new SequentialFileReader(std::move(file)));
1556
0
    }
1557
0
  }
1558
0
  if (!status.ok()) {
1559
0
    if (exec_state) {
1560
0
      *exec_state = LDBCommandExecuteResult::Failed("Failed to open WAL file " +
1561
0
                                                    status.ToString());
1562
0
    } else {
1563
0
      std::cerr << "Error: Failed to open WAL file " << status.ToString()
1564
0
                << std::endl;
1565
0
    }
1566
0
  } else {
1567
0
    StdErrReporter reporter;
1568
0
    uint64_t log_number;
1569
0
    FileType type;
1570
1571
    // we need the log number, but ParseFilename expects dbname/NNN.log.
1572
0
    string sanitized = wal_file;
1573
0
    size_t lastslash = sanitized.rfind('/');
1574
0
    if (lastslash != std::string::npos)
1575
0
      sanitized = sanitized.substr(lastslash + 1);
1576
0
    if (!ParseFileName(sanitized, &log_number, &type)) {
1577
      // bogus input, carry on as best we can
1578
0
      log_number = 0;
1579
0
    }
1580
0
    DBOptions db_options;
1581
0
    log::Reader reader(db_options.info_log, move(wal_file_reader), &reporter,
1582
0
                       true, 0, log_number);
1583
0
    string scratch;
1584
0
    WriteBatch batch;
1585
0
    Slice record;
1586
0
    std::stringstream row;
1587
0
    if (print_header) {
1588
0
      std::cout << "Sequence,Count,ByteSize,Physical Offset,Key(s)";
1589
0
      if (print_values) {
1590
0
        std::cout << " : value ";
1591
0
      }
1592
0
      std::cout << "\n";
1593
0
    }
1594
0
    while (reader.ReadRecord(&record, &scratch)) {
1595
0
      row.str("");
1596
0
      if (record.size() < 12) {
1597
0
        reporter.Corruption(record.size(),
1598
0
                            STATUS(Corruption, "log record too small"));
1599
0
      } else {
1600
0
        WriteBatchInternal::SetContents(&batch, record);
1601
0
        row << WriteBatchInternal::Sequence(&batch) << ",";
1602
0
        row << WriteBatchInternal::Count(&batch) << ",";
1603
0
        row << WriteBatchInternal::ByteSize(&batch) << ",";
1604
0
        row << reader.LastRecordOffset() << ",";
1605
0
        InMemoryHandler handler(row, print_values);
1606
0
        CHECK_OK(batch.Iterate(&handler));
1607
0
        row << "\n";
1608
0
      }
1609
0
      std::cout << row.str();
1610
0
    }
1611
0
  }
1612
0
}
1613
1614
}  // namespace
1615
1616
const string WALDumperCommand::ARG_WAL_FILE = "walfile";
1617
const string WALDumperCommand::ARG_PRINT_VALUE = "print_value";
1618
const string WALDumperCommand::ARG_PRINT_HEADER = "header";
1619
1620
WALDumperCommand::WALDumperCommand(const vector<string>& params,
1621
      const map<string, string>& options, const vector<string>& flags) :
1622
    LDBCommand(options, flags, true,
1623
               BuildCmdLineOptions(
1624
                {ARG_WAL_FILE, ARG_PRINT_HEADER, ARG_PRINT_VALUE})),
1625
0
    print_header_(false), print_values_(false) {
1626
1627
0
  wal_file_.clear();
1628
1629
0
  map<string, string>::const_iterator itr = options.find(ARG_WAL_FILE);
1630
0
  if (itr != options.end()) {
1631
0
    wal_file_ = itr->second;
1632
0
  }
1633
1634
1635
0
  print_header_ = IsFlagPresent(flags, ARG_PRINT_HEADER);
1636
0
  print_values_ = IsFlagPresent(flags, ARG_PRINT_VALUE);
1637
0
  if (wal_file_.empty()) {
1638
0
    exec_state_ = LDBCommandExecuteResult::Failed("Argument " + ARG_WAL_FILE +
1639
0
                                                  " must be specified.");
1640
0
  }
1641
0
}
1642
1643
0
void WALDumperCommand::Help(string& ret) {
1644
0
  ret.append("  ");
1645
0
  ret.append(WALDumperCommand::Name());
1646
0
  ret.append(" --" + ARG_WAL_FILE + "=<write_ahead_log_file_path>");
1647
0
  ret.append(" [--" + ARG_PRINT_HEADER + "] ");
1648
0
  ret.append(" [--" + ARG_PRINT_VALUE + "] ");
1649
0
  ret.append("\n");
1650
0
}
1651
1652
0
void WALDumperCommand::DoCommand() {
1653
0
  DumpWalFile(wal_file_, print_header_, print_values_, &exec_state_);
1654
0
}
1655
1656
// ----------------------------------------------------------------------------
1657
1658
GetCommand::GetCommand(const vector<string>& params,
1659
      const map<string, string>& options, const vector<string>& flags) :
1660
  LDBCommand(options, flags, true, BuildCmdLineOptions({ARG_TTL, ARG_HEX,
1661
                                                        ARG_KEY_HEX,
1662
0
                                                        ARG_VALUE_HEX})) {
1663
1664
0
  if (params.size() != 1) {
1665
0
    exec_state_ = LDBCommandExecuteResult::Failed(
1666
0
        "<key> must be specified for the get command");
1667
0
  } else {
1668
0
    key_ = params.at(0);
1669
0
  }
1670
1671
0
  if (is_key_hex_) {
1672
0
    key_ = HexToString(key_);
1673
0
  }
1674
0
}
1675
1676
0
void GetCommand::Help(string& ret) {
1677
0
  ret.append("  ");
1678
0
  ret.append(GetCommand::Name());
1679
0
  ret.append(" <key>");
1680
0
  ret.append(" [--" + ARG_TTL + "]");
1681
0
  ret.append("\n");
1682
0
}
1683
1684
0
void GetCommand::DoCommand() {
1685
0
  if (!db_) {
1686
0
    assert(GetExecuteState().IsFailed());
1687
0
    return;
1688
0
  }
1689
0
  string value;
1690
0
  Status st = db_->Get(ReadOptions(), GetCfHandle(), key_, &value);
1691
0
  if (st.ok()) {
1692
0
    fprintf(stdout, "%s\n",
1693
0
              (is_value_hex_ ? StringToHex(value) : value).c_str());
1694
0
  } else {
1695
0
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
1696
0
  }
1697
0
}
1698
1699
// ----------------------------------------------------------------------------
1700
1701
ApproxSizeCommand::ApproxSizeCommand(const vector<string>& params,
1702
      const map<string, string>& options, const vector<string>& flags) :
1703
  LDBCommand(options, flags, true,
1704
             BuildCmdLineOptions({ARG_HEX, ARG_KEY_HEX, ARG_VALUE_HEX,
1705
0
                                  ARG_FROM, ARG_TO})) {
1706
1707
0
  if (options.find(ARG_FROM) != options.end()) {
1708
0
    start_key_ = options.find(ARG_FROM)->second;
1709
0
  } else {
1710
0
    exec_state_ = LDBCommandExecuteResult::Failed(
1711
0
        ARG_FROM + " must be specified for approxsize command");
1712
0
    return;
1713
0
  }
1714
1715
0
  if (options.find(ARG_TO) != options.end()) {
1716
0
    end_key_ = options.find(ARG_TO)->second;
1717
0
  } else {
1718
0
    exec_state_ = LDBCommandExecuteResult::Failed(
1719
0
        ARG_TO + " must be specified for approxsize command");
1720
0
    return;
1721
0
  }
1722
1723
0
  if (is_key_hex_) {
1724
0
    start_key_ = HexToString(start_key_);
1725
0
    end_key_ = HexToString(end_key_);
1726
0
  }
1727
0
}
1728
1729
0
void ApproxSizeCommand::Help(string& ret) {
1730
0
  ret.append("  ");
1731
0
  ret.append(ApproxSizeCommand::Name());
1732
0
  ret.append(HelpRangeCmdArgs());
1733
0
  ret.append("\n");
1734
0
}
1735
1736
0
void ApproxSizeCommand::DoCommand() {
1737
0
  if (!db_) {
1738
0
    assert(GetExecuteState().IsFailed());
1739
0
    return;
1740
0
  }
1741
0
  Range ranges[1];
1742
0
  ranges[0] = Range(start_key_, end_key_);
1743
0
  uint64_t sizes[1];
1744
0
  db_->GetApproximateSizes(GetCfHandle(), ranges, 1, sizes);
1745
0
  fprintf(stdout, "%" PRIu64 "\n", sizes[0]);
1746
  /* Weird that GetApproximateSizes() returns void, although documentation
1747
   * says that it returns a Status object.
1748
  if (!st.ok()) {
1749
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
1750
  }
1751
  */
1752
0
}
1753
1754
// ----------------------------------------------------------------------------
1755
1756
BatchPutCommand::BatchPutCommand(const vector<string>& params,
1757
      const map<string, string>& options, const vector<string>& flags) :
1758
  LDBCommand(options, flags, false,
1759
             BuildCmdLineOptions({ARG_TTL, ARG_HEX, ARG_KEY_HEX, ARG_VALUE_HEX,
1760
0
                                  ARG_CREATE_IF_MISSING})) {
1761
1762
0
  if (params.size() < 2) {
1763
0
    exec_state_ = LDBCommandExecuteResult::Failed(
1764
0
        "At least one <key> <value> pair must be specified batchput.");
1765
0
  } else if (params.size() % 2 != 0) {
1766
0
    exec_state_ = LDBCommandExecuteResult::Failed(
1767
0
        "Equal number of <key>s and <value>s must be specified for batchput.");
1768
0
  } else {
1769
0
    for (size_t i = 0; i < params.size(); i += 2) {
1770
0
      string key = params.at(i);
1771
0
      string value = params.at(i+1);
1772
0
      key_values_.emplace_back(is_key_hex_ ? HexToString(key) : key,
1773
0
                               is_value_hex_ ? HexToString(value) : value);
1774
0
    }
1775
0
  }
1776
0
}
1777
1778
0
void BatchPutCommand::Help(string& ret) {
1779
0
  ret.append("  ");
1780
0
  ret.append(BatchPutCommand::Name());
1781
0
  ret.append(" <key> <value> [<key> <value>] [..]");
1782
0
  ret.append(" [--" + ARG_TTL + "]");
1783
0
  ret.append("\n");
1784
0
}
1785
1786
0
void BatchPutCommand::DoCommand() {
1787
0
  if (!db_) {
1788
0
    assert(GetExecuteState().IsFailed());
1789
0
    return;
1790
0
  }
1791
0
  WriteBatch batch;
1792
1793
0
  for (auto itr = key_values_.begin(); itr != key_values_.end(); ++itr) {
1794
0
    batch.Put(GetCfHandle(), itr->first, itr->second);
1795
0
  }
1796
0
  Status st = db_->Write(WriteOptions(), &batch);
1797
0
  if (st.ok()) {
1798
0
    fprintf(stdout, "OK\n");
1799
0
  } else {
1800
0
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
1801
0
  }
1802
0
}
1803
1804
0
Options BatchPutCommand::PrepareOptionsForOpenDB() {
1805
0
  Options opt = LDBCommand::PrepareOptionsForOpenDB();
1806
0
  opt.create_if_missing = IsFlagPresent(flags_, ARG_CREATE_IF_MISSING);
1807
0
  return opt;
1808
0
}
1809
1810
// ----------------------------------------------------------------------------
1811
1812
ScanCommand::ScanCommand(const vector<string>& params,
1813
                         const map<string, string>& options,
1814
                         const vector<string>& flags)
1815
    : LDBCommand(options, flags, true,
1816
                 BuildCmdLineOptions(
1817
                     {ARG_TTL,      ARG_NO_VALUE,  ARG_HEX,    ARG_KEY_HEX,
1818
                      ARG_TO,       ARG_VALUE_HEX, ARG_FROM,   ARG_TIMESTAMP,
1819
                      ARG_MAX_KEYS, ARG_TTL_START, ARG_TTL_END, ARG_ONLY_VERIFY_CHECKSUMS})),
1820
      start_key_specified_(false),
1821
      end_key_specified_(false),
1822
      max_keys_scanned_(-1),
1823
2
      no_value_(false) {
1824
1825
2
  map<string, string>::const_iterator itr = options.find(ARG_FROM);
1826
2
  if (itr != options.end()) {
1827
0
    start_key_ = itr->second;
1828
0
    if (is_key_hex_) {
1829
0
      start_key_ = HexToString(start_key_);
1830
0
    }
1831
0
    start_key_specified_ = true;
1832
0
  }
1833
2
  itr = options.find(ARG_TO);
1834
2
  if (itr != options.end()) {
1835
0
    end_key_ = itr->second;
1836
0
    if (is_key_hex_) {
1837
0
      end_key_ = HexToString(end_key_);
1838
0
    }
1839
0
    end_key_specified_ = true;
1840
0
  }
1841
1842
2
  vector<string>::const_iterator vitr =
1843
2
      std::find(flags.begin(), flags.end(), ARG_NO_VALUE);
1844
2
  if (vitr != flags.end()) {
1845
0
    no_value_ = true;
1846
0
  }
1847
1848
2
  vitr =  std::find(flags.begin(), flags.end(), ARG_ONLY_VERIFY_CHECKSUMS);
1849
2
  if (vitr != flags.end()) {
1850
2
    LOG(INFO) << "Only verify checksums, don't print entries.";
1851
2
    only_verify_checksums_ = true;
1852
2
  }
1853
1854
2
  itr = options.find(ARG_MAX_KEYS);
1855
2
  if (itr != options.end()) {
1856
0
    try {
1857
#if defined(CYGWIN)
1858
      max_keys_scanned_ = strtol(itr->second.c_str(), 0, 10);
1859
#else
1860
0
      max_keys_scanned_ = stoi(itr->second);
1861
0
#endif
1862
0
    } catch(const std::invalid_argument&) {
1863
0
      exec_state_ = LDBCommandExecuteResult::Failed(ARG_MAX_KEYS +
1864
0
                                                    " has an invalid value");
1865
0
    } catch(const std::out_of_range&) {
1866
0
      exec_state_ = LDBCommandExecuteResult::Failed(
1867
0
          ARG_MAX_KEYS + " has a value out-of-range");
1868
0
    }
1869
0
  }
1870
2
}
1871
1872
0
void ScanCommand::Help(string& ret) {
1873
0
  ret.append("  ");
1874
0
  ret.append(ScanCommand::Name());
1875
0
  ret.append(HelpRangeCmdArgs());
1876
0
  ret.append(" [--" + ARG_TTL + "]");
1877
0
  ret.append(" [--" + ARG_TIMESTAMP + "]");
1878
0
  ret.append(" [--" + ARG_MAX_KEYS + "=<N>q] ");
1879
0
  ret.append(" [--" + ARG_TTL_START + "=<N>:- is inclusive]");
1880
0
  ret.append(" [--" + ARG_TTL_END + "=<N>:- is exclusive]");
1881
0
  ret.append(" [--" + ARG_NO_VALUE + "]");
1882
0
  ret.append(" [--" + ARG_ONLY_VERIFY_CHECKSUMS + "]");
1883
0
  ret.append("\n");
1884
0
}
1885
1886
2
void ScanCommand::DoCommand() {
1887
2
  if (!db_) {
1888
0
    assert(GetExecuteState().IsFailed());
1889
0
    return;
1890
0
  }
1891
1892
2
  int num_keys_scanned = 0;
1893
2
  Iterator* it = db_->NewIterator(ReadOptions(), GetCfHandle());
1894
2
  if (start_key_specified_) {
1895
0
    it->Seek(start_key_);
1896
2
  } else {
1897
2
    it->SeekToFirst();
1898
2
  }
1899
2
  int ttl_start;
1900
2
  if (!ParseIntOption(option_map_, ARG_TTL_START, ttl_start, exec_state_)) {
1901
2
    ttl_start = DBWithTTLImpl::kMinTimestamp;  // TTL introduction time
1902
2
  }
1903
2
  int ttl_end;
1904
2
  if (!ParseIntOption(option_map_, ARG_TTL_END, ttl_end, exec_state_)) {
1905
2
    ttl_end = DBWithTTLImpl::kMaxTimestamp;  // Max time allowed by TTL feature
1906
2
  }
1907
2
  if (ttl_end < ttl_start) {
1908
0
    fprintf(stderr, "Error: End time can't be less than start time\n");
1909
0
    delete it;
1910
0
    return;
1911
0
  }
1912
2
  if (is_db_ttl_ && timestamp_) {
1913
0
    fprintf(stdout, "Scanning key-values from %s to %s\n",
1914
0
            ReadableTime(ttl_start).c_str(), ReadableTime(ttl_end).c_str());
1915
0
  }
1916
2
  for ( ;
1917
6
        it->Valid() && (!end_key_specified_ || it->key().ToString() < end_key_);
1918
4
        it->Next()) {
1919
4
    if (is_db_ttl_) {
1920
0
      TtlIterator* it_ttl = dynamic_cast<TtlIterator*>(it);
1921
0
      assert(it_ttl);
1922
0
      int rawtime = it_ttl->timestamp();
1923
0
      if (rawtime < ttl_start || rawtime >= ttl_end) {
1924
0
        continue;
1925
0
      }
1926
0
      if (timestamp_ && !only_verify_checksums_) {
1927
0
        fprintf(stdout, "%s ", ReadableTime(rawtime).c_str());
1928
0
      }
1929
0
    }
1930
1931
4
    Slice key_slice = it->key();
1932
1933
4
    std::string formatted_key;
1934
4
    if (is_key_hex_) {
1935
0
      formatted_key = "0x" + key_slice.ToString(true /* hex */);
1936
0
      key_slice = formatted_key;
1937
4
    } else if (ldb_options_.key_formatter) {
1938
0
      formatted_key = ldb_options_.key_formatter->Format(key_slice);
1939
0
      key_slice = formatted_key;
1940
0
    }
1941
1942
4
    if (no_value_ && !only_verify_checksums_) {
1943
0
      fprintf(stdout, "%.*s\n", static_cast<int>(key_slice.size()),
1944
0
              key_slice.data());
1945
4
    } else {
1946
4
      Slice val_slice = it->value();
1947
4
      std::string formatted_value;
1948
4
      if (is_value_hex_) {
1949
0
        formatted_value = "0x" + val_slice.ToString(true /* hex */);
1950
0
        val_slice = formatted_value;
1951
0
      }
1952
4
      if (!only_verify_checksums_) {
1953
0
        fprintf(stdout, "%.*s : %.*s\n", static_cast<int>(key_slice.size()),
1954
0
                key_slice.data(), static_cast<int>(val_slice.size()),
1955
0
                val_slice.data());
1956
0
      }
1957
4
    }
1958
1959
4
    num_keys_scanned++;
1960
4
    if (max_keys_scanned_ >= 0 && num_keys_scanned >= max_keys_scanned_) {
1961
0
      break;
1962
0
    }
1963
4
  }
1964
2
  if (!it->status().ok()) {  // Check for any errors found during the scan
1965
0
    exec_state_ = LDBCommandExecuteResult::Failed(it->status().ToString());
1966
0
  }
1967
2
  delete it;
1968
2
}
1969
1970
// ----------------------------------------------------------------------------
1971
1972
DeleteCommand::DeleteCommand(const vector<string>& params,
1973
      const map<string, string>& options, const vector<string>& flags) :
1974
  LDBCommand(options, flags, false,
1975
0
             BuildCmdLineOptions({ARG_HEX, ARG_KEY_HEX, ARG_VALUE_HEX})) {
1976
1977
0
  if (params.size() != 1) {
1978
0
    exec_state_ = LDBCommandExecuteResult::Failed(
1979
0
        "KEY must be specified for the delete command");
1980
0
  } else {
1981
0
    key_ = params.at(0);
1982
0
    if (is_key_hex_) {
1983
0
      key_ = HexToString(key_);
1984
0
    }
1985
0
  }
1986
0
}
1987
1988
0
void DeleteCommand::Help(string& ret) {
1989
0
  ret.append("  ");
1990
0
  ret.append(DeleteCommand::Name() + " <key>");
1991
0
  ret.append("\n");
1992
0
}
1993
1994
0
void DeleteCommand::DoCommand() {
1995
0
  if (!db_) {
1996
0
    assert(GetExecuteState().IsFailed());
1997
0
    return;
1998
0
  }
1999
0
  Status st = db_->Delete(WriteOptions(), GetCfHandle(), key_);
2000
0
  if (st.ok()) {
2001
0
    fprintf(stdout, "OK\n");
2002
0
  } else {
2003
0
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
2004
0
  }
2005
0
}
2006
2007
2008
PutCommand::PutCommand(const vector<string>& params,
2009
      const map<string, string>& options, const vector<string>& flags) :
2010
  LDBCommand(options, flags, false,
2011
             BuildCmdLineOptions({ARG_TTL, ARG_HEX, ARG_KEY_HEX, ARG_VALUE_HEX,
2012
0
                                  ARG_CREATE_IF_MISSING})) {
2013
2014
0
  if (params.size() != 2) {
2015
0
    exec_state_ = LDBCommandExecuteResult::Failed(
2016
0
        "<key> and <value> must be specified for the put command");
2017
0
  } else {
2018
0
    key_ = params.at(0);
2019
0
    value_ = params.at(1);
2020
0
  }
2021
2022
0
  if (is_key_hex_) {
2023
0
    key_ = HexToString(key_);
2024
0
  }
2025
2026
0
  if (is_value_hex_) {
2027
0
    value_ = HexToString(value_);
2028
0
  }
2029
0
}
2030
2031
0
void PutCommand::Help(string& ret) {
2032
0
  ret.append("  ");
2033
0
  ret.append(PutCommand::Name());
2034
0
  ret.append(" <key> <value> ");
2035
0
  ret.append(" [--" + ARG_TTL + "]");
2036
0
  ret.append("\n");
2037
0
}
2038
2039
0
void PutCommand::DoCommand() {
2040
0
  if (!db_) {
2041
0
    assert(GetExecuteState().IsFailed());
2042
0
    return;
2043
0
  }
2044
0
  Status st = db_->Put(WriteOptions(), GetCfHandle(), key_, value_);
2045
0
  if (st.ok()) {
2046
0
    fprintf(stdout, "OK\n");
2047
0
  } else {
2048
0
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
2049
0
  }
2050
0
}
2051
2052
0
Options PutCommand::PrepareOptionsForOpenDB() {
2053
0
  Options opt = LDBCommand::PrepareOptionsForOpenDB();
2054
0
  opt.create_if_missing = IsFlagPresent(flags_, ARG_CREATE_IF_MISSING);
2055
0
  return opt;
2056
0
}
2057
2058
// ----------------------------------------------------------------------------
2059
2060
const char* DBQuerierCommand::HELP_CMD = "help";
2061
const char* DBQuerierCommand::GET_CMD = "get";
2062
const char* DBQuerierCommand::PUT_CMD = "put";
2063
const char* DBQuerierCommand::DELETE_CMD = "delete";
2064
2065
DBQuerierCommand::DBQuerierCommand(const vector<string>& params,
2066
    const map<string, string>& options, const vector<string>& flags) :
2067
  LDBCommand(options, flags, false,
2068
             BuildCmdLineOptions({ARG_TTL, ARG_HEX, ARG_KEY_HEX,
2069
0
                                  ARG_VALUE_HEX})) {
2070
2071
0
}
2072
2073
0
void DBQuerierCommand::Help(string& ret) {
2074
0
  ret.append("  ");
2075
0
  ret.append(DBQuerierCommand::Name());
2076
0
  ret.append(" [--" + ARG_TTL + "]");
2077
0
  ret.append("\n");
2078
0
  ret.append("    Starts a REPL shell.  Type help for list of available "
2079
0
             "commands.");
2080
0
  ret.append("\n");
2081
0
}
2082
2083
0
void DBQuerierCommand::DoCommand() {
2084
0
  if (!db_) {
2085
0
    assert(GetExecuteState().IsFailed());
2086
0
    return;
2087
0
  }
2088
2089
0
  ReadOptions read_options;
2090
0
  WriteOptions write_options;
2091
2092
0
  string line;
2093
0
  string key;
2094
0
  string value;
2095
0
  while (getline(std::cin, line, '\n')) {
2096
2097
    // Parse line into vector<string>
2098
0
    vector<string> tokens;
2099
0
    size_t pos = 0;
2100
0
    while (true) {
2101
0
      size_t pos2 = line.find(' ', pos);
2102
0
      if (pos2 == string::npos) {
2103
0
        break;
2104
0
      }
2105
0
      tokens.push_back(line.substr(pos, pos2-pos));
2106
0
      pos = pos2 + 1;
2107
0
    }
2108
0
    tokens.push_back(line.substr(pos));
2109
2110
0
    const string& cmd = tokens[0];
2111
2112
0
    if (cmd == HELP_CMD) {
2113
0
      fprintf(stdout,
2114
0
              "get <key>\n"
2115
0
              "put <key> <value>\n"
2116
0
              "delete <key>\n");
2117
0
    } else if (cmd == DELETE_CMD && tokens.size() == 2) {
2118
0
      key = (is_key_hex_ ? HexToString(tokens[1]) : tokens[1]);
2119
0
      CHECK_OK(db_->Delete(write_options, GetCfHandle(), Slice(key)));
2120
0
      fprintf(stdout, "Successfully deleted %s\n", tokens[1].c_str());
2121
0
    } else if (cmd == PUT_CMD && tokens.size() == 3) {
2122
0
      key = (is_key_hex_ ? HexToString(tokens[1]) : tokens[1]);
2123
0
      value = (is_value_hex_ ? HexToString(tokens[2]) : tokens[2]);
2124
0
      CHECK_OK(db_->Put(write_options, GetCfHandle(), Slice(key), Slice(value)));
2125
0
      fprintf(stdout, "Successfully put %s %s\n",
2126
0
              tokens[1].c_str(), tokens[2].c_str());
2127
0
    } else if (cmd == GET_CMD && tokens.size() == 2) {
2128
0
      key = (is_key_hex_ ? HexToString(tokens[1]) : tokens[1]);
2129
0
      if (db_->Get(read_options, GetCfHandle(), Slice(key), &value).ok()) {
2130
0
        fprintf(stdout, "%s\n", PrintKeyValue(key, value,
2131
0
              is_key_hex_, is_value_hex_).c_str());
2132
0
      } else {
2133
0
        fprintf(stdout, "Not found %s\n", tokens[1].c_str());
2134
0
      }
2135
0
    } else {
2136
0
      fprintf(stdout, "Unknown command %s\n", line.c_str());
2137
0
    }
2138
0
  }
2139
0
}
2140
2141
// ----------------------------------------------------------------------------
2142
2143
CheckConsistencyCommand::CheckConsistencyCommand(const vector<string>& params,
2144
    const map<string, string>& options, const vector<string>& flags) :
2145
  LDBCommand(options, flags, false,
2146
2
             BuildCmdLineOptions({})) {
2147
2
}
2148
2149
0
void CheckConsistencyCommand::Help(string& ret) {
2150
0
  ret.append("  ");
2151
0
  ret.append(CheckConsistencyCommand::Name());
2152
0
  ret.append("\n");
2153
0
}
2154
2155
2
void CheckConsistencyCommand::DoCommand() {
2156
2
  Options opt = PrepareOptionsForOpenDB();
2157
2
  opt.paranoid_checks = true;
2158
2
  if (!exec_state_.IsNotStarted()) {
2159
0
    return;
2160
0
  }
2161
2
  DB* db;
2162
2
  Status st = DB::OpenForReadOnly(opt, db_path_, &db, false);
2163
2
  delete db;
2164
2
  if (st.ok()) {
2165
2
    fprintf(stdout, "OK\n");
2166
0
  } else {
2167
0
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
2168
0
  }
2169
2
}
2170
2171
// ----------------------------------------------------------------------------
2172
2173
namespace {
2174
2175
0
void DumpSstFile(std::string filename, bool output_hex, bool show_properties) {
2176
0
  std::string from_key;
2177
0
  std::string to_key;
2178
0
  if (filename.length() <= 4 ||
2179
0
      filename.rfind(".sst") != filename.length() - 4) {
2180
0
    std::cout << "Invalid sst file name." << std::endl;
2181
0
    return;
2182
0
  }
2183
  // no verification
2184
0
  rocksdb::SstFileReader reader(
2185
0
      filename, false, (output_hex ? OutputFormat::kHex : OutputFormat::kRaw));
2186
0
  Status st = reader.ReadSequential(true, -1, false,  // has_from
2187
0
                                    from_key, false,  // has_to
2188
0
                                    to_key);
2189
0
  if (!st.ok()) {
2190
0
    std::cerr << "Error in reading SST file " << filename << st.ToString()
2191
0
              << std::endl;
2192
0
    return;
2193
0
  }
2194
2195
0
  if (show_properties) {
2196
0
    const rocksdb::TableProperties* table_properties;
2197
2198
0
    std::shared_ptr<const rocksdb::TableProperties>
2199
0
        table_properties_from_reader;
2200
0
    st = reader.ReadTableProperties(&table_properties_from_reader);
2201
0
    if (!st.ok()) {
2202
0
      std::cerr << filename << ": " << st.ToString()
2203
0
                << ". Try to use initial table properties" << std::endl;
2204
0
      table_properties = reader.GetInitTableProperties();
2205
0
    } else {
2206
0
      table_properties = table_properties_from_reader.get();
2207
0
    }
2208
0
    if (table_properties != nullptr) {
2209
0
      std::cout << std::endl << "Table Properties:" << std::endl;
2210
0
      std::cout << table_properties->ToString("\n") << std::endl;
2211
0
      std::cout << "# deleted keys: "
2212
0
                << rocksdb::GetDeletedKeys(
2213
0
                       table_properties->user_collected_properties)
2214
0
                << std::endl;
2215
0
    }
2216
0
  }
2217
0
}
2218
2219
}  // namespace
2220
2221
DBFileDumperCommand::DBFileDumperCommand(const vector<string>& params,
2222
                                         const map<string, string>& options,
2223
                                         const vector<string>& flags)
2224
0
    : LDBCommand(options, flags, true, BuildCmdLineOptions({})) {}
2225
2226
0
void DBFileDumperCommand::Help(string& ret) {
2227
0
  ret.append("  ");
2228
0
  ret.append(DBFileDumperCommand::Name());
2229
0
  ret.append("\n");
2230
0
}
2231
2232
0
void DBFileDumperCommand::DoCommand() {
2233
0
  if (!db_) {
2234
0
    assert(GetExecuteState().IsFailed());
2235
0
    return;
2236
0
  }
2237
0
  Status s;
2238
2239
0
  std::cout << "Manifest File" << std::endl;
2240
0
  std::cout << "==============================" << std::endl;
2241
0
  std::string manifest_filename;
2242
0
  s = ReadFileToString(db_->GetEnv(), CurrentFileName(db_->GetName()),
2243
0
                       &manifest_filename);
2244
0
  if (!s.ok() || manifest_filename.empty() ||
2245
0
      manifest_filename.back() != '\n') {
2246
0
    std::cerr << "Error when reading CURRENT file "
2247
0
              << CurrentFileName(db_->GetName()) << std::endl;
2248
0
  }
2249
  // remove the trailing '\n'
2250
0
  manifest_filename.resize(manifest_filename.size() - 1);
2251
0
  string manifest_filepath = db_->GetName() + "/" + manifest_filename;
2252
0
  std::cout << manifest_filepath << std::endl;
2253
0
  DumpManifestFile(manifest_filepath, false, false);
2254
0
  std::cout << std::endl;
2255
2256
0
  std::cout << "SST Files" << std::endl;
2257
0
  std::cout << "==============================" << std::endl;
2258
0
  std::vector<LiveFileMetaData> metadata;
2259
0
  db_->GetLiveFilesMetaData(&metadata);
2260
0
  for (auto& fileMetadata : metadata) {
2261
0
    std::string filename = fileMetadata.db_path + fileMetadata.name;
2262
0
    std::cout << filename << " level:" << fileMetadata.level << std::endl;
2263
0
    std::cout << "------------------------------" << std::endl;
2264
0
    DumpSstFile(filename, false, true);
2265
0
    std::cout << std::endl;
2266
0
  }
2267
0
  std::cout << std::endl;
2268
2269
0
  std::cout << "Write Ahead Log Files" << std::endl;
2270
0
  std::cout << "==============================" << std::endl;
2271
0
  rocksdb::VectorLogPtr wal_files;
2272
0
  s = db_->GetSortedWalFiles(&wal_files);
2273
0
  if (!s.ok()) {
2274
0
    std::cerr << "Error when getting WAL files" << std::endl;
2275
0
  } else {
2276
0
    for (auto& wal : wal_files) {
2277
      // TODO(qyang): option.wal_dir should be passed into ldb command
2278
0
      std::string filename = db_->GetOptions().wal_dir + wal->PathName();
2279
0
      std::cout << filename << std::endl;
2280
0
      DumpWalFile(filename, true, true, &exec_state_);
2281
0
    }
2282
0
  }
2283
0
}
2284
2285
}   // namespace rocksdb
2286
#endif  // ROCKSDB_LITE