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 611
      unsigned int match;
      unsigned long long num;
K
Kai Liu 已提交
612 613 614 615
      if (sscanf(entry->d_name,
                 "MANIFEST-%ln%ln",
                 (unsigned long*)&num,
                 (unsigned long*)&match)
616 617 618 619 620
          && match == strlen(entry->d_name)) {
        if (!found) {
          manifestfile = db_path_ + "/" + std::string(entry->d_name);
          found = true;
        } else {
621
          exec_state_ = LDBCommandExecuteResult::Failed(
622
              "Multiple MANIFEST files found; use --path to select one");
623 624 625 626 627 628 629 630 631 632
          return;
        }
      }
    }
  }

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

633 634
  DumpManifestFile(manifestfile, verbose_, is_key_hex_, json_);

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

// ----------------------------------------------------------------------------
641

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

ListColumnFamiliesCommand::ListColumnFamiliesCommand(
650 651
    const vector<string>& params, const map<string, string>& options,
    const vector<string>& flags)
652 653 654
    : LDBCommand(options, flags, false, {}) {

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

void ListColumnFamiliesCommand::DoCommand() {
663
  vector<string> column_families;
664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682
  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");
  }
}

// ----------------------------------------------------------------------------
683

I
Igor Canadi 已提交
684 685
namespace {

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

// 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
696
void IncBucketCounts(vector<uint64_t>& bucket_counts, int ttl_start,
697 698 699 700
      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;
701
  bucket_counts[bucket]++;
702 703
}

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

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

721 722 723 724
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";
725

726 727 728
InternalDumpCommand::InternalDumpCommand(const vector<string>& params,
                                         const map<string, string>& options,
                                         const vector<string>& flags) :
729
    LDBCommand(options, flags, true,
730 731 732 733
               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})),
734 735 736
    has_from_(false),
    has_to_(false),
    max_keys_(-1),
737
    delim_("."),
738
    count_only_(false),
739
    count_delim_(false),
740 741
    print_stats_(false),
    is_input_key_hex_(false) {
742 743 744 745

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

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

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

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

771 772 773 774 775 776 777 778 779 780
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");
781 782 783 784 785 786 787 788
}

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

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

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

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

822
  long long count = 0;
823 824 825 826 827 828 829 830 831 832 833 834 835 836 837
  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;
838 839 840
    int k;
    if (count_delim_) {
      rtype1 = "";
841
      s1=0;
842 843
      row = iter->key().ToString();
      val = iter->value().ToString();
844
      for(k=0;row[k]!='\x01' && row[k]!='\0';k++)
845
        s1++;
846
      for(k=0;val[k]!='\x01' && val[k]!='\0';k++)
847
        s1++;
848 849 850 851 852 853 854
      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;
855 856 857
        rtype2 = rtype1;
      } else {
        c++;
858 859
        s2+=s1;
        rtype2=rtype1;
860 861
    }
  }
862

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

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


880 881 882 883
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";
884

885 886
DBDumperCommand::DBDumperCommand(const vector<string>& params,
      const map<string, string>& options, const vector<string>& flags) :
887
    LDBCommand(options, flags, true,
888 889 890 891 892 893
               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})),
894 895 896 897
    null_from_(true),
    null_to_(true),
    max_keys_(-1),
    count_only_(false),
898
    count_delim_(false),
899 900
    print_stats_(false) {

901
  map<string, string>::const_iterator itr = options.find(ARG_FROM);
902 903 904 905 906 907 908 909 910 911 912 913 914 915
  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 已提交
916 917 918
#if defined(CYGWIN)
      max_keys_ = strtol(itr->second.c_str(), 0, 10);
#else
M
Mayank Agarwal 已提交
919
      max_keys_ = stoi(itr->second);
S
sdong 已提交
920
#endif
921
    } catch(const invalid_argument&) {
922
      exec_state_ = LDBCommandExecuteResult::Failed(ARG_MAX_KEYS +
923
                                                    " has an invalid value");
924
    } catch(const out_of_range&) {
925 926
      exec_state_ = LDBCommandExecuteResult::Failed(
          ARG_MAX_KEYS + " has a value out-of-range");
927 928
    }
  }
