ldb_cmd.cc 64.5 KB
Newer Older
1 2 3 4 5
//  Copyright (c) 2013, Facebook, Inc.  All rights reserved.
//  This source code is licensed under the BSD-style license found in the
//  LICENSE file in the root directory of this source tree. An additional grant
//  of patent rights can be found in the PATENTS file in the same directory.
//
I
Igor Canadi 已提交
6
#ifndef ROCKSDB_LITE
7
#include "util/ldb_cmd.h"
A
Abhishek Kona 已提交
8 9

#include "db/dbformat.h"
10
#include "db/db_impl.h"
A
Abhishek Kona 已提交
11
#include "db/log_reader.h"
12
#include "db/filename.h"
13
#include "db/writebuffer.h"
A
Abhishek Kona 已提交
14
#include "db/write_batch_internal.h"
15
#include "rocksdb/write_batch.h"
I
Igor Canadi 已提交
16
#include "rocksdb/cache.h"
17
#include "rocksdb/table_properties.h"
D
Dmitri Smirnov 已提交
18
#include "port/dirent.h"
19
#include "util/coding.h"
20
#include "util/sst_dump_tool_imp.h"
S
sdong 已提交
21
#include "util/string_util.h"
22
#include "util/scoped_arena_iterator.h"
23
#include "utilities/ttl/db_ttl_impl.h"
24

S
sdong 已提交
25
#include <cstdlib>
26 27 28 29 30 31
#include <ctime>
#include <limits>
#include <sstream>
#include <string>
#include <stdexcept>

32
namespace rocksdb {
33

34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
using namespace std;

const string LDBCommand::ARG_DB = "db";
const string LDBCommand::ARG_HEX = "hex";
const string LDBCommand::ARG_KEY_HEX = "key_hex";
const string LDBCommand::ARG_VALUE_HEX = "value_hex";
const string LDBCommand::ARG_TTL = "ttl";
const string LDBCommand::ARG_TTL_START = "start_time";
const string LDBCommand::ARG_TTL_END = "end_time";
const string LDBCommand::ARG_TIMESTAMP = "timestamp";
const string LDBCommand::ARG_FROM = "from";
const string LDBCommand::ARG_TO = "to";
const string LDBCommand::ARG_MAX_KEYS = "max_keys";
const string LDBCommand::ARG_BLOOM_BITS = "bloom_bits";
const string LDBCommand::ARG_FIX_PREFIX_LEN = "fix_prefix_len";
const string LDBCommand::ARG_COMPRESSION_TYPE = "compression_type";
const string LDBCommand::ARG_BLOCK_SIZE = "block_size";
const string LDBCommand::ARG_AUTO_COMPACTION = "auto_compaction";
52
const string LDBCommand::ARG_DB_WRITE_BUFFER_SIZE = "db_write_buffer_size";
53 54 55
const string LDBCommand::ARG_WRITE_BUFFER_SIZE = "write_buffer_size";
const string LDBCommand::ARG_FILE_SIZE = "file_size";
const string LDBCommand::ARG_CREATE_IF_MISSING = "create_if_missing";
56

57
const char* LDBCommand::DELIM = " ==> ";
58

59
LDBCommand* LDBCommand::InitFromCmdLineArgs(
60 61 62 63 64 65
  int argc,
  char** argv,
  const Options& options,
  const LDBOptions& ldb_options
) {
  vector<string> args;
66 67 68
  for (int i = 1; i < argc; i++) {
    args.push_back(argv[i]);
  }
69
  return InitFromCmdLineArgs(args, options, ldb_options);
70 71 72 73 74 75
}

/**
 * Parse the command-line arguments and create the appropriate LDBCommand2
 * instance.
 * The command line arguments must be in the following format:
76 77
 * ./ldb --db=PATH_TO_DB [--commonOpt1=commonOpt1Val] ..
 *        COMMAND <PARAM1> <PARAM2> ... [-cmdSpecificOpt1=cmdSpecificOpt1Val] ..
78 79
 * This is similar to the command line format used by HBaseClientTool.
 * Command name is not included in args.
80
 * Returns nullptr if the command-line cannot be parsed.
81
 */
82
LDBCommand* LDBCommand::InitFromCmdLineArgs(
83 84 85 86 87 88
  const vector<string>& args,
  const Options& options,
  const LDBOptions& ldb_options
) {
  // --x=y command line arguments are added as x->y map entries.
  map<string, string> option_map;
89 90

  // Command-line arguments of the form --hex end up in this array as hex
91
  vector<string> flags;
92

93
  // Everything other than option_map and flags. Represents commands
94 95
  // and their parameters.  For eg: put key1 value1 go into this vector.
  vector<string> cmdTokens;
96

97
  const string OPTION_PREFIX = "--";
98

99
  for (const auto& arg : args) {
100
    if (arg[0] == '-' && arg[1] == '-'){
I
Igor Canadi 已提交
101
      vector<string> splits = StringSplit(arg, '=');
102
      if (splits.size() == 2) {
103
        string optionKey = splits[0].substr(OPTION_PREFIX.size());
104
        option_map[optionKey] = splits[1];
105
      } else {
106
        string optionKey = splits[0].substr(OPTION_PREFIX.size());
107 108
        flags.push_back(optionKey);
      }
109
    } else {
110
      cmdTokens.push_back(arg);
111 112 113 114 115
    }
  }

  if (cmdTokens.size() < 1) {
    fprintf(stderr, "Command not specified!");
116
    return nullptr;
117 118
  }

119 120
  string cmd = cmdTokens[0];
  vector<string> cmdParams(cmdTokens.begin()+1, cmdTokens.end());
121
  LDBCommand* command = LDBCommand::SelectCommand(
122 123 124 125 126
    cmd,
    cmdParams,
    option_map,
    flags
  );
127 128

  if (command) {
129 130
    command->SetDBOptions(options);
    command->SetLDBOptions(ldb_options);
131 132 133 134 135 136
  }
  return command;
}

LDBCommand* LDBCommand::SelectCommand(
    const std::string& cmd,
137 138 139 140 141
    const vector<string>& cmdParams,
    const map<string, string>& option_map,
    const vector<string>& flags
  ) {

142
  if (cmd == GetCommand::Name()) {
143
    return new GetCommand(cmdParams, option_map, flags);
144
  } else if (cmd == PutCommand::Name()) {
145
    return new PutCommand(cmdParams, option_map, flags);
146
  } else if (cmd == BatchPutCommand::Name()) {
147
    return new BatchPutCommand(cmdParams, option_map, flags);
148
  } else if (cmd == ScanCommand::Name()) {
149
    return new ScanCommand(cmdParams, option_map, flags);
150
  } else if (cmd == DeleteCommand::Name()) {
151
    return new DeleteCommand(cmdParams, option_map, flags);
152
  } else if (cmd == ApproxSizeCommand::Name()) {
153
    return new ApproxSizeCommand(cmdParams, option_map, flags);
154
  } else if (cmd == DBQuerierCommand::Name()) {
155
    return new DBQuerierCommand(cmdParams, option_map, flags);
156
  } else if (cmd == CompactorCommand::Name()) {
157
    return new CompactorCommand(cmdParams, option_map, flags);
158
  } else if (cmd == WALDumperCommand::Name()) {
159
    return new WALDumperCommand(cmdParams, option_map, flags);
160
  } else if (cmd == ReduceDBLevelsCommand::Name()) {
161
    return new ReduceDBLevelsCommand(cmdParams, option_map, flags);
162 163
  } else if (cmd == ChangeCompactionStyleCommand::Name()) {
    return new ChangeCompactionStyleCommand(cmdParams, option_map, flags);
164
  } else if (cmd == DBDumperCommand::Name()) {
165
    return new DBDumperCommand(cmdParams, option_map, flags);
166
  } else if (cmd == DBLoaderCommand::Name()) {
167
    return new DBLoaderCommand(cmdParams, option_map, flags);
168
  } else if (cmd == ManifestDumpCommand::Name()) {
169
    return new ManifestDumpCommand(cmdParams, option_map, flags);
170 171
  } else if (cmd == ListColumnFamiliesCommand::Name()) {
    return new ListColumnFamiliesCommand(cmdParams, option_map, flags);
172 173
  } else if (cmd == DBFileDumperCommand::Name()) {
    return new DBFileDumperCommand(cmdParams, option_map, flags);
174 175
  } else if (cmd == InternalDumpCommand::Name()) {
    return new InternalDumpCommand(cmdParams, option_map, flags);
Y
Yiting Li 已提交
176 177
  } else if (cmd == CheckConsistencyCommand::Name()) {
    return new CheckConsistencyCommand(cmdParams, option_map, flags);
178
  }
179
  return nullptr;
180 181
}

182

183 184 185 186 187 188 189
/**
 * Parses the specific integer option and fills in the value.
 * Returns true if the option is found.
 * Returns false if the option is not found or if there is an error parsing the
 * value.  If there is an error, the specified exec_state is also
 * updated.
 */
190 191 192 193 194
bool LDBCommand::ParseIntOption(const map<string, string>& options,
                                const string& option, int& value,
                                LDBCommandExecuteResult& exec_state) {

  map<string, string>::const_iterator itr = option_map_.find(option);
195
  if (itr != option_map_.end()) {
196
    try {
S
sdong 已提交
197 198 199
#if defined(CYGWIN)
      value = strtol(itr->second.c_str(), 0, 10);
#else
200
      value = stoi(itr->second);
S
sdong 已提交
201
#endif
202
      return true;
203
    } catch(const invalid_argument&) {
204 205
      exec_state =
          LDBCommandExecuteResult::Failed(option + " has an invalid value.");
206
    } catch(const out_of_range&) {
207 208
      exec_state = LDBCommandExecuteResult::Failed(
          option + " has a value out-of-range.");
209 210
    }
  }
211
  return false;
212 213
}

214 215 216 217 218
/**
 * Parses the specified option and fills in the value.
 * Returns true if the option is found.
 * Returns false otherwise.
 */
219 220
bool LDBCommand::ParseStringOption(const map<string, string>& options,
                                   const string& option, string* value) {
221 222 223 224 225 226 227 228
  auto itr = option_map_.find(option);
  if (itr != option_map_.end()) {
    *value = itr->second;
    return true;
  }
  return false;
}

229
Options LDBCommand::PrepareOptionsForOpenDB() {
230

231
  Options opt = options_;
232
  opt.create_if_missing = false;
233

234
  map<string, string>::const_iterator itr;
235

236
  BlockBasedTableOptions table_options;
S
sdong 已提交
237
  bool use_table_options = false;
238
  int bits;
239
  if (ParseIntOption(option_map_, ARG_BLOOM_BITS, bits, exec_state_)) {
240
    if (bits > 0) {
S
sdong 已提交
241
      use_table_options = true;
242
      table_options.filter_policy.reset(NewBloomFilterPolicy(bits));
243
    } else {
244 245
      exec_state_ =
          LDBCommandExecuteResult::Failed(ARG_BLOOM_BITS + " must be > 0.");
246 247 248 249
    }
  }

  int block_size;
250
  if (ParseIntOption(option_map_, ARG_BLOCK_SIZE, block_size, exec_state_)) {
251
    if (block_size > 0) {
S
sdong 已提交
252
      use_table_options = true;
253
      table_options.block_size = block_size;
254
    } else {
255 256
      exec_state_ =
          LDBCommandExecuteResult::Failed(ARG_BLOCK_SIZE + " must be > 0.");
257 258 259
    }
  }

S
sdong 已提交
260 261 262 263
  if (use_table_options) {
    opt.table_factory.reset(NewBlockBasedTableFactory(table_options));
  }

264 265
  itr = option_map_.find(ARG_AUTO_COMPACTION);
  if (itr != option_map_.end()) {
266 267 268
    opt.disable_auto_compactions = ! StringToBool(itr->second);
  }

269 270
  itr = option_map_.find(ARG_COMPRESSION_TYPE);
  if (itr != option_map_.end()) {
271
    string comp = itr->second;
272
    if (comp == "no") {
273
      opt.compression = kNoCompression;
274
    } else if (comp == "snappy") {
275
      opt.compression = kSnappyCompression;
276
    } else if (comp == "zlib") {
277
      opt.compression = kZlibCompression;
278
    } else if (comp == "bzip2") {
279
      opt.compression = kBZip2Compression;
A
Albert Strasheim 已提交
280 281 282 283
    } else if (comp == "lz4") {
      opt.compression = kLZ4Compression;
    } else if (comp == "lz4hc") {
      opt.compression = kLZ4HCCompression;
284 285
    } else if (comp == "zstd") {
      opt.compression = kZSTDNotFinalCompression;
286 287
    } else {
      // Unknown compression.
288 289
      exec_state_ =
          LDBCommandExecuteResult::Failed("Unknown compression level: " + comp);
290 291 292
    }
  }

293 294 295 296 297 298
  int db_write_buffer_size;
  if (ParseIntOption(option_map_, ARG_DB_WRITE_BUFFER_SIZE,
        db_write_buffer_size, exec_state_)) {
    if (db_write_buffer_size >= 0) {
      opt.db_write_buffer_size = db_write_buffer_size;
    } else {
299
      exec_state_ = LDBCommandExecuteResult::Failed(ARG_DB_WRITE_BUFFER_SIZE +
300
                                                    " must be >= 0.");
301 302 303
    }
  }

304
  int write_buffer_size;
305 306
  if (ParseIntOption(option_map_, ARG_WRITE_BUFFER_SIZE, write_buffer_size,
        exec_state_)) {
307
    if (write_buffer_size > 0) {
308
      opt.write_buffer_size = write_buffer_size;
309
    } else {
310
      exec_state_ = LDBCommandExecuteResult::Failed(ARG_WRITE_BUFFER_SIZE +
311
                                                    " must be > 0.");
312 313 314 315
    }
  }

  int file_size;
316
  if (ParseIntOption(option_map_, ARG_FILE_SIZE, file_size, exec_state_)) {
317
    if (file_size > 0) {
318 319
      opt.target_file_size_base = file_size;
    } else {
320 321
      exec_state_ =
          LDBCommandExecuteResult::Failed(ARG_FILE_SIZE + " must be > 0.");
322 323 324
    }
  }

325
  if (opt.db_paths.size() == 0) {
326
    opt.db_paths.emplace_back(db_path_, std::numeric_limits<uint64_t>::max());
327 328
  }

S
sdong 已提交
329
  int fix_prefix_len;
330 331
  if (ParseIntOption(option_map_, ARG_FIX_PREFIX_LEN, fix_prefix_len,
                     exec_state_)) {
S
sdong 已提交
332 333 334 335
    if (fix_prefix_len > 0) {
      opt.prefix_extractor.reset(
          NewFixedPrefixTransform(static_cast<size_t>(fix_prefix_len)));
    } else {
336
      exec_state_ =
337
          LDBCommandExecuteResult::Failed(ARG_FIX_PREFIX_LEN + " must be > 0.");
S
sdong 已提交
338 339 340
    }
  }

341 342 343
  return opt;
}

344 345
bool LDBCommand::ParseKeyValue(const string& line, string* key, string* value,
                              bool is_key_hex, bool is_value_hex) {
346
  size_t pos = line.find(DELIM);
347
  if (pos != string::npos) {
348 349 350 351 352 353 354 355 356 357 358 359 360
    *key = line.substr(0, pos);
    *value = line.substr(pos + strlen(DELIM));
    if (is_key_hex) {
      *key = HexToString(*key);
    }
    if (is_value_hex) {
      *value = HexToString(*value);
    }
    return true;
  } else {
    return false;
  }
}
361

362 363 364 365 366 367 368 369 370
/**
 * Make sure that ONLY the command-line options and flags expected by this
 * command are specified on the command-line.  Extraneous options are usually
 * the result of user error.
 * Returns true if all checks pass.  Else returns false, and prints an
 * appropriate error msg to stderr.
 */
bool LDBCommand::ValidateCmdLineOptions() {

371 372
  for (map<string, string>::const_iterator itr = option_map_.begin();
        itr != option_map_.end(); ++itr) {
M
Mayank Agarwal 已提交
373
    if (find(valid_cmd_line_options_.begin(),
374
          valid_cmd_line_options_.end(), itr->first) ==
375 376 377 378 379
          valid_cmd_line_options_.end()) {
      fprintf(stderr, "Invalid command-line option %s\n", itr->first.c_str());
      return false;
    }
  }
380

381
  for (vector<string>::const_iterator itr = flags_.begin();
382
        itr != flags_.end(); ++itr) {
M
Mayank Agarwal 已提交
383
    if (find(valid_cmd_line_options_.begin(),
384
          valid_cmd_line_options_.end(), *itr) ==
385 386 387
          valid_cmd_line_options_.end()) {
      fprintf(stderr, "Invalid command-line flag %s\n", itr->c_str());
      return false;
388 389 390
    }
  }

391
  if (!NoDBOpen() && option_map_.find(ARG_DB) == option_map_.end()) {
392 393 394 395 396 397 398
    fprintf(stderr, "%s must be specified\n", ARG_DB.c_str());
    return false;
  }

  return true;
}

399 400
CompactorCommand::CompactorCommand(const vector<string>& params,
      const map<string, string>& options, const vector<string>& flags) :
401 402
    LDBCommand(options, flags, false,
               BuildCmdLineOptions({ARG_FROM, ARG_TO, ARG_HEX, ARG_KEY_HEX,
403
                                    ARG_VALUE_HEX, ARG_TTL})),
404
    null_from_(true), null_to_(true) {
405 406

  map<string, string>::const_iterator itr = options.find(ARG_FROM);
407 408 409 410 411 412 413 414 415 416 417 418
  if (itr != options.end()) {
    null_from_ = false;
    from_ = itr->second;
  }

  itr = options.find(ARG_TO);
  if (itr != options.end()) {
    null_to_ = false;
    to_ = itr->second;
  }

  if (is_key_hex_) {
419 420 421 422 423 424 425 426 427
    if (!null_from_) {
      from_ = HexToString(from_);
    }
    if (!null_to_) {
      to_ = HexToString(to_);
    }
  }
}

428 429 430 431 432
void CompactorCommand::Help(string& ret) {
  ret.append("  ");
  ret.append(CompactorCommand::Name());
  ret.append(HelpRangeCmdArgs());
  ret.append("\n");
433 434
}

435
void CompactorCommand::DoCommand() {
436

437 438
  Slice* begin = nullptr;
  Slice* end = nullptr;
439
  if (!null_from_) {
440
    begin = new Slice(from_);
441 442
  }
  if (!null_to_) {
443
    end = new Slice(to_);
444 445
  }

446
  db_->CompactRange(CompactRangeOptions(), begin, end);
447
  exec_state_ = LDBCommandExecuteResult::Succeed("");
448 449 450 451 452

  delete begin;
  delete end;
}

453 454
// ----------------------------------------------------------------------------

455 456 457
const string DBLoaderCommand::ARG_DISABLE_WAL = "disable_wal";
const string DBLoaderCommand::ARG_BULK_LOAD = "bulk_load";
const string DBLoaderCommand::ARG_COMPACT = "compact";
Z
Zheng Shao 已提交
458

459 460
DBLoaderCommand::DBLoaderCommand(const vector<string>& params,
      const map<string, string>& options, const vector<string>& flags) :
461 462 463
    LDBCommand(options, flags, false,
               BuildCmdLineOptions({ARG_HEX, ARG_KEY_HEX, ARG_VALUE_HEX,
                                    ARG_FROM, ARG_TO, ARG_CREATE_IF_MISSING,
464 465 466 467
                                    ARG_DISABLE_WAL, ARG_BULK_LOAD,
                                    ARG_COMPACT})),
    create_if_missing_(false), disable_wal_(false), bulk_load_(false),
    compact_(false) {
468 469 470

  create_if_missing_ = IsFlagPresent(flags, ARG_CREATE_IF_MISSING);
  disable_wal_ = IsFlagPresent(flags, ARG_DISABLE_WAL);
471 472
  bulk_load_ = IsFlagPresent(flags, ARG_BULK_LOAD);
  compact_ = IsFlagPresent(flags, ARG_COMPACT);
Z
Zheng Shao 已提交
473 474
}

475 476 477 478 479 480 481 482
void DBLoaderCommand::Help(string& ret) {
  ret.append("  ");
  ret.append(DBLoaderCommand::Name());
  ret.append(" [--" + ARG_CREATE_IF_MISSING + "]");
  ret.append(" [--" + ARG_DISABLE_WAL + "]");
  ret.append(" [--" + ARG_BULK_LOAD + "]");
  ret.append(" [--" + ARG_COMPACT + "]");
  ret.append("\n");
Z
Zheng Shao 已提交
483 484
}

485 486
Options DBLoaderCommand::PrepareOptionsForOpenDB() {
  Options opt = LDBCommand::PrepareOptionsForOpenDB();
Z
Zheng Shao 已提交
487
  opt.create_if_missing = create_if_missing_;
488 489 490
  if (bulk_load_) {
    opt.PrepareForBulkLoad();
  }
Z
Zheng Shao 已提交
491 492 493
  return opt;
}

494
void DBLoaderCommand::DoCommand() {
Z
Zheng Shao 已提交
495 496 497 498 499 500 501 502 503 504
  if (!db_) {
    return;
  }

  WriteOptions write_options;
  if (disable_wal_) {
    write_options.disableWAL = true;
  }

  int bad_lines = 0;
505 506 507 508
  string line;
  while (getline(cin, line, '\n')) {
    string key;
    string value;
509
    if (ParseKeyValue(line, &key, &value, is_key_hex_, is_value_hex_)) {
Z
Zheng Shao 已提交
510 511 512 513 514 515 516 517 518
      db_->Put(write_options, Slice(key), Slice(value));
    } else if (0 == line.find("Keys in range:")) {
      // ignore this line
    } else if (0 == line.find("Created bg thread 0x")) {
      // ignore this line
    } else {
      bad_lines ++;
    }
  }
519

Z
Zheng Shao 已提交
520
  if (bad_lines > 0) {
521
    cout << "Warning: " << bad_lines << " bad lines ignored." << endl;
Z
Zheng Shao 已提交
522
  }
523
  if (compact_) {
524
    db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
525
  }
Z
Zheng Shao 已提交
526 527
}

528 529
// ----------------------------------------------------------------------------

530 531
namespace {

532
void DumpManifestFile(std::string file, bool verbose, bool hex, bool json) {
533 534 535
  Options options;
  EnvOptions sopt;
  std::string dbname("dummy");
536 537
  std::shared_ptr<Cache> tc(NewLRUCache(options.max_open_files - 10,
                                        options.table_cache_numshardbits));
538 539 540 541
  // Notice we are using the default options not through SanitizeOptions(),
  // if VersionSet::DumpManifest() depends on any option done by
  // SanitizeOptions(), we need to initialize it manually.
  options.db_paths.emplace_back("dummy", 0);
542
  options.num_levels = 64;
S
sdong 已提交
543
  WriteController wc(options.delayed_write_rate);
544 545
  WriteBuffer wb(options.db_write_buffer_size);
  VersionSet versions(dbname, &options, sopt, tc.get(), &wb, &wc);
546
  Status s = versions.DumpManifest(options, file, verbose, hex, json);
547 548 549 550 551 552 553 554
  if (!s.ok()) {
    printf("Error in processing file %s %s\n", file.c_str(),
           s.ToString().c_str());
  }
}

}  // namespace

555
const string ManifestDumpCommand::ARG_VERBOSE = "verbose";
556 557
const string ManifestDumpCommand::ARG_JSON = "json";
const string ManifestDumpCommand::ARG_PATH = "path";
558

559 560 561 562
void ManifestDumpCommand::Help(string& ret) {
  ret.append("  ");
  ret.append(ManifestDumpCommand::Name());
  ret.append(" [--" + ARG_VERBOSE + "]");
563
  ret.append(" [--" + ARG_JSON + "]");
564 565
  ret.append(" [--" + ARG_PATH + "=<path_to_manifest_file>]");
  ret.append("\n");
566 567
}

568 569
ManifestDumpCommand::ManifestDumpCommand(const vector<string>& params,
      const map<string, string>& options, const vector<string>& flags) :
570
    LDBCommand(options, flags, false,
571
               BuildCmdLineOptions({ARG_VERBOSE, ARG_PATH, ARG_HEX, ARG_JSON})),
572
    verbose_(false),
573
    json_(false),
574 575
    path_("")
{
576
  verbose_ = IsFlagPresent(flags, ARG_VERBOSE);
577
  json_ = IsFlagPresent(flags, ARG_JSON);
578

579
  map<string, string>::const_iterator itr = options.find(ARG_PATH);
580 581 582
  if (itr != options.end()) {
    path_ = itr->second;
    if (path_.empty()) {
583
      exec_state_ = LDBCommandExecuteResult::Failed("--path: missing pathname");
584 585 586 587 588 589 590 591 592 593 594 595 596 597
    }
  }
}

void ManifestDumpCommand::DoCommand() {

  std::string manifestfile;

  if (!path_.empty()) {
    manifestfile = path_;
  } else {
    bool found = false;
    // We need to find the manifest file by searching the directory
    // containing the db for files of the form MANIFEST_[0-9]+
D
Dmitri Smirnov 已提交
598 599

    auto CloseDir = [](DIR* p) { closedir(p); };
S
sdong 已提交
600 601
    std::unique_ptr<DIR, decltype(CloseDir)> d(opendir(db_path_.c_str()),
                                               CloseDir);
D
Dmitri Smirnov 已提交
602

603
    if (d == nullptr) {
604 605
      exec_state_ =
          LDBCommandExecuteResult::Failed(db_path_ + " is not a directory");
606 607 608
      return;
    }
    struct dirent* entry;
D
Dmitri Smirnov 已提交
609
    while ((entry = readdir(d.get())) != nullptr) {
610
      unsigned int match;
611 612 613
      uint64_t num;
      if (sscanf(entry->d_name, "MANIFEST-%lu%n", &num, &match) &&
          match == strlen(entry->d_name)) {
614 615 616 617
        if (!found) {
          manifestfile = db_path_ + "/" + std::string(entry->d_name);
          found = true;
        } else {
618
          exec_state_ = LDBCommandExecuteResult::Failed(
619
              "Multiple MANIFEST files found; use --path to select one");
620 621 622 623 624 625 626 627 628 629
          return;
        }
      }
    }
  }

  if (verbose_) {
    printf("Processing Manifest file %s\n", manifestfile.c_str());
  }

630 631
  DumpManifestFile(manifestfile, verbose_, is_key_hex_, json_);

632 633 634 635 636 637
  if (verbose_) {
    printf("Processing Manifest file %s done\n", manifestfile.c_str());
  }
}

// ----------------------------------------------------------------------------
638

639 640 641 642 643
void ListColumnFamiliesCommand::Help(string& ret) {
  ret.append("  ");
  ret.append(ListColumnFamiliesCommand::Name());
  ret.append(" full_path_to_db_directory ");
  ret.append("\n");
644 645 646
}

ListColumnFamiliesCommand::ListColumnFamiliesCommand(
647 648
    const vector<string>& params, const map<string, string>& options,
    const vector<string>& flags)
649 650 651
    : LDBCommand(options, flags, false, {}) {

  if (params.size() != 1) {
652
    exec_state_ = LDBCommandExecuteResult::Failed(
653 654 655 656 657 658 659
        "dbname must be specified for the list_column_families command");
  } else {
    dbname_ = params[0];
  }
}

void ListColumnFamiliesCommand::DoCommand() {
660
  vector<string> column_families;
661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
  Status s = DB::ListColumnFamilies(DBOptions(), dbname_, &column_families);
  if (!s.ok()) {
    printf("Error in processing db %s %s\n", dbname_.c_str(),
           s.ToString().c_str());
  } else {
    printf("Column families in %s: \n{", dbname_.c_str());
    bool first = true;
    for (auto cf : column_families) {
      if (!first) {
        printf(", ");
      }
      first = false;
      printf("%s", cf.c_str());
    }
    printf("}\n");
  }
}

// ----------------------------------------------------------------------------
680

I
Igor Canadi 已提交
681 682
namespace {

683
string ReadableTime(int unixtime) {
684 685
  char time_buffer [80];
  time_t rawtime = unixtime;
686 687 688
  struct tm tInfo;
  struct tm* timeinfo = localtime_r(&rawtime, &tInfo);
  assert(timeinfo == &tInfo);
689
  strftime(time_buffer, 80, "%c", timeinfo);
690
  return string(time_buffer);
691 692 693 694
}

// This function only called when it's the sane case of >1 buckets in time-range
// Also called only when timekv falls between ttl_start and ttl_end provided
695
void IncBucketCounts(vector<uint64_t>& bucket_counts, int ttl_start,
696 697 698 699
      int time_range, int bucket_size, int timekv, int num_buckets) {
  assert(time_range > 0 && timekv >= ttl_start && bucket_size > 0 &&
    timekv < (ttl_start + time_range) && num_buckets > 1);
  int bucket = (timekv - ttl_start) / bucket_size;
700
  bucket_counts[bucket]++;
701 702
}

703 704
void PrintBucketCounts(const vector<uint64_t>& bucket_counts, int ttl_start,
      int ttl_end, int bucket_size, int num_buckets) {
705
  int time_point = ttl_start;
706 707
  for(int i = 0; i < num_buckets - 1; i++, time_point += bucket_size) {
    fprintf(stdout, "Keys in range %s to %s : %lu\n",
708
            ReadableTime(time_point).c_str(),
K
Kai Liu 已提交
709
            ReadableTime(time_point + bucket_size).c_str(),
710
            (unsigned long)bucket_counts[i]);
711
  }
712
  fprintf(stdout, "Keys in range %s to %s : %lu\n",
713
          ReadableTime(time_point).c_str(),
K
Kai Liu 已提交
714
          ReadableTime(ttl_end).c_str(),
715
          (unsigned long)bucket_counts[num_buckets - 1]);
716 717
}

I
Igor Canadi 已提交
718 719
}  // namespace

720 721 722 723
const string InternalDumpCommand::ARG_COUNT_ONLY = "count_only";
const string InternalDumpCommand::ARG_COUNT_DELIM = "count_delim";
const string InternalDumpCommand::ARG_STATS = "stats";
const string InternalDumpCommand::ARG_INPUT_KEY_HEX = "input_key_hex";
724

725 726 727
InternalDumpCommand::InternalDumpCommand(const vector<string>& params,
                                         const map<string, string>& options,
                                         const vector<string>& flags) :
728
    LDBCommand(options, flags, true,
729 730 731 732
               BuildCmdLineOptions({ ARG_HEX, ARG_KEY_HEX, ARG_VALUE_HEX,
                                     ARG_FROM, ARG_TO, ARG_MAX_KEYS,
                                     ARG_COUNT_ONLY, ARG_COUNT_DELIM, ARG_STATS,
                                     ARG_INPUT_KEY_HEX})),
733 734 735
    has_from_(false),
    has_to_(false),
    max_keys_(-1),
736
    delim_("."),
737
    count_only_(false),
738
    count_delim_(false),
739 740
    print_stats_(false),
    is_input_key_hex_(false) {
741 742 743 744

  has_from_ = ParseStringOption(options, ARG_FROM, &from_);
  has_to_ = ParseStringOption(options, ARG_TO, &to_);

745 746
  ParseIntOption(options, ARG_MAX_KEYS, max_keys_, exec_state_);
  map<string, string>::const_iterator itr = options.find(ARG_COUNT_DELIM);
747 748 749
  if (itr != options.end()) {
    delim_ = itr->second;
    count_delim_ = true;
750
   // fprintf(stdout,"delim = %c\n",delim_[0]);
751 752
  } else {
    count_delim_ = IsFlagPresent(flags, ARG_COUNT_DELIM);
753
    delim_=".";
754
  }
755 756 757

  print_stats_ = IsFlagPresent(flags, ARG_STATS);
  count_only_ = IsFlagPresent(flags, ARG_COUNT_ONLY);
758
  is_input_key_hex_ = IsFlagPresent(flags, ARG_INPUT_KEY_HEX);
759

760
  if (is_input_key_hex_) {
761 762 763 764 765 766 767 768 769
    if (has_from_) {
      from_ = HexToString(from_);
    }
    if (has_to_) {
      to_ = HexToString(to_);
    }
  }
}

770 771 772 773 774 775 776 777 778 779
void InternalDumpCommand::Help(string& ret) {
  ret.append("  ");
  ret.append(InternalDumpCommand::Name());
  ret.append(HelpRangeCmdArgs());
  ret.append(" [--" + ARG_INPUT_KEY_HEX + "]");
  ret.append(" [--" + ARG_MAX_KEYS + "=<N>]");
  ret.append(" [--" + ARG_COUNT_ONLY + "]");
  ret.append(" [--" + ARG_COUNT_DELIM + "=<char>]");
  ret.append(" [--" + ARG_STATS + "]");
  ret.append("\n");
780 781 782 783 784 785 786 787
}

void InternalDumpCommand::DoCommand() {
  if (!db_) {
    return;
  }

  if (print_stats_) {
788
    string stats;
789
    if (db_->GetProperty("rocksdb.stats", &stats)) {
790 791 792 793 794 795 796
      fprintf(stdout, "%s\n", stats.c_str());
    }
  }

  // Cast as DBImpl to get internal iterator
  DBImpl* idb = dynamic_cast<DBImpl*>(db_);
  if (!idb) {
797
    exec_state_ = LDBCommandExecuteResult::Failed("DB is not DBImpl");
798 799
    return;
  }
800
  string rtype1,rtype2,row,val;
801
  rtype2 = "";
802 803
  uint64_t c=0;
  uint64_t s1=0,s2=0;
804
  // Setup internal key iterator
805 806
  Arena arena;
  ScopedArenaIterator iter(idb->TEST_NewInternalIterator(&arena));
807 808
  Status st = iter->status();
  if (!st.ok()) {
809 810
    exec_state_ =
        LDBCommandExecuteResult::Failed("Iterator error:" + st.ToString());
811 812 813
  }

  if (has_from_) {
814 815
    InternalKey ikey;
    ikey.SetMaxPossibleForUserKey(from_);
816 817 818 819 820
    iter->Seek(ikey.Encode());
  } else {
    iter->SeekToFirst();
  }

821
  long long count = 0;
822 823 824 825 826 827 828 829 830 831 832 833 834 835 836
  for (; iter->Valid(); iter->Next()) {
    ParsedInternalKey ikey;
    if (!ParseInternalKey(iter->key(), &ikey)) {
      fprintf(stderr, "Internal Key [%s] parse error!\n",
              iter->key().ToString(true /* in hex*/).data());
      // TODO: add error counter
      continue;
    }

    // If end marker was specified, we stop before it
    if (has_to_ && options_.comparator->Compare(ikey.user_key, to_) >= 0) {
      break;
    }

    ++count;
837 838 839
    int k;
    if (count_delim_) {
      rtype1 = "";
840
      s1=0;
841 842
      row = iter->key().ToString();
      val = iter->value().ToString();
843
      for(k=0;row[k]!='\x01' && row[k]!='\0';k++)
844
        s1++;
845
      for(k=0;val[k]!='\x01' && val[k]!='\0';k++)
846
        s1++;
847 848 849 850 851 852 853
      for(int j=0;row[j]!=delim_[0] && row[j]!='\0' && row[j]!='\x01';j++)
        rtype1+=row[j];
      if(rtype2.compare("") && rtype2.compare(rtype1)!=0) {
        fprintf(stdout,"%s => count:%lld\tsize:%lld\n",rtype2.c_str(),
            (long long)c,(long long)s2);
        c=1;
        s2=s1;
854 855 856
        rtype2 = rtype1;
      } else {
        c++;
857 858
        s2+=s1;
        rtype2=rtype1;
859 860
    }
  }
861

862
    if (!count_only_ && !count_delim_) {
863 864 865
      string key = ikey.DebugString(is_key_hex_);
      string value = iter->value().ToString(is_value_hex_);
      std::cout << key << " => " << value << "\n";
866 867 868
    }

    // Terminate if maximum number of keys have been dumped
869
    if (max_keys_ > 0 && count >= max_keys_) break;
870
  }
871 872 873
  if(count_delim_) {
    fprintf(stdout,"%s => count:%lld\tsize:%lld\n", rtype2.c_str(),
        (long long)c,(long long)s2);
874
  } else
875
  fprintf(stdout, "Internal keys in range: %lld\n", (long long) count);
876 877 878
}


879 880 881 882
const string DBDumperCommand::ARG_COUNT_ONLY = "count_only";
const string DBDumperCommand::ARG_COUNT_DELIM = "count_delim";
const string DBDumperCommand::ARG_STATS = "stats";
const string DBDumperCommand::ARG_TTL_BUCKET = "bucket";
883

884 885
DBDumperCommand::DBDumperCommand(const vector<string>& params,
      const map<string, string>& options, const vector<string>& flags) :
886
    LDBCommand(options, flags, true,
887 888 889 890 891 892
               BuildCmdLineOptions({ARG_TTL, ARG_HEX, ARG_KEY_HEX,
                                    ARG_VALUE_HEX, ARG_FROM, ARG_TO,
                                    ARG_MAX_KEYS, ARG_COUNT_ONLY,
                                    ARG_COUNT_DELIM, ARG_STATS, ARG_TTL_START,
                                    ARG_TTL_END, ARG_TTL_BUCKET,
                                    ARG_TIMESTAMP})),
893 894 895 896
    null_from_(true),
    null_to_(true),
    max_keys_(-1),
    count_only_(false),
897
    count_delim_(false),
898 899
    print_stats_(false) {

900
  map<string, string>::const_iterator itr = options.find(ARG_FROM);
901 902 903 904 905 906 907 908 909 910 911 912 913 914
  if (itr != options.end()) {
    null_from_ = false;
    from_ = itr->second;
  }

  itr = options.find(ARG_TO);
  if (itr != options.end()) {
    null_to_ = false;
    to_ = itr->second;
  }

  itr = options.find(ARG_MAX_KEYS);
  if (itr != options.end()) {
    try {
S
sdong 已提交
915 916 917
#if defined(CYGWIN)
      max_keys_ = strtol(itr->second.c_str(), 0, 10);
#else
M
Mayank Agarwal 已提交
918
      max_keys_ = stoi(itr->second);
S
sdong 已提交
919
#endif
920
    } catch(const invalid_argument&) {
921
      exec_state_ = LDBCommandExecuteResult::Failed(ARG_MAX_KEYS +
922
                                                    " has an invalid value");
923
    } catch(const out_of_range&) {
924 925
      exec_state_ = LDBCommandExecuteResult::Failed(
          ARG_MAX_KEYS + " has a value out-of-range");
926 927
    }
  }
928 929 930 931 932 933
  itr = options.find(ARG_COUNT_DELIM);
  if (itr != options.end()) {
    delim_ = itr->second;
    count_delim_ = true;
  } else {
    count_delim_ = IsFlagPresent(flags, ARG_COUNT_DELIM);
934
    delim_=".";
935
  }
936

937 938 939 940
  print_stats_ = IsFlagPresent(flags, ARG_STATS);
  count_only_ = IsFlagPresent(flags, ARG_COUNT_ONLY);

  if (is_key_hex_) {
941 942 943 944 945 946 947 948 949
    if (!null_from_) {
      from_ = HexToString(from_);
    }
    if (!null_to_) {
      to_ = HexToString(to_);
    }
  }
}

950 951 952 953 954 955 956 957 958 959 960 961 962 963
void DBDumperCommand::Help(string& ret) {
  ret.append("  ");
  ret.append(DBDumperCommand::Name());
  ret.append(HelpRangeCmdArgs());
  ret.append(" [--" + ARG_TTL + "]");
  ret.append(" [--" + ARG_MAX_KEYS + "=<N>]");
  ret.append(" [--" + ARG_TIMESTAMP + "]");
  ret.append(" [--" + ARG_COUNT_ONLY + "]");
  ret.append(" [--" + ARG_COUNT_DELIM + "=<char>]");
  ret.append(" [--" + ARG_STATS + "]");
  ret.append(" [--" + ARG_TTL_BUCKET + "=<N>]");
  ret.append(" [--" + ARG_TTL_START + "=<N>:- is inclusive]");
  ret.append(" [--" + ARG_TTL_END + "=<N>:- is exclusive]");
  ret.append("\n");
964 965
}

966
void DBDumperCommand::DoCommand() {
967 968 969
  if (!db_) {
    return;
  }
970 971 972
  // Parse command line args
  uint64_t count = 0;
  if (print_stats_) {
973
    string stats;
974
    if (db_->GetProperty("rocksdb.stats", &stats)) {
975 976 977 978 979
      fprintf(stdout, "%s\n", stats.c_str());
    }
  }

  // Setup key iterator
980 981
  Iterator* iter = db_->NewIterator(ReadOptions());
  Status st = iter->status();
982
  if (!st.ok()) {
983 984
    exec_state_ =
        LDBCommandExecuteResult::Failed("Iterator error." + st.ToString());
985 986 987 988 989 990 991 992 993
  }

  if (!null_from_) {
    iter->Seek(from_);
  } else {
    iter->SeekToFirst();
  }

  int max_keys = max_keys_;
994
  int ttl_start;
995
  if (!ParseIntOption(option_map_, ARG_TTL_START, ttl_start, exec_state_)) {
996
    ttl_start = DBWithTTLImpl::kMinTimestamp;  // TTL introduction time
997 998
  }
  int ttl_end;
999
  if (!ParseIntOption(option_map_, ARG_TTL_END, ttl_end, exec_state_)) {
1000
    ttl_end = DBWithTTLImpl::kMaxTimestamp;  // Max time allowed by TTL feature
1001 1002 1003 1004 1005 1006 1007 1008
  }
  if (ttl_end < ttl_start) {
    fprintf(stderr, "Error: End time can't be less than start time\n");
    delete iter;
    return;
  }
  int time_range = ttl_end - ttl_start;
  int bucket_size;
1009
  if (!ParseIntOption(option_map_, ARG_TTL_BUCKET, bucket_size, exec_state_) ||
1010 1011 1012
      bucket_size <= 0) {
    bucket_size = time_range; // Will have just 1 bucket by default
  }
1013
  //cretaing variables for row count of each type
1014
  string rtype1,rtype2,row,val;
1015
  rtype2 = "";
1016 1017
  uint64_t c=0;
  uint64_t s1=0,s2=0;
1018

1019
  // At this point, bucket_size=0 => time_range=0
1020 1021 1022
  int num_buckets = (bucket_size >= time_range)
                        ? 1
                        : ((time_range + bucket_size - 1) / bucket_size);
1023
  vector<uint64_t> bucket_counts(num_buckets, 0);
1024
  if (is_db_ttl_ && !count_only_ && timestamp_ && !count_delim_) {
1025 1026 1027 1028
    fprintf(stdout, "Dumping key-values from %s to %s\n",
            ReadableTime(ttl_start).c_str(), ReadableTime(ttl_end).c_str());
  }

1029
  for (; iter->Valid(); iter->Next()) {
1030
    int rawtime = 0;
1031 1032 1033 1034 1035 1036
    // If end marker was specified, we stop before it
    if (!null_to_ && (iter->key().ToString() >= to_))
      break;
    // Terminate if maximum number of keys have been dumped
    if (max_keys == 0)
      break;
1037
    if (is_db_ttl_) {
1038 1039
      TtlIterator* it_ttl = dynamic_cast<TtlIterator*>(iter);
      assert(it_ttl);
1040 1041
      rawtime = it_ttl->timestamp();
      if (rawtime < ttl_start || rawtime >= ttl_end) {
1042 1043 1044
        continue;
      }
    }
1045 1046 1047
    if (max_keys > 0) {
      --max_keys;
    }
1048
    if (is_db_ttl_ && num_buckets > 1) {
1049
      IncBucketCounts(bucket_counts, ttl_start, time_range, bucket_size,
1050 1051
                      rawtime, num_buckets);
    }
1052
    ++count;
1053 1054 1055 1056 1057
    if (count_delim_) {
      rtype1 = "";
      row = iter->key().ToString();
      val = iter->value().ToString();
      s1 = row.size()+val.size();
1058 1059 1060 1061 1062 1063 1064
      for(int j=0;row[j]!=delim_[0] && row[j]!='\0';j++)
        rtype1+=row[j];
      if(rtype2.compare("") && rtype2.compare(rtype1)!=0) {
        fprintf(stdout,"%s => count:%lld\tsize:%lld\n",rtype2.c_str(),
            (long long )c,(long long)s2);
        c=1;
        s2=s1;
1065 1066
        rtype2 = rtype1;
      } else {
1067 1068 1069
          c++;
          s2+=s1;
          rtype2=rtype1;
1070
      }
1071

1072 1073
    }

1074 1075


1076
    if (!count_only_ && !count_delim_) {
1077 1078 1079
      if (is_db_ttl_ && timestamp_) {
        fprintf(stdout, "%s ", ReadableTime(rawtime).c_str());
      }
1080
      string str = PrintKeyValue(iter->key().ToString(),
1081 1082
                                 iter->value().ToString(), is_key_hex_,
                                 is_value_hex_);
1083
      fprintf(stdout, "%s\n", str.c_str());
1084 1085
    }
  }
1086

1087
  if (num_buckets > 1 && is_db_ttl_) {
1088
    PrintBucketCounts(bucket_counts, ttl_start, ttl_end, bucket_size,
1089
                      num_buckets);
1090 1091 1092
  } else if(count_delim_) {
    fprintf(stdout,"%s => count:%lld\tsize:%lld\n",rtype2.c_str(),
        (long long )c,(long long)s2);
1093
  } else {
1094
    fprintf(stdout, "Keys in range: %lld\n", (long long) count);
1095
  }
1096 1097 1098 1099
  // Clean up
  delete iter;
}

1100 1101
const string ReduceDBLevelsCommand::ARG_NEW_LEVELS = "new_levels";
const string  ReduceDBLevelsCommand::ARG_PRINT_OLD_LEVELS = "print_old_levels";
1102

1103 1104
ReduceDBLevelsCommand::ReduceDBLevelsCommand(const vector<string>& params,
      const map<string, string>& options, const vector<string>& flags) :
1105 1106
    LDBCommand(options, flags, false,
               BuildCmdLineOptions({ARG_NEW_LEVELS, ARG_PRINT_OLD_LEVELS})),
I
Igor Canadi 已提交
1107
    old_levels_(1 << 7),
1108 1109
    new_levels_(-1),
    print_old_levels_(false) {
1110 1111


1112
  ParseIntOption(option_map_, ARG_NEW_LEVELS, new_levels_, exec_state_);
1113
  print_old_levels_ = IsFlagPresent(flags, ARG_PRINT_OLD_LEVELS);
1114

1115
  if(new_levels_ <= 0) {
1116
    exec_state_ = LDBCommandExecuteResult::Failed(
1117
        " Use --" + ARG_NEW_LEVELS + " to specify a new level number\n");
1118 1119 1120
  }
}

1121
vector<string> ReduceDBLevelsCommand::PrepareArgs(const string& db_path,
1122
    int new_levels, bool print_old_level) {
1123
  vector<string> ret;
1124
  ret.push_back("reduce_levels");
1125
  ret.push_back("--" + ARG_DB + "=" + db_path);
S
sdong 已提交
1126
  ret.push_back("--" + ARG_NEW_LEVELS + "=" + rocksdb::ToString(new_levels));
1127
  if(print_old_level) {
1128
    ret.push_back("--" + ARG_PRINT_OLD_LEVELS);
1129 1130 1131 1132
  }
  return ret;
}

1133 1134 1135 1136 1137 1138
void ReduceDBLevelsCommand::Help(string& ret) {
  ret.append("  ");
  ret.append(ReduceDBLevelsCommand::Name());
  ret.append(" --" + ARG_NEW_LEVELS + "=<New number of levels>");
  ret.append(" [--" + ARG_PRINT_OLD_LEVELS + "]");
  ret.append("\n");
1139 1140
}

1141 1142
Options ReduceDBLevelsCommand::PrepareOptionsForOpenDB() {
  Options opt = LDBCommand::PrepareOptionsForOpenDB();
1143
  opt.num_levels = old_levels_;
1144
  opt.max_bytes_for_level_multiplier_additional.resize(opt.num_levels, 1);
1145
  // Disable size compaction
I
Igor Canadi 已提交
1146
  opt.max_bytes_for_level_base = 1ULL << 50;
1147
  opt.max_bytes_for_level_multiplier = 1;
1148 1149 1150
  return opt;
}

1151
Status ReduceDBLevelsCommand::GetOldNumOfLevels(Options& opt,
1152
    int* levels) {
H
Haobo Xu 已提交
1153
  EnvOptions soptions;
I
Igor Canadi 已提交
1154
  std::shared_ptr<Cache> tc(
1155
      NewLRUCache(opt.max_open_files - 10, opt.table_cache_numshardbits));
1156
  const InternalKeyComparator cmp(opt.comparator);
S
sdong 已提交
1157
  WriteController wc(opt.delayed_write_rate);
1158 1159
  WriteBuffer wb(opt.db_write_buffer_size);
  VersionSet versions(db_path_, &opt, soptions, tc.get(), &wb, &wc);
I
Igor Canadi 已提交
1160
  std::vector<ColumnFamilyDescriptor> dummy;
1161
  ColumnFamilyDescriptor dummy_descriptor(kDefaultColumnFamilyName,
I
Igor Canadi 已提交
1162 1163
                                          ColumnFamilyOptions(opt));
  dummy.push_back(dummy_descriptor);
1164 1165 1166
  // We rely the VersionSet::Recover to tell us the internal data structures
  // in the db. And the Recover() should never do any change
  // (like LogAndApply) to the manifest file.
I
Igor Canadi 已提交
1167
  Status st = versions.Recover(dummy);
1168 1169 1170 1171
  if (!st.ok()) {
    return st;
  }
  int max = -1;
1172
  auto default_cfd = versions.GetColumnFamilySet()->GetDefault();
I
Igor Canadi 已提交
1173
  for (int i = 0; i < default_cfd->NumberLevels(); i++) {
S
sdong 已提交
1174
    if (default_cfd->current()->storage_info()->NumLevelFiles(i)) {
1175 1176 1177 1178 1179 1180 1181 1182
      max = i;
    }
  }

  *levels = max + 1;
  return st;
}

1183
void ReduceDBLevelsCommand::DoCommand() {
1184
  if (new_levels_ <= 1) {
1185 1186
    exec_state_ =
        LDBCommandExecuteResult::Failed("Invalid number of levels.\n");
1187 1188 1189
    return;
  }

1190 1191
  Status st;
  Options opt = PrepareOptionsForOpenDB();
1192 1193 1194
  int old_level_num = -1;
  st = GetOldNumOfLevels(opt, &old_level_num);
  if (!st.ok()) {
1195
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
1196 1197 1198
    return;
  }

1199
  if (print_old_levels_) {
1200
    fprintf(stdout, "The old number of levels in use is %d\n", old_level_num);
1201
  }
1202

1203 1204
  if (old_level_num <= new_levels_) {
    return;
1205 1206
  }

1207 1208 1209
  old_levels_ = old_level_num;

  OpenDB();
1210 1211 1212
  if (!db_) {
    return;
  }
1213
  // Compact the whole DB to put all files to the highest level.
1214
  fprintf(stdout, "Compacting the db...\n");
1215
  db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
1216 1217
  CloseDB();

H
Haobo Xu 已提交
1218
  EnvOptions soptions;
1219
  st = VersionSet::ReduceNumberOfLevels(db_path_, &opt, soptions, new_levels_);
1220
  if (!st.ok()) {
1221
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
1222 1223 1224 1225
    return;
  }
}

1226
const string ChangeCompactionStyleCommand::ARG_OLD_COMPACTION_STYLE =
1227
  "old_compaction_style";
1228
const string ChangeCompactionStyleCommand::ARG_NEW_COMPACTION_STYLE =
1229 1230 1231
  "new_compaction_style";

ChangeCompactionStyleCommand::ChangeCompactionStyleCommand(
1232 1233
      const vector<string>& params, const map<string, string>& options,
      const vector<string>& flags) :
1234 1235 1236 1237 1238 1239
    LDBCommand(options, flags, false,
               BuildCmdLineOptions({ARG_OLD_COMPACTION_STYLE,
                                    ARG_NEW_COMPACTION_STYLE})),
    old_compaction_style_(-1),
    new_compaction_style_(-1) {

1240 1241
  ParseIntOption(option_map_, ARG_OLD_COMPACTION_STYLE, old_compaction_style_,
    exec_state_);
1242 1243
  if (old_compaction_style_ != kCompactionStyleLevel &&
     old_compaction_style_ != kCompactionStyleUniversal) {
1244
    exec_state_ = LDBCommandExecuteResult::Failed(
1245 1246
        "Use --" + ARG_OLD_COMPACTION_STYLE + " to specify old compaction " +
        "style. Check ldb help for proper compaction style value.\n");
1247 1248 1249
    return;
  }

1250 1251
  ParseIntOption(option_map_, ARG_NEW_COMPACTION_STYLE, new_compaction_style_,
    exec_state_);
1252 1253
  if (new_compaction_style_ != kCompactionStyleLevel &&
     new_compaction_style_ != kCompactionStyleUniversal) {
1254
    exec_state_ = LDBCommandExecuteResult::Failed(
1255 1256
        "Use --" + ARG_NEW_COMPACTION_STYLE + " to specify new compaction " +
        "style. Check ldb help for proper compaction style value.\n");
1257 1258 1259 1260
    return;
  }

  if (new_compaction_style_ == old_compaction_style_) {
1261
    exec_state_ = LDBCommandExecuteResult::Failed(
1262 1263
        "Old compaction style is the same as new compaction style. "
        "Nothing to do.\n");
1264 1265 1266 1267 1268
    return;
  }

  if (old_compaction_style_ == kCompactionStyleUniversal &&
      new_compaction_style_ == kCompactionStyleLevel) {
1269
    exec_state_ = LDBCommandExecuteResult::Failed(
1270 1271
        "Convert from universal compaction to level compaction. "
        "Nothing to do.\n");
1272 1273 1274 1275
    return;
  }
}

1276 1277 1278 1279 1280 1281 1282 1283
void ChangeCompactionStyleCommand::Help(string& ret) {
  ret.append("  ");
  ret.append(ChangeCompactionStyleCommand::Name());
  ret.append(" --" + ARG_OLD_COMPACTION_STYLE + "=<Old compaction style: 0 " +
             "for level compaction, 1 for universal compaction>");
  ret.append(" --" + ARG_NEW_COMPACTION_STYLE + "=<New compaction style: 0 " +
             "for level compaction, 1 for universal compaction>");
  ret.append("\n");
1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307
}

Options ChangeCompactionStyleCommand::PrepareOptionsForOpenDB() {
  Options opt = LDBCommand::PrepareOptionsForOpenDB();

  if (old_compaction_style_ == kCompactionStyleLevel &&
      new_compaction_style_ == kCompactionStyleUniversal) {
    // In order to convert from level compaction to universal compaction, we
    // need to compact all data into a single file and move it to level 0.
    opt.disable_auto_compactions = true;
    opt.target_file_size_base = INT_MAX;
    opt.target_file_size_multiplier = 1;
    opt.max_bytes_for_level_base = INT_MAX;
    opt.max_bytes_for_level_multiplier = 1;
  }

  return opt;
}

void ChangeCompactionStyleCommand::DoCommand() {
  // print db stats before we have made any change
  std::string property;
  std::string files_per_level;
  for (int i = 0; i < db_->NumberLevels(); i++) {
1308
    db_->GetProperty("rocksdb.num-files-at-level" + NumberToString(i),
1309 1310
                     &property);

1311
    // format print string
1312
    char buf[100];
1313
    snprintf(buf, sizeof(buf), "%s%s", (i ? "," : ""), property.c_str());
1314 1315 1316 1317 1318 1319
    files_per_level += buf;
  }
  fprintf(stdout, "files per level before compaction: %s\n",
          files_per_level.c_str());

  // manual compact into a single file and move the file to level 0
1320 1321 1322 1323
  CompactRangeOptions compact_options;
  compact_options.change_level = true;
  compact_options.target_level = 0;
  db_->CompactRange(compact_options, nullptr, nullptr);
1324 1325 1326 1327 1328

  // verify compaction result
  files_per_level = "";
  int num_files = 0;
  for (int i = 0; i < db_->NumberLevels(); i++) {
1329
    db_->GetProperty("rocksdb.num-files-at-level" + NumberToString(i),
1330 1331
                     &property);

1332
    // format print string
1333
    char buf[100];
1334
    snprintf(buf, sizeof(buf), "%s%s", (i ? "," : ""), property.c_str());
1335 1336 1337 1338 1339 1340
    files_per_level += buf;

    num_files = atoi(property.c_str());

    // level 0 should have only 1 file
    if (i == 0 && num_files != 1) {
1341 1342 1343 1344
      exec_state_ = LDBCommandExecuteResult::Failed(
          "Number of db files at "
          "level 0 after compaction is " +
          ToString(num_files) + ", not 1.\n");
1345 1346 1347 1348
      return;
    }
    // other levels should have no file
    if (i > 0 && num_files != 0) {
1349 1350 1351 1352 1353
      exec_state_ = LDBCommandExecuteResult::Failed(
          "Number of db files at "
          "level " +
          ToString(i) + " after compaction is " + ToString(num_files) +
          ", not 0.\n");
1354 1355 1356 1357 1358 1359 1360 1361
      return;
    }
  }

  fprintf(stdout, "files per level after compaction: %s\n",
          files_per_level.c_str());
}

1362 1363 1364 1365 1366
// ----------------------------------------------------------------------------

namespace {

struct StdErrReporter : public log::Reader::Reporter {
I
Igor Sugak 已提交
1367
  virtual void Corruption(size_t bytes, const Status& s) override {
1368 1369 1370 1371
    cerr << "Corruption detected in log file " << s.ToString() << "\n";
  }
};

1372 1373
class InMemoryHandler : public WriteBatch::Handler {
 public:
1374
  InMemoryHandler(stringstream& row, bool print_values) : Handler(), row_(row) {
1375 1376
    print_values_ = print_values;
  }
1377

1378
  void commonPutMerge(const Slice& key, const Slice& value) {
1379
    string k = LDBCommand::StringToHex(key.ToString());
1380
    if (print_values_) {
1381
      string v = LDBCommand::StringToHex(value.ToString());
1382 1383 1384 1385 1386
      row_ << k << " : ";
      row_ << v << " ";
    } else {
      row_ << k << " ";
    }
1387
  }
1388

I
Igor Sugak 已提交
1389
  virtual void Put(const Slice& key, const Slice& value) override {
1390 1391
    row_ << "PUT : ";
    commonPutMerge(key, value);
1392 1393
  }

I
Igor Sugak 已提交
1394
  virtual void Merge(const Slice& key, const Slice& value) override {
1395 1396
    row_ << "MERGE : ";
    commonPutMerge(key, value);
1397
  }
1398

I
Igor Sugak 已提交
1399
  virtual void Delete(const Slice& key) override {
1400
    row_ <<",DELETE : ";
1401
    row_ << LDBCommand::StringToHex(key.ToString()) << " ";
1402 1403
  }

1404
  virtual ~InMemoryHandler() {}
1405

1406
 private:
1407
  stringstream & row_;
1408
  bool print_values_;
1409 1410
};

1411 1412 1413 1414
void DumpWalFile(std::string wal_file, bool print_header, bool print_values,
                 LDBCommandExecuteResult* exec_state) {
  Env* env_ = Env::Default();
  EnvOptions soptions;
1415 1416 1417 1418 1419 1420 1421 1422 1423 1424
  unique_ptr<SequentialFileReader> wal_file_reader;

  Status status;
  {
    unique_ptr<SequentialFile> file;
    status = env_->NewSequentialFile(wal_file, &file, soptions);
    if (status.ok()) {
      wal_file_reader.reset(new SequentialFileReader(std::move(file)));
    }
  }
1425 1426
  if (!status.ok()) {
    if (exec_state) {
1427
      *exec_state = LDBCommandExecuteResult::Failed("Failed to open WAL file " +
1428 1429 1430 1431 1432 1433 1434
                                                    status.ToString());
    } else {
      cerr << "Error: Failed to open WAL file " << status.ToString()
           << std::endl;
    }
  } else {
    StdErrReporter reporter;
1435
    log::Reader reader(move(wal_file_reader), &reporter, true, 0);
1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468
    string scratch;
    WriteBatch batch;
    Slice record;
    stringstream row;
    if (print_header) {
      cout << "Sequence,Count,ByteSize,Physical Offset,Key(s)";
      if (print_values) {
        cout << " : value ";
      }
      cout << "\n";
    }
    while (reader.ReadRecord(&record, &scratch)) {
      row.str("");
      if (record.size() < 12) {
        reporter.Corruption(record.size(),
                            Status::Corruption("log record too small"));
      } else {
        WriteBatchInternal::SetContents(&batch, record);
        row << WriteBatchInternal::Sequence(&batch) << ",";
        row << WriteBatchInternal::Count(&batch) << ",";
        row << WriteBatchInternal::ByteSize(&batch) << ",";
        row << reader.LastRecordOffset() << ",";
        InMemoryHandler handler(row, print_values);
        batch.Iterate(&handler);
        row << "\n";
      }
      cout << row.str();
    }
  }
}

}  // namespace

1469 1470 1471
const string WALDumperCommand::ARG_WAL_FILE = "walfile";
const string WALDumperCommand::ARG_PRINT_VALUE = "print_value";
const string WALDumperCommand::ARG_PRINT_HEADER = "header";
1472

1473 1474
WALDumperCommand::WALDumperCommand(const vector<string>& params,
      const map<string, string>& options, const vector<string>& flags) :
1475
    LDBCommand(options, flags, true,
1476 1477 1478
               BuildCmdLineOptions(
                {ARG_WAL_FILE, ARG_PRINT_HEADER, ARG_PRINT_VALUE})),
    print_header_(false), print_values_(false) {
1479

A
Abhishek Kona 已提交
1480
  wal_file_.clear();
1481

1482
  map<string, string>::const_iterator itr = options.find(ARG_WAL_FILE);
1483 1484
  if (itr != options.end()) {
    wal_file_ = itr->second;
A
Abhishek Kona 已提交
1485
  }
1486 1487


1488 1489
  print_header_ = IsFlagPresent(flags, ARG_PRINT_HEADER);
  print_values_ = IsFlagPresent(flags, ARG_PRINT_VALUE);
A
Abhishek Kona 已提交
1490
  if (wal_file_.empty()) {
1491 1492
    exec_state_ = LDBCommandExecuteResult::Failed("Argument " + ARG_WAL_FILE +
                                                  " must be specified.");
A
Abhishek Kona 已提交
1493 1494 1495
  }
}

1496 1497 1498 1499 1500 1501 1502
void WALDumperCommand::Help(string& ret) {
  ret.append("  ");
  ret.append(WALDumperCommand::Name());
  ret.append(" --" + ARG_WAL_FILE + "=<write_ahead_log_file_path>");
  ret.append(" [--" + ARG_PRINT_HEADER + "] ");
  ret.append(" [--" + ARG_PRINT_VALUE + "] ");
  ret.append("\n");
A
Abhishek Kona 已提交
1503 1504
}

1505
void WALDumperCommand::DoCommand() {
1506
  DumpWalFile(wal_file_, print_header_, print_values_, &exec_state_);
A
Abhishek Kona 已提交
1507 1508
}

1509
// ----------------------------------------------------------------------------
1510

1511 1512
GetCommand::GetCommand(const vector<string>& params,
      const map<string, string>& options, const vector<string>& flags) :
1513 1514 1515
  LDBCommand(options, flags, true, BuildCmdLineOptions({ARG_TTL, ARG_HEX,
                                                        ARG_KEY_HEX,
                                                        ARG_VALUE_HEX})) {
1516 1517

  if (params.size() != 1) {
1518
    exec_state_ = LDBCommandExecuteResult::Failed(
1519
        "<key> must be specified for the get command");
1520 1521 1522 1523 1524 1525 1526 1527 1528
  } else {
    key_ = params.at(0);
  }

  if (is_key_hex_) {
    key_ = HexToString(key_);
  }
}

1529 1530 1531 1532 1533 1534
void GetCommand::Help(string& ret) {
  ret.append("  ");
  ret.append(GetCommand::Name());
  ret.append(" <key>");
  ret.append(" [--" + ARG_TTL + "]");
  ret.append("\n");
1535 1536 1537
}

void GetCommand::DoCommand() {
1538
  string value;
1539
  Status st = db_->Get(ReadOptions(), key_, &value);
1540 1541 1542 1543
  if (st.ok()) {
    fprintf(stdout, "%s\n",
              (is_value_hex_ ? StringToHex(value) : value).c_str());
  } else {
1544
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
1545 1546 1547
  }
}

1548
// ----------------------------------------------------------------------------
1549

1550 1551
ApproxSizeCommand::ApproxSizeCommand(const vector<string>& params,
      const map<string, string>& options, const vector<string>& flags) :
1552 1553 1554 1555 1556 1557 1558
  LDBCommand(options, flags, true,
             BuildCmdLineOptions({ARG_HEX, ARG_KEY_HEX, ARG_VALUE_HEX,
                                  ARG_FROM, ARG_TO})) {

  if (options.find(ARG_FROM) != options.end()) {
    start_key_ = options.find(ARG_FROM)->second;
  } else {
1559 1560
    exec_state_ = LDBCommandExecuteResult::Failed(
        ARG_FROM + " must be specified for approxsize command");
1561 1562 1563 1564 1565 1566
    return;
  }

  if (options.find(ARG_TO) != options.end()) {
    end_key_ = options.find(ARG_TO)->second;
  } else {
1567 1568
    exec_state_ = LDBCommandExecuteResult::Failed(
        ARG_TO + " must be specified for approxsize command");
1569 1570 1571 1572 1573 1574 1575 1576 1577
    return;
  }

  if (is_key_hex_) {
    start_key_ = HexToString(start_key_);
    end_key_ = HexToString(end_key_);
  }
}

1578 1579 1580 1581 1582
void ApproxSizeCommand::Help(string& ret) {
  ret.append("  ");
  ret.append(ApproxSizeCommand::Name());
  ret.append(HelpRangeCmdArgs());
  ret.append("\n");
1583 1584 1585 1586
}

void ApproxSizeCommand::DoCommand() {

1587 1588
  Range ranges[1];
  ranges[0] = Range(start_key_, end_key_);
1589 1590
  uint64_t sizes[1];
  db_->GetApproximateSizes(ranges, 1, sizes);
K
Kai Liu 已提交
1591
  fprintf(stdout, "%lu\n", (unsigned long)sizes[0]);
1592
  /* Weird that GetApproximateSizes() returns void, although documentation
1593 1594
   * says that it returns a Status object.
  if (!st.ok()) {
1595
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
1596 1597 1598 1599
  }
  */
}

1600
// ----------------------------------------------------------------------------
1601

1602 1603 1604 1605 1606
BatchPutCommand::BatchPutCommand(const vector<string>& params,
      const map<string, string>& options, const vector<string>& flags) :
  LDBCommand(options, flags, false,
             BuildCmdLineOptions({ARG_TTL, ARG_HEX, ARG_KEY_HEX, ARG_VALUE_HEX,
                                  ARG_CREATE_IF_MISSING})) {
1607 1608

  if (params.size() < 2) {
1609
    exec_state_ = LDBCommandExecuteResult::Failed(
1610
        "At least one <key> <value> pair must be specified batchput.");
1611
  } else if (params.size() % 2 != 0) {
1612
    exec_state_ = LDBCommandExecuteResult::Failed(
1613 1614 1615
        "Equal number of <key>s and <value>s must be specified for batchput.");
  } else {
    for (size_t i = 0; i < params.size(); i += 2) {
1616 1617 1618
      string key = params.at(i);
      string value = params.at(i+1);
      key_values_.push_back(pair<string, string>(
1619 1620 1621 1622 1623 1624
                    is_key_hex_ ? HexToString(key) : key,
                    is_value_hex_ ? HexToString(value) : value));
    }
  }
}

1625 1626 1627 1628 1629 1630
void BatchPutCommand::Help(string& ret) {
  ret.append("  ");
  ret.append(BatchPutCommand::Name());
  ret.append(" <key> <value> [<key> <value>] [..]");
  ret.append(" [--" + ARG_TTL + "]");
  ret.append("\n");
1631 1632 1633
}

void BatchPutCommand::DoCommand() {
1634
  WriteBatch batch;
1635

1636
  for (vector<pair<string, string>>::const_iterator itr
1637
        = key_values_.begin(); itr != key_values_.end(); ++itr) {
1638
      batch.Put(itr->first, itr->second);
1639
  }
1640
  Status st = db_->Write(WriteOptions(), &batch);
1641 1642 1643
  if (st.ok()) {
    fprintf(stdout, "OK\n");
  } else {
1644
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
1645 1646 1647
  }
}

1648 1649
Options BatchPutCommand::PrepareOptionsForOpenDB() {
  Options opt = LDBCommand::PrepareOptionsForOpenDB();
1650 1651 1652 1653
  opt.create_if_missing = IsFlagPresent(flags_, ARG_CREATE_IF_MISSING);
  return opt;
}

1654
// ----------------------------------------------------------------------------
1655

1656 1657
ScanCommand::ScanCommand(const vector<string>& params,
      const map<string, string>& options, const vector<string>& flags) :
1658
    LDBCommand(options, flags, true,
1659 1660 1661
               BuildCmdLineOptions({ARG_TTL, ARG_HEX, ARG_KEY_HEX, ARG_TO,
                                    ARG_VALUE_HEX, ARG_FROM, ARG_TIMESTAMP,
                                    ARG_MAX_KEYS, ARG_TTL_START, ARG_TTL_END})),
1662 1663 1664 1665
    start_key_specified_(false),
    end_key_specified_(false),
    max_keys_scanned_(-1) {

1666
  map<string, string>::const_iterator itr = options.find(ARG_FROM);
1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685
  if (itr != options.end()) {
    start_key_ = itr->second;
    if (is_key_hex_) {
      start_key_ = HexToString(start_key_);
    }
    start_key_specified_ = true;
  }
  itr = options.find(ARG_TO);
  if (itr != options.end()) {
    end_key_ = itr->second;
    if (is_key_hex_) {
      end_key_ = HexToString(end_key_);
    }
    end_key_specified_ = true;
  }

  itr = options.find(ARG_MAX_KEYS);
  if (itr != options.end()) {
    try {
S
sdong 已提交
1686 1687 1688
#if defined(CYGWIN)
      max_keys_scanned_ = strtol(itr->second.c_str(), 0, 10);
#else
M
Mayank Agarwal 已提交
1689
      max_keys_scanned_ = stoi(itr->second);
S
sdong 已提交
1690
#endif
1691
    } catch(const invalid_argument&) {
1692
      exec_state_ = LDBCommandExecuteResult::Failed(ARG_MAX_KEYS +
1693
                                                    " has an invalid value");
1694
    } catch(const out_of_range&) {
1695 1696
      exec_state_ = LDBCommandExecuteResult::Failed(
          ARG_MAX_KEYS + " has a value out-of-range");
1697 1698 1699 1700
    }
  }
}

1701 1702 1703 1704 1705 1706 1707 1708 1709 1710
void ScanCommand::Help(string& ret) {
  ret.append("  ");
  ret.append(ScanCommand::Name());
  ret.append(HelpRangeCmdArgs());
  ret.append(" [--" + ARG_TTL + "]");
  ret.append(" [--" + ARG_TIMESTAMP + "]");
  ret.append(" [--" + ARG_MAX_KEYS + "=<N>q] ");
  ret.append(" [--" + ARG_TTL_START + "=<N>:- is inclusive]");
  ret.append(" [--" + ARG_TTL_END + "=<N>:- is exclusive]");
  ret.append("\n");
1711 1712 1713 1714 1715
}

void ScanCommand::DoCommand() {

  int num_keys_scanned = 0;
1716
  Iterator* it = db_->NewIterator(ReadOptions());
1717 1718 1719 1720 1721
  if (start_key_specified_) {
    it->Seek(start_key_);
  } else {
    it->SeekToFirst();
  }
1722
  int ttl_start;
1723
  if (!ParseIntOption(option_map_, ARG_TTL_START, ttl_start, exec_state_)) {
1724
    ttl_start = DBWithTTLImpl::kMinTimestamp;  // TTL introduction time
1725 1726
  }
  int ttl_end;
1727
  if (!ParseIntOption(option_map_, ARG_TTL_END, ttl_end, exec_state_)) {
1728
    ttl_end = DBWithTTLImpl::kMaxTimestamp;  // Max time allowed by TTL feature
1729 1730 1731 1732 1733 1734 1735 1736 1737 1738
  }
  if (ttl_end < ttl_start) {
    fprintf(stderr, "Error: End time can't be less than start time\n");
    delete it;
    return;
  }
  if (is_db_ttl_ && timestamp_) {
    fprintf(stdout, "Scanning key-values from %s to %s\n",
            ReadableTime(ttl_start).c_str(), ReadableTime(ttl_end).c_str());
  }
1739
  for ( ;
1740 1741 1742
        it->Valid() && (!end_key_specified_ || it->key().ToString() < end_key_);
        it->Next()) {
    string key = ldb_options_.key_formatter->Format(it->key());
1743
    if (is_db_ttl_) {
1744 1745
      TtlIterator* it_ttl = dynamic_cast<TtlIterator*>(it);
      assert(it_ttl);
1746 1747
      int rawtime = it_ttl->timestamp();
      if (rawtime < ttl_start || rawtime >= ttl_end) {
1748 1749 1750 1751 1752 1753
        continue;
      }
      if (timestamp_) {
        fprintf(stdout, "%s ", ReadableTime(rawtime).c_str());
      }
    }
1754
    string value = it->value().ToString();
1755
    fprintf(stdout, "%s : %s\n",
1756
            (is_key_hex_ ? "0x" + it->key().ToString(true) : key).c_str(),
1757 1758
            (is_value_hex_ ? StringToHex(value) : value).c_str()
        );
1759 1760 1761 1762 1763 1764
    num_keys_scanned++;
    if (max_keys_scanned_ >= 0 && num_keys_scanned >= max_keys_scanned_) {
      break;
    }
  }
  if (!it->status().ok()) {  // Check for any errors found during the scan
1765
    exec_state_ = LDBCommandExecuteResult::Failed(it->status().ToString());
1766 1767 1768 1769
  }
  delete it;
}

1770
// ----------------------------------------------------------------------------
1771

1772 1773
DeleteCommand::DeleteCommand(const vector<string>& params,
      const map<string, string>& options, const vector<string>& flags) :
1774 1775 1776 1777
  LDBCommand(options, flags, false,
             BuildCmdLineOptions({ARG_HEX, ARG_KEY_HEX, ARG_VALUE_HEX})) {

  if (params.size() != 1) {
1778
    exec_state_ = LDBCommandExecuteResult::Failed(
1779
        "KEY must be specified for the delete command");
1780 1781 1782 1783 1784 1785 1786 1787
  } else {
    key_ = params.at(0);
    if (is_key_hex_) {
      key_ = HexToString(key_);
    }
  }
}

1788 1789 1790 1791
void DeleteCommand::Help(string& ret) {
  ret.append("  ");
  ret.append(DeleteCommand::Name() + " <key>");
  ret.append("\n");
1792 1793 1794
}

void DeleteCommand::DoCommand() {
1795
  Status st = db_->Delete(WriteOptions(), key_);
1796 1797 1798
  if (st.ok()) {
    fprintf(stdout, "OK\n");
  } else {
1799
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
1800 1801 1802 1803
  }
}


1804 1805
PutCommand::PutCommand(const vector<string>& params,
      const map<string, string>& options, const vector<string>& flags) :
1806
  LDBCommand(options, flags, false,
1807
             BuildCmdLineOptions({ARG_TTL, ARG_HEX, ARG_KEY_HEX, ARG_VALUE_HEX,
1808 1809 1810
                                  ARG_CREATE_IF_MISSING})) {

  if (params.size() != 2) {
1811
    exec_state_ = LDBCommandExecuteResult::Failed(
1812
        "<key> and <value> must be specified for the put command");
1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826
  } else {
    key_ = params.at(0);
    value_ = params.at(1);
  }

  if (is_key_hex_) {
    key_ = HexToString(key_);
  }

  if (is_value_hex_) {
    value_ = HexToString(value_);
  }
}

1827 1828 1829 1830 1831 1832
void PutCommand::Help(string& ret) {
  ret.append("  ");
  ret.append(PutCommand::Name());
  ret.append(" <key> <value> ");
  ret.append(" [--" + ARG_TTL + "]");
  ret.append("\n");
1833 1834 1835
}

void PutCommand::DoCommand() {
1836
  Status st = db_->Put(WriteOptions(), key_, value_);
1837 1838 1839
  if (st.ok()) {
    fprintf(stdout, "OK\n");
  } else {
1840
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
1841 1842 1843
  }
}

1844 1845
Options PutCommand::PrepareOptionsForOpenDB() {
  Options opt = LDBCommand::PrepareOptionsForOpenDB();
1846 1847 1848 1849
  opt.create_if_missing = IsFlagPresent(flags_, ARG_CREATE_IF_MISSING);
  return opt;
}

1850
// ----------------------------------------------------------------------------
1851 1852 1853 1854 1855 1856

const char* DBQuerierCommand::HELP_CMD = "help";
const char* DBQuerierCommand::GET_CMD = "get";
const char* DBQuerierCommand::PUT_CMD = "put";
const char* DBQuerierCommand::DELETE_CMD = "delete";

1857 1858
DBQuerierCommand::DBQuerierCommand(const vector<string>& params,
    const map<string, string>& options, const vector<string>& flags) :
1859
  LDBCommand(options, flags, false,
1860 1861
             BuildCmdLineOptions({ARG_TTL, ARG_HEX, ARG_KEY_HEX,
                                  ARG_VALUE_HEX})) {
1862 1863 1864

}

1865 1866 1867 1868 1869 1870
void DBQuerierCommand::Help(string& ret) {
  ret.append("  ");
  ret.append(DBQuerierCommand::Name());
  ret.append(" [--" + ARG_TTL + "]");
  ret.append("\n");
  ret.append("    Starts a REPL shell.  Type help for list of available "
1871
             "commands.");
1872
  ret.append("\n");
1873 1874 1875 1876 1877 1878
}

void DBQuerierCommand::DoCommand() {
  if (!db_) {
    return;
  }
1879

1880 1881
  ReadOptions read_options;
  WriteOptions write_options;
1882

1883 1884 1885 1886 1887 1888 1889
  string line;
  string key;
  string value;
  while (getline(cin, line, '\n')) {

    // Parse line into vector<string>
    vector<string> tokens;
1890 1891 1892
    size_t pos = 0;
    while (true) {
      size_t pos2 = line.find(' ', pos);
1893
      if (pos2 == string::npos) {
1894 1895 1896 1897 1898 1899 1900
        break;
      }
      tokens.push_back(line.substr(pos, pos2-pos));
      pos = pos2 + 1;
    }
    tokens.push_back(line.substr(pos));

1901
    const string& cmd = tokens[0];
1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931

    if (cmd == HELP_CMD) {
      fprintf(stdout,
              "get <key>\n"
              "put <key> <value>\n"
              "delete <key>\n");
    } else if (cmd == DELETE_CMD && tokens.size() == 2) {
      key = (is_key_hex_ ? HexToString(tokens[1]) : tokens[1]);
      db_->Delete(write_options, Slice(key));
      fprintf(stdout, "Successfully deleted %s\n", tokens[1].c_str());
    } else if (cmd == PUT_CMD && tokens.size() == 3) {
      key = (is_key_hex_ ? HexToString(tokens[1]) : tokens[1]);
      value = (is_value_hex_ ? HexToString(tokens[2]) : tokens[2]);
      db_->Put(write_options, Slice(key), Slice(value));
      fprintf(stdout, "Successfully put %s %s\n",
              tokens[1].c_str(), tokens[2].c_str());
    } else if (cmd == GET_CMD && tokens.size() == 2) {
      key = (is_key_hex_ ? HexToString(tokens[1]) : tokens[1]);
      if (db_->Get(read_options, Slice(key), &value).ok()) {
        fprintf(stdout, "%s\n", PrintKeyValue(key, value,
              is_key_hex_, is_value_hex_).c_str());
      } else {
        fprintf(stdout, "Not found %s\n", tokens[1].c_str());
      }
    } else {
      fprintf(stdout, "Unknown command %s\n", line.c_str());
    }
  }
}

1932 1933
// ----------------------------------------------------------------------------

1934 1935
CheckConsistencyCommand::CheckConsistencyCommand(const vector<string>& params,
    const map<string, string>& options, const vector<string>& flags) :
Y
Yiting Li 已提交
1936 1937 1938 1939
  LDBCommand(options, flags, false,
             BuildCmdLineOptions({})) {
}

1940 1941 1942 1943
void CheckConsistencyCommand::Help(string& ret) {
  ret.append("  ");
  ret.append(CheckConsistencyCommand::Name());
  ret.append("\n");
Y
Yiting Li 已提交
1944
}
1945

Y
Yiting Li 已提交
1946 1947
void CheckConsistencyCommand::DoCommand() {
  Options opt = PrepareOptionsForOpenDB();
I
Igor Canadi 已提交
1948
  opt.paranoid_checks = true;
Y
Yiting Li 已提交
1949 1950 1951
  if (!exec_state_.IsNotStarted()) {
    return;
  }
I
Igor Canadi 已提交
1952 1953 1954
  DB* db;
  Status st = DB::OpenForReadOnly(opt, db_path_, &db, false);
  delete db;
Y
Yiting Li 已提交
1955 1956 1957
  if (st.ok()) {
    fprintf(stdout, "OK\n");
  } else {
1958
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
Y
Yiting Li 已提交
1959
  }
1960
}
Y
Yiting Li 已提交
1961

1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041
// ----------------------------------------------------------------------------

namespace {

void DumpSstFile(std::string filename, bool output_hex, bool show_properties) {
  std::string from_key;
  std::string to_key;
  if (filename.length() <= 4 ||
      filename.rfind(".sst") != filename.length() - 4) {
    std::cout << "Invalid sst file name." << std::endl;
    return;
  }
  // no verification
  rocksdb::SstFileReader reader(filename, false, output_hex);
  Status st = reader.ReadSequential(true, -1, false,  // has_from
                                    from_key, false,  // has_to
                                    to_key);
  if (!st.ok()) {
    std::cerr << "Error in reading SST file " << filename << st.ToString()
              << std::endl;
    return;
  }

  if (show_properties) {
    const rocksdb::TableProperties* table_properties;

    std::shared_ptr<const rocksdb::TableProperties>
        table_properties_from_reader;
    st = reader.ReadTableProperties(&table_properties_from_reader);
    if (!st.ok()) {
      std::cerr << filename << ": " << st.ToString()
                << ". Try to use initial table properties" << std::endl;
      table_properties = reader.GetInitTableProperties();
    } else {
      table_properties = table_properties_from_reader.get();
    }
    if (table_properties != nullptr) {
      std::cout << std::endl << "Table Properties:" << std::endl;
      std::cout << table_properties->ToString("\n") << std::endl;
      std::cout << "# deleted keys: "
                << rocksdb::GetDeletedKeys(
                       table_properties->user_collected_properties)
                << std::endl;
    }
  }
}

}  // namespace

DBFileDumperCommand::DBFileDumperCommand(const vector<string>& params,
                                         const map<string, string>& options,
                                         const vector<string>& flags)
    : LDBCommand(options, flags, true, BuildCmdLineOptions({})) {}

void DBFileDumperCommand::Help(string& ret) {
  ret.append("  ");
  ret.append(DBFileDumperCommand::Name());
  ret.append("\n");
}

void DBFileDumperCommand::DoCommand() {
  if (!db_) {
    return;
  }
  Status s;

  std::cout << "Manifest File" << std::endl;
  std::cout << "==============================" << std::endl;
  std::string manifest_filename;
  s = ReadFileToString(db_->GetEnv(), CurrentFileName(db_->GetName()),
                       &manifest_filename);
  if (!s.ok() || manifest_filename.empty() ||
      manifest_filename.back() != '\n') {
    std::cerr << "Error when reading CURRENT file "
              << CurrentFileName(db_->GetName()) << std::endl;
  }
  // remove the trailing '\n'
  manifest_filename.resize(manifest_filename.size() - 1);
  string manifest_filepath = db_->GetName() + "/" + manifest_filename;
  std::cout << manifest_filepath << std::endl;
2042
  DumpManifestFile(manifest_filepath, false, false, false);
2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073
  std::cout << std::endl;

  std::cout << "SST Files" << std::endl;
  std::cout << "==============================" << std::endl;
  std::vector<LiveFileMetaData> metadata;
  db_->GetLiveFilesMetaData(&metadata);
  for (auto& fileMetadata : metadata) {
    std::string filename = fileMetadata.db_path + fileMetadata.name;
    std::cout << filename << " level:" << fileMetadata.level << std::endl;
    std::cout << "------------------------------" << std::endl;
    DumpSstFile(filename, false, true);
    std::cout << std::endl;
  }
  std::cout << std::endl;

  std::cout << "Write Ahead Log Files" << std::endl;
  std::cout << "==============================" << std::endl;
  rocksdb::VectorLogPtr wal_files;
  s = db_->GetSortedWalFiles(wal_files);
  if (!s.ok()) {
    std::cerr << "Error when getting WAL files" << std::endl;
  } else {
    for (auto& wal : wal_files) {
      // TODO(qyang): option.wal_dir should be passed into ldb command
      std::string filename = db_->GetOptions().wal_dir + wal->PathName();
      std::cout << filename << std::endl;
      DumpWalFile(filename, true, true, &exec_state_);
    }
  }
}

Y
Yiting Li 已提交
2074
}   // namespace rocksdb
I
Igor Canadi 已提交
2075
#endif  // ROCKSDB_LITE