929 930 931 932 933 934
  itr = options.find(ARG_COUNT_DELIM);
  if (itr != options.end()) {
    delim_ = itr->second;
    count_delim_ = true;
  } else {
    count_delim_ = IsFlagPresent(flags, ARG_COUNT_DELIM);
935
    delim_=".";
936
  }
937

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

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

951 952 953 954 955 956 957 958 959 960 961 962 963 964
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");
965 966
}

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

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

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

  int max_keys = max_keys_;
995
  int ttl_start;
996
  if (!ParseIntOption(option_map_, ARG_TTL_START, ttl_start, exec_state_)) {
997
    ttl_start = DBWithTTLImpl::kMinTimestamp;  // TTL introduction time
998 999
  }
  int ttl_end;
1000
  if (!ParseIntOption(option_map_, ARG_TTL_END, ttl_end, exec_state_)) {
1001
    ttl_end = DBWithTTLImpl::kMaxTimestamp;  // Max time allowed by TTL feature
1002 1003 1004 1005 1006 1007 1008 1009
  }
  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;
1010
  if (!ParseIntOption(option_map_, ARG_TTL_BUCKET, bucket_size, exec_state_) ||
1011 1012 1013
      bucket_size <= 0) {
    bucket_size = time_range; // Will have just 1 bucket by default
  }
1014
  //cretaing variables for row count of each type
1015
  string rtype1,rtype2,row,val;
1016
  rtype2 = "";
1017 1018
  uint64_t c=0;
  uint64_t s1=0,s2=0;
1019

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

1030
  for (; iter->Valid(); iter->Next()) {
1031
    int rawtime = 0;
1032 1033 1034 1035 1036 1037
    // 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;
1038
    if (is_db_ttl_) {
1039 1040
      TtlIterator* it_ttl = dynamic_cast<TtlIterator*>(iter);
      assert(it_ttl);
1041 1042
      rawtime = it_ttl->timestamp();
      if (rawtime < ttl_start || rawtime >= ttl_end) {
1043 1044 1045
        continue;
      }
    }
1046 1047 1048
    if (max_keys > 0) {
      --max_keys;
    }
1049
    if (is_db_ttl_ && num_buckets > 1) {
1050
      IncBucketCounts(bucket_counts, ttl_start, time_range, bucket_size,
1051 1052
                      rawtime, num_buckets);
    }
1053
    ++count;
1054 1055 1056 1057 1058
    if (count_delim_) {
      rtype1 = "";
      row = iter->key().ToString();
      val = iter->value().ToString();
      s1 = row.size()+val.size();
1059 1060 1061 1062 1063 1064 1065
      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;
1066 1067
        rtype2 = rtype1;
      } else {
1068 1069 1070
          c++;
          s2+=s1;
          rtype2=rtype1;
1071
      }
1072

1073 1074
    }

1075 1076


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

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

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

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


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

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

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

1134 1135 1136 1137 1138 1139
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");
1140 1141
}

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

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

  *levels = max + 1;
  return st;
}

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

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

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

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

1208 1209 1210
  old_levels_ = old_level_num;

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

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

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

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

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

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

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

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

1277 1278 1279 1280 1281 1282 1283 1284
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");
1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308
}

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++) {
1309
    db_->GetProperty("rocksdb.num-files-at-level" + NumberToString(i),
1310 1311
                     &property);

1312
    // format print string
1313
    char buf[100];
1314
    snprintf(buf, sizeof(buf), "%s%s", (i ? "," : ""), property.c_str());
1315 1316 1317 1318 1319 1320
    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
1321 1322 1323 1324
  CompactRangeOptions compact_options;
  compact_options.change_level = true;
  compact_options.target_level = 0;
  db_->CompactRange(compact_options, nullptr, nullptr);
1325 1326 1327 1328 1329

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

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

    num_files = atoi(property.c_str());

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

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

1363 1364 1365 1366 1367
// ----------------------------------------------------------------------------

namespace {

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

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

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

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

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

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

1405
  virtual ~InMemoryHandler() {}
1406

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

1412 1413 1414 1415
void DumpWalFile(std::string wal_file, bool print_header, bool print_values,
                 LDBCommandExecuteResult* exec_state) {
  Env* env_ = Env::Default();
  EnvOptions soptions;
1416 1417 1418 1419 1420 1421 1422 1423 1424 1425
  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)));
    }
  }
1426 1427
  if (!status.ok()) {
    if (exec_state) {
1428
      *exec_state = LDBCommandExecuteResult::Failed("Failed to open WAL file " +
1429 1430 1431 1432 1433 1434 1435
                                                    status.ToString());
    } else {
      cerr << "Error: Failed to open WAL file " << status.ToString()
           << std::endl;
    }
  } else {
    StdErrReporter reporter;
1436
    log::Reader reader(move(wal_file_reader), &reporter, true, 0);
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 1469
    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

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

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

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

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


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

1497 1498 1499 1500 1501 1502 1503
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 已提交
1504 1505
}

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

1510
// ----------------------------------------------------------------------------
1511

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

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

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

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

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

1549
// ----------------------------------------------------------------------------
1550

1551 1552
ApproxSizeCommand::ApproxSizeCommand(const vector<string>& params,
      const map<string, string>& options, const vector<string>& flags) :
1553 1554 1555 1556 1557 1558 1559
  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 {
1560 1561
    exec_state_ = LDBCommandExecuteResult::Failed(
        ARG_FROM + " must be specified for approxsize command");
1562 1563 1564 1565 1566 1567
    return;
  }

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

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

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

void ApproxSizeCommand::DoCommand() {

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

1601
// ----------------------------------------------------------------------------
1602

1603 1604 1605 1606 1607
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})) {
1608 1609

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

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

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

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

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

1655
// ----------------------------------------------------------------------------
1656

1657 1658
ScanCommand::ScanCommand(const vector<string>& params,
      const map<string, string>& options, const vector<string>& flags) :
1659
    LDBCommand(options, flags, true,
1660 1661 1662
               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})),
1663 1664 1665 1666
    start_key_specified_(false),
    end_key_specified_(false),
    max_keys_scanned_(-1) {

1667
  map<string, string>::const_iterator itr = options.find(ARG_FROM);
1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686
  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 已提交
1687 1688 1689
#if defined(CYGWIN)
      max_keys_scanned_ = strtol(itr->second.c_str(), 0, 10);
#else
M
Mayank Agarwal 已提交
1690
      max_keys_scanned_ = stoi(itr->second);
S
sdong 已提交
1691
#endif
1692
    } catch(const invalid_argument&) {
1693
      exec_state_ = LDBCommandExecuteResult::Failed(ARG_MAX_KEYS +
1694
                                                    " has an invalid value");
1695
    } catch(const out_of_range&) {
1696 1697
      exec_state_ = LDBCommandExecuteResult::Failed(
          ARG_MAX_KEYS + " has a value out-of-range");
1698 1699 1700 1701
    }
  }
}

1702 1703 1704 1705 1706 1707 1708 1709 1710 1711
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");
1712 1713 1714 1715 1716
}

void ScanCommand::DoCommand() {

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

1771
// ----------------------------------------------------------------------------
1772

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

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

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

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


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

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

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

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

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

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

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

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

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

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

}

1866 1867 1868 1869 1870 1871
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 "
1872
             "commands.");
1873
  ret.append("\n");
1874 1875 1876 1877 1878 1879
}

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

1881 1882
  ReadOptions read_options;
  WriteOptions write_options;
1883

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

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

1902
    const string& cmd = tokens[0];
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 1932

    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());
    }
  }
}

1933 1934
// ----------------------------------------------------------------------------

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

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

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

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;
2043
  DumpManifestFile(manifest_filepath, false, false, false);
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 2074
  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 已提交
2075
}   // namespace rocksdb
I
Igor Canadi 已提交
2076
#endif  // ROCKSDB_LITE