ldb_cmd.cc 95.4 KB
Newer Older
1
//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
S
Siying Dong 已提交
2 3 4
//  This source code is licensed under both the GPLv2 (found in the
//  COPYING file in the root directory) and Apache 2.0 License
//  (found in the LICENSE.Apache file in the root directory).
5
//
I
Igor Canadi 已提交
6
#ifndef ROCKSDB_LITE
A
Arun Sharma 已提交
7
#include "rocksdb/utilities/ldb_cmd.h"
A
Abhishek Kona 已提交
8

9 10 11 12 13 14
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif

#include <inttypes.h>

15
#include "db/db_impl.h"
A
Andrew Kryczka 已提交
16 17
#include "db/dbformat.h"
#include "db/log_reader.h"
A
Abhishek Kona 已提交
18
#include "db/write_batch_internal.h"
A
Andrew Kryczka 已提交
19
#include "port/dirent.h"
I
Igor Canadi 已提交
20
#include "rocksdb/cache.h"
21
#include "rocksdb/table_properties.h"
W
Wanning Jiang 已提交
22
#include "rocksdb/utilities/backupable_db.h"
A
Aaron Gao 已提交
23
#include "rocksdb/utilities/checkpoint.h"
A
Andrew Kryczka 已提交
24
#include "rocksdb/utilities/debug.h"
25
#include "rocksdb/utilities/object_registry.h"
26
#include "rocksdb/utilities/options_util.h"
A
Andrew Kryczka 已提交
27
#include "rocksdb/write_batch.h"
28
#include "rocksdb/write_buffer_manager.h"
S
sdong 已提交
29
#include "table/scoped_arena_iterator.h"
A
Arun Sharma 已提交
30
#include "tools/ldb_cmd_impl.h"
31
#include "tools/sst_dump_tool_imp.h"
S
Siying Dong 已提交
32
#include "util/cast_util.h"
33
#include "util/coding.h"
34
#include "util/filename.h"
A
Andrew Kryczka 已提交
35
#include "util/stderr_logger.h"
S
sdong 已提交
36
#include "util/string_util.h"
37
#include "utilities/ttl/db_ttl_impl.h"
38

S
sdong 已提交
39
#include <cstdlib>
40
#include <ctime>
41 42
#include <fstream>
#include <functional>
A
Arun Sharma 已提交
43
#include <iostream>
44 45 46
#include <limits>
#include <sstream>
#include <stdexcept>
A
Arun Sharma 已提交
47
#include <string>
48

49
namespace rocksdb {
50

51 52 53 54 55 56 57 58 59 60
const std::string LDBCommand::ARG_DB = "db";
const std::string LDBCommand::ARG_PATH = "path";
const std::string LDBCommand::ARG_HEX = "hex";
const std::string LDBCommand::ARG_KEY_HEX = "key_hex";
const std::string LDBCommand::ARG_VALUE_HEX = "value_hex";
const std::string LDBCommand::ARG_CF_NAME = "column_family";
const std::string LDBCommand::ARG_TTL = "ttl";
const std::string LDBCommand::ARG_TTL_START = "start_time";
const std::string LDBCommand::ARG_TTL_END = "end_time";
const std::string LDBCommand::ARG_TIMESTAMP = "timestamp";
61
const std::string LDBCommand::ARG_TRY_LOAD_OPTIONS = "try_load_options";
62 63
const std::string LDBCommand::ARG_IGNORE_UNKNOWN_OPTIONS =
    "ignore_unknown_options";
64 65 66 67 68 69 70
const std::string LDBCommand::ARG_FROM = "from";
const std::string LDBCommand::ARG_TO = "to";
const std::string LDBCommand::ARG_MAX_KEYS = "max_keys";
const std::string LDBCommand::ARG_BLOOM_BITS = "bloom_bits";
const std::string LDBCommand::ARG_FIX_PREFIX_LEN = "fix_prefix_len";
const std::string LDBCommand::ARG_COMPRESSION_TYPE = "compression_type";
const std::string LDBCommand::ARG_COMPRESSION_MAX_DICT_BYTES =
71
    "compression_max_dict_bytes";
72 73 74 75 76 77 78
const std::string LDBCommand::ARG_BLOCK_SIZE = "block_size";
const std::string LDBCommand::ARG_AUTO_COMPACTION = "auto_compaction";
const std::string LDBCommand::ARG_DB_WRITE_BUFFER_SIZE = "db_write_buffer_size";
const std::string LDBCommand::ARG_WRITE_BUFFER_SIZE = "write_buffer_size";
const std::string LDBCommand::ARG_FILE_SIZE = "file_size";
const std::string LDBCommand::ARG_CREATE_IF_MISSING = "create_if_missing";
const std::string LDBCommand::ARG_NO_VALUE = "no_value";
79

80
const char* LDBCommand::DELIM = " ==> ";
81

82 83 84 85 86 87 88 89
namespace {

void DumpWalFile(std::string wal_file, bool print_header, bool print_values,
                 LDBCommandExecuteResult* exec_state);

void DumpSstFile(std::string filename, bool output_hex, bool show_properties);
};

90
LDBCommand* LDBCommand::InitFromCmdLineArgs(
S
sdong 已提交
91 92 93
    int argc, char** argv, const Options& options,
    const LDBOptions& ldb_options,
    const std::vector<ColumnFamilyDescriptor>* column_families) {
94
  std::vector<std::string> args;
95 96 97
  for (int i = 1; i < argc; i++) {
    args.push_back(argv[i]);
  }
A
Arun Sharma 已提交
98 99
  return InitFromCmdLineArgs(args, options, ldb_options, column_families,
                             SelectCommand);
100 101 102 103 104 105
}

/**
 * Parse the command-line arguments and create the appropriate LDBCommand2
 * instance.
 * The command line arguments must be in the following format:
106 107
 * ./ldb --db=PATH_TO_DB [--commonOpt1=commonOpt1Val] ..
 *        COMMAND <PARAM1> <PARAM2> ... [-cmdSpecificOpt1=cmdSpecificOpt1Val] ..
108 109
 * This is similar to the command line format used by HBaseClientTool.
 * Command name is not included in args.
110
 * Returns nullptr if the command-line cannot be parsed.
111
 */
112
LDBCommand* LDBCommand::InitFromCmdLineArgs(
113
    const std::vector<std::string>& args, const Options& options,
S
sdong 已提交
114
    const LDBOptions& ldb_options,
115
    const std::vector<ColumnFamilyDescriptor>* column_families,
116 117 118 119 120 121 122
    const std::function<LDBCommand*(const ParsedParams&)>& selector) {
  // --x=y command line arguments are added as x->y map entries in
  // parsed_params.option_map.
  //
  // Command-line arguments of the form --hex end up in this array as hex to
  // parsed_params.flags
  ParsedParams parsed_params;
123

124
  // Everything other than option_map and flags. Represents commands
125
  // and their parameters.  For eg: put key1 value1 go into this vector.
126
  std::vector<std::string> cmdTokens;
127

128
  const std::string OPTION_PREFIX = "--";
129

130
  for (const auto& arg : args) {
131
    if (arg[0] == '-' && arg[1] == '-'){
132
      std::vector<std::string> splits = StringSplit(arg, '=');
133
      if (splits.size() == 2) {
134
        std::string optionKey = splits[0].substr(OPTION_PREFIX.size());
135
        parsed_params.option_map[optionKey] = splits[1];
136
      } else {
137
        std::string optionKey = splits[0].substr(OPTION_PREFIX.size());
138
        parsed_params.flags.push_back(optionKey);
139
      }
140
    } else {
141
      cmdTokens.push_back(arg);
142 143 144 145 146
    }
  }

  if (cmdTokens.size() < 1) {
    fprintf(stderr, "Command not specified!");
147
    return nullptr;
148 149
  }

150 151 152 153
  parsed_params.cmd = cmdTokens[0];
  parsed_params.cmd_params.assign(cmdTokens.begin() + 1, cmdTokens.end());

  LDBCommand* command = selector(parsed_params);
154 155

  if (command) {
156 157
    command->SetDBOptions(options);
    command->SetLDBOptions(ldb_options);
158 159 160 161
  }
  return command;
}

162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
LDBCommand* LDBCommand::SelectCommand(const ParsedParams& parsed_params) {
  if (parsed_params.cmd == GetCommand::Name()) {
    return new GetCommand(parsed_params.cmd_params, parsed_params.option_map,
                          parsed_params.flags);
  } else if (parsed_params.cmd == PutCommand::Name()) {
    return new PutCommand(parsed_params.cmd_params, parsed_params.option_map,
                          parsed_params.flags);
  } else if (parsed_params.cmd == BatchPutCommand::Name()) {
    return new BatchPutCommand(parsed_params.cmd_params,
                               parsed_params.option_map, parsed_params.flags);
  } else if (parsed_params.cmd == ScanCommand::Name()) {
    return new ScanCommand(parsed_params.cmd_params, parsed_params.option_map,
                           parsed_params.flags);
  } else if (parsed_params.cmd == DeleteCommand::Name()) {
    return new DeleteCommand(parsed_params.cmd_params, parsed_params.option_map,
                             parsed_params.flags);
A
Andrew Kryczka 已提交
178 179 180 181
  } else if (parsed_params.cmd == DeleteRangeCommand::Name()) {
    return new DeleteRangeCommand(parsed_params.cmd_params,
                                  parsed_params.option_map,
                                  parsed_params.flags);
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
  } else if (parsed_params.cmd == ApproxSizeCommand::Name()) {
    return new ApproxSizeCommand(parsed_params.cmd_params,
                                 parsed_params.option_map, parsed_params.flags);
  } else if (parsed_params.cmd == DBQuerierCommand::Name()) {
    return new DBQuerierCommand(parsed_params.cmd_params,
                                parsed_params.option_map, parsed_params.flags);
  } else if (parsed_params.cmd == CompactorCommand::Name()) {
    return new CompactorCommand(parsed_params.cmd_params,
                                parsed_params.option_map, parsed_params.flags);
  } else if (parsed_params.cmd == WALDumperCommand::Name()) {
    return new WALDumperCommand(parsed_params.cmd_params,
                                parsed_params.option_map, parsed_params.flags);
  } else if (parsed_params.cmd == ReduceDBLevelsCommand::Name()) {
    return new ReduceDBLevelsCommand(parsed_params.cmd_params,
                                     parsed_params.option_map,
                                     parsed_params.flags);
  } else if (parsed_params.cmd == ChangeCompactionStyleCommand::Name()) {
    return new ChangeCompactionStyleCommand(parsed_params.cmd_params,
                                            parsed_params.option_map,
                                            parsed_params.flags);
  } else if (parsed_params.cmd == DBDumperCommand::Name()) {
    return new DBDumperCommand(parsed_params.cmd_params,
                               parsed_params.option_map, parsed_params.flags);
  } else if (parsed_params.cmd == DBLoaderCommand::Name()) {
    return new DBLoaderCommand(parsed_params.cmd_params,
                               parsed_params.option_map, parsed_params.flags);
  } else if (parsed_params.cmd == ManifestDumpCommand::Name()) {
    return new ManifestDumpCommand(parsed_params.cmd_params,
                                   parsed_params.option_map,
                                   parsed_params.flags);
  } else if (parsed_params.cmd == ListColumnFamiliesCommand::Name()) {
    return new ListColumnFamiliesCommand(parsed_params.cmd_params,
                                         parsed_params.option_map,
                                         parsed_params.flags);
  } else if (parsed_params.cmd == CreateColumnFamilyCommand::Name()) {
    return new CreateColumnFamilyCommand(parsed_params.cmd_params,
                                         parsed_params.option_map,
                                         parsed_params.flags);
  } else if (parsed_params.cmd == DBFileDumperCommand::Name()) {
    return new DBFileDumperCommand(parsed_params.cmd_params,
                                   parsed_params.option_map,
                                   parsed_params.flags);
  } else if (parsed_params.cmd == InternalDumpCommand::Name()) {
    return new InternalDumpCommand(parsed_params.cmd_params,
                                   parsed_params.option_map,
                                   parsed_params.flags);
  } else if (parsed_params.cmd == CheckConsistencyCommand::Name()) {
    return new CheckConsistencyCommand(parsed_params.cmd_params,
                                       parsed_params.option_map,
                                       parsed_params.flags);
A
Aaron Gao 已提交
232 233 234 235
  } else if (parsed_params.cmd == CheckPointCommand::Name()) {
    return new CheckPointCommand(parsed_params.cmd_params,
                                 parsed_params.option_map,
                                 parsed_params.flags);
236 237 238
  } else if (parsed_params.cmd == RepairCommand::Name()) {
    return new RepairCommand(parsed_params.cmd_params, parsed_params.option_map,
                             parsed_params.flags);
W
Wanning Jiang 已提交
239 240 241
  } else if (parsed_params.cmd == BackupCommand::Name()) {
    return new BackupCommand(parsed_params.cmd_params, parsed_params.option_map,
                             parsed_params.flags);
A
Andrew Kryczka 已提交
242 243 244
  } else if (parsed_params.cmd == RestoreCommand::Name()) {
    return new RestoreCommand(parsed_params.cmd_params,
                              parsed_params.option_map, parsed_params.flags);
245
  }
246
  return nullptr;
247 248
}

A
Arun Sharma 已提交
249 250 251 252 253 254 255 256
/* Run the command, and return the execute result. */
void LDBCommand::Run() {
  if (!exec_state_.IsNotStarted()) {
    return;
  }

  if (db_ == nullptr && !NoDBOpen()) {
    OpenDB();
257 258 259 260 261 262
    if (exec_state_.IsFailed() && try_load_options_) {
      // We don't always return if there is a failure because a WAL file or
      // manifest file can be given to "dump" command so we should continue.
      // --try_load_options is not valid in those cases.
      return;
    }
A
Arun Sharma 已提交
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
  }

  // We'll intentionally proceed even if the DB can't be opened because users
  // can also specify a filename, not just a directory.
  DoCommand();

  if (exec_state_.IsNotStarted()) {
    exec_state_ = LDBCommandExecuteResult::Succeed("");
  }

  if (db_ != nullptr) {
    CloseDB();
  }
}

278 279 280
LDBCommand::LDBCommand(const std::map<std::string, std::string>& options,
                       const std::vector<std::string>& flags, bool is_read_only,
                       const std::vector<std::string>& valid_cmd_line_options)
A
Arun Sharma 已提交
281
    : db_(nullptr),
P
Prashant D 已提交
282
      db_ttl_(nullptr),
A
Arun Sharma 已提交
283 284 285 286 287
      is_read_only_(is_read_only),
      is_key_hex_(false),
      is_value_hex_(false),
      is_db_ttl_(false),
      timestamp_(false),
288
      try_load_options_(false),
289
      ignore_unknown_options_(false),
290
      create_if_missing_(false),
A
Arun Sharma 已提交
291 292 293
      option_map_(options),
      flags_(flags),
      valid_cmd_line_options_(valid_cmd_line_options) {
294
  std::map<std::string, std::string>::const_iterator itr = options.find(ARG_DB);
A
Arun Sharma 已提交
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
  if (itr != options.end()) {
    db_path_ = itr->second;
  }

  itr = options.find(ARG_CF_NAME);
  if (itr != options.end()) {
    column_family_name_ = itr->second;
  } else {
    column_family_name_ = kDefaultColumnFamilyName;
  }

  is_key_hex_ = IsKeyHex(options, flags);
  is_value_hex_ = IsValueHex(options, flags);
  is_db_ttl_ = IsFlagPresent(flags, ARG_TTL);
  timestamp_ = IsFlagPresent(flags, ARG_TIMESTAMP);
310
  try_load_options_ = IsFlagPresent(flags, ARG_TRY_LOAD_OPTIONS);
311
  ignore_unknown_options_ = IsFlagPresent(flags, ARG_IGNORE_UNKNOWN_OPTIONS);
A
Arun Sharma 已提交
312 313 314
}

void LDBCommand::OpenDB() {
315
  if (!create_if_missing_ && try_load_options_) {
A
Andrew Kryczka 已提交
316
    Status s = LoadLatestOptions(db_path_, Env::Default(), &options_,
317
                                 &column_families_, ignore_unknown_options_);
A
Andrew Kryczka 已提交
318
    if (!s.ok()) {
319 320 321 322 323 324 325
      // Option file exists but load option file error.
      std::string msg = s.ToString();
      exec_state_ = LDBCommandExecuteResult::Failed(msg);
      db_ = nullptr;
      return;
    }
  }
A
Andrew Kryczka 已提交
326
  options_ = PrepareOptionsForOpenDB();
A
Arun Sharma 已提交
327 328 329 330 331 332 333 334 335 336 337 338 339
  if (!exec_state_.IsNotStarted()) {
    return;
  }
  // Open the DB.
  Status st;
  std::vector<ColumnFamilyHandle*> handles_opened;
  if (is_db_ttl_) {
    // ldb doesn't yet support TTL DB with multiple column families
    if (!column_family_name_.empty() || !column_families_.empty()) {
      exec_state_ = LDBCommandExecuteResult::Failed(
          "ldb doesn't support TTL DB with multiple column families");
    }
    if (is_read_only_) {
A
Andrew Kryczka 已提交
340
      st = DBWithTTL::Open(options_, db_path_, &db_ttl_, 0, true);
A
Arun Sharma 已提交
341
    } else {
A
Andrew Kryczka 已提交
342
      st = DBWithTTL::Open(options_, db_path_, &db_ttl_);
A
Arun Sharma 已提交
343 344 345
    }
    db_ = db_ttl_;
  } else {
A
Andrew Kryczka 已提交
346
    if (column_families_.empty()) {
A
Arun Sharma 已提交
347 348 349 350 351 352 353 354 355 356
      // Try to figure out column family lists
      std::vector<std::string> cf_list;
      st = DB::ListColumnFamilies(DBOptions(), db_path_, &cf_list);
      // There is possible the DB doesn't exist yet, for "create if not
      // "existing case". The failure is ignored here. We rely on DB::Open()
      // to give us the correct error message for problem with opening
      // existing DB.
      if (st.ok() && cf_list.size() > 1) {
        // Ignore single column family DB.
        for (auto cf_name : cf_list) {
A
Andrew Kryczka 已提交
357
          column_families_.emplace_back(cf_name, options_);
A
Arun Sharma 已提交
358 359 360 361 362
        }
      }
    }
    if (is_read_only_) {
      if (column_families_.empty()) {
A
Andrew Kryczka 已提交
363
        st = DB::OpenForReadOnly(options_, db_path_, &db_);
A
Arun Sharma 已提交
364
      } else {
A
Andrew Kryczka 已提交
365
        st = DB::OpenForReadOnly(options_, db_path_, column_families_,
A
Arun Sharma 已提交
366 367 368 369
                                 &handles_opened, &db_);
      }
    } else {
      if (column_families_.empty()) {
A
Andrew Kryczka 已提交
370
        st = DB::Open(options_, db_path_, &db_);
A
Arun Sharma 已提交
371
      } else {
372 373
        st = DB::Open(options_, db_path_, column_families_, &handles_opened,
                      &db_);
A
Arun Sharma 已提交
374 375 376 377
      }
    }
  }
  if (!st.ok()) {
378
    std::string msg = st.ToString();
A
Arun Sharma 已提交
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427
    exec_state_ = LDBCommandExecuteResult::Failed(msg);
  } else if (!handles_opened.empty()) {
    assert(handles_opened.size() == column_families_.size());
    bool found_cf_name = false;
    for (size_t i = 0; i < handles_opened.size(); i++) {
      cf_handles_[column_families_[i].name] = handles_opened[i];
      if (column_family_name_ == column_families_[i].name) {
        found_cf_name = true;
      }
    }
    if (!found_cf_name) {
      exec_state_ = LDBCommandExecuteResult::Failed(
          "Non-existing column family " + column_family_name_);
      CloseDB();
    }
  } else {
    // We successfully opened DB in single column family mode.
    assert(column_families_.empty());
    if (column_family_name_ != kDefaultColumnFamilyName) {
      exec_state_ = LDBCommandExecuteResult::Failed(
          "Non-existing column family " + column_family_name_);
      CloseDB();
    }
  }
}

void LDBCommand::CloseDB() {
  if (db_ != nullptr) {
    for (auto& pair : cf_handles_) {
      delete pair.second;
    }
    delete db_;
    db_ = nullptr;
  }
}

ColumnFamilyHandle* LDBCommand::GetCfHandle() {
  if (!cf_handles_.empty()) {
    auto it = cf_handles_.find(column_family_name_);
    if (it == cf_handles_.end()) {
      exec_state_ = LDBCommandExecuteResult::Failed(
          "Cannot find column family " + column_family_name_);
    } else {
      return it->second;
    }
  }
  return db_->DefaultColumnFamily();
}

428 429 430 431 432 433 434 435 436 437 438
std::vector<std::string> LDBCommand::BuildCmdLineOptions(
    std::vector<std::string> options) {
  std::vector<std::string> ret = {ARG_DB,
                                  ARG_BLOOM_BITS,
                                  ARG_BLOCK_SIZE,
                                  ARG_AUTO_COMPACTION,
                                  ARG_COMPRESSION_TYPE,
                                  ARG_COMPRESSION_MAX_DICT_BYTES,
                                  ARG_WRITE_BUFFER_SIZE,
                                  ARG_FILE_SIZE,
                                  ARG_FIX_PREFIX_LEN,
439
                                  ARG_TRY_LOAD_OPTIONS,
440
                                  ARG_IGNORE_UNKNOWN_OPTIONS,
441
                                  ARG_CF_NAME};
A
Arun Sharma 已提交
442 443 444
  ret.insert(ret.end(), options.begin(), options.end());
  return ret;
}
445

446 447 448 449 450 451 452
/**
 * 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.
 */
453
bool LDBCommand::ParseIntOption(
454
    const std::map<std::string, std::string>& options,
455 456 457 458
    const std::string& option, int& value,
    LDBCommandExecuteResult& exec_state) {
  std::map<std::string, std::string>::const_iterator itr =
      option_map_.find(option);
459
  if (itr != option_map_.end()) {
460
    try {
S
sdong 已提交
461 462 463
#if defined(CYGWIN)
      value = strtol(itr->second.c_str(), 0, 10);
#else
464
      value = std::stoi(itr->second);
S
sdong 已提交
465
#endif
466
      return true;
467
    } catch (const std::invalid_argument&) {
468 469
      exec_state =
          LDBCommandExecuteResult::Failed(option + " has an invalid value.");
470
    } catch (const std::out_of_range&) {
471 472
      exec_state = LDBCommandExecuteResult::Failed(
          option + " has a value out-of-range.");
473 474
    }
  }
475
  return false;
476 477
}

478 479 480 481 482
/**
 * Parses the specified option and fills in the value.
 * Returns true if the option is found.
 * Returns false otherwise.
 */
483
bool LDBCommand::ParseStringOption(
484
    const std::map<std::string, std::string>& options,
485
    const std::string& option, std::string* value) {
486 487 488 489 490 491 492 493
  auto itr = option_map_.find(option);
  if (itr != option_map_.end()) {
    *value = itr->second;
    return true;
  }
  return false;
}

494
Options LDBCommand::PrepareOptionsForOpenDB() {
A
Andrew Kryczka 已提交
495 496 497 498 499 500 501 502 503 504 505 506 507
  ColumnFamilyOptions* cf_opts;
  auto column_families_iter =
      std::find_if(column_families_.begin(), column_families_.end(),
                   [this](const ColumnFamilyDescriptor& cf_desc) {
                     return cf_desc.name == column_family_name_;
                   });
  if (column_families_iter != column_families_.end()) {
    cf_opts = &column_families_iter->options;
  } else {
    cf_opts = static_cast<ColumnFamilyOptions*>(&options_);
  }
  DBOptions* db_opts = static_cast<DBOptions*>(&options_);
  db_opts->create_if_missing = false;
508

509
  std::map<std::string, std::string>::const_iterator itr;
510

511
  BlockBasedTableOptions table_options;
S
sdong 已提交
512
  bool use_table_options = false;
513
  int bits;
514
  if (ParseIntOption(option_map_, ARG_BLOOM_BITS, bits, exec_state_)) {
515
    if (bits > 0) {
S
sdong 已提交
516
      use_table_options = true;
517
      table_options.filter_policy.reset(NewBloomFilterPolicy(bits));
518
    } else {
519 520
      exec_state_ =
          LDBCommandExecuteResult::Failed(ARG_BLOOM_BITS + " must be > 0.");
521 522 523 524
    }
  }

  int block_size;
525
  if (ParseIntOption(option_map_, ARG_BLOCK_SIZE, block_size, exec_state_)) {
526
    if (block_size > 0) {
S
sdong 已提交
527
      use_table_options = true;
528
      table_options.block_size = block_size;
529
    } else {
530 531
      exec_state_ =
          LDBCommandExecuteResult::Failed(ARG_BLOCK_SIZE + " must be > 0.");
532 533 534
    }
  }

S
sdong 已提交
535
  if (use_table_options) {
A
Andrew Kryczka 已提交
536
    cf_opts->table_factory.reset(NewBlockBasedTableFactory(table_options));
S
sdong 已提交
537 538
  }

539 540
  itr = option_map_.find(ARG_AUTO_COMPACTION);
  if (itr != option_map_.end()) {
A
Andrew Kryczka 已提交
541
    cf_opts->disable_auto_compactions = !StringToBool(itr->second);
542 543
  }

544 545
  itr = option_map_.find(ARG_COMPRESSION_TYPE);
  if (itr != option_map_.end()) {
546
    std::string comp = itr->second;
547
    if (comp == "no") {
A
Andrew Kryczka 已提交
548
      cf_opts->compression = kNoCompression;
549
    } else if (comp == "snappy") {
A
Andrew Kryczka 已提交
550
      cf_opts->compression = kSnappyCompression;
551
    } else if (comp == "zlib") {
A
Andrew Kryczka 已提交
552
      cf_opts->compression = kZlibCompression;
553
    } else if (comp == "bzip2") {
A
Andrew Kryczka 已提交
554
      cf_opts->compression = kBZip2Compression;
A
Albert Strasheim 已提交
555
    } else if (comp == "lz4") {
A
Andrew Kryczka 已提交
556
      cf_opts->compression = kLZ4Compression;
A
Albert Strasheim 已提交
557
    } else if (comp == "lz4hc") {
A
Andrew Kryczka 已提交
558
      cf_opts->compression = kLZ4HCCompression;
559
    } else if (comp == "xpress") {
A
Andrew Kryczka 已提交
560
      cf_opts->compression = kXpressCompression;
561
    } else if (comp == "zstd") {
A
Andrew Kryczka 已提交
562
      cf_opts->compression = kZSTD;
563 564
    } else {
      // Unknown compression.
565 566
      exec_state_ =
          LDBCommandExecuteResult::Failed("Unknown compression level: " + comp);
567 568 569
    }
  }

570 571 572 573
  int compression_max_dict_bytes;
  if (ParseIntOption(option_map_, ARG_COMPRESSION_MAX_DICT_BYTES,
                     compression_max_dict_bytes, exec_state_)) {
    if (compression_max_dict_bytes >= 0) {
A
Andrew Kryczka 已提交
574
      cf_opts->compression_opts.max_dict_bytes = compression_max_dict_bytes;
575 576 577 578 579 580
    } else {
      exec_state_ = LDBCommandExecuteResult::Failed(
          ARG_COMPRESSION_MAX_DICT_BYTES + " must be >= 0.");
    }
  }

581 582 583 584
  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) {
A
Andrew Kryczka 已提交
585
      db_opts->db_write_buffer_size = db_write_buffer_size;
586
    } else {
587
      exec_state_ = LDBCommandExecuteResult::Failed(ARG_DB_WRITE_BUFFER_SIZE +
588
                                                    " must be >= 0.");
589 590 591
    }
  }

592
  int write_buffer_size;
593 594
  if (ParseIntOption(option_map_, ARG_WRITE_BUFFER_SIZE, write_buffer_size,
        exec_state_)) {
595
    if (write_buffer_size > 0) {
A
Andrew Kryczka 已提交
596
      cf_opts->write_buffer_size = write_buffer_size;
597
    } else {
598
      exec_state_ = LDBCommandExecuteResult::Failed(ARG_WRITE_BUFFER_SIZE +
599
                                                    " must be > 0.");
600 601 602 603
    }
  }

  int file_size;
604
  if (ParseIntOption(option_map_, ARG_FILE_SIZE, file_size, exec_state_)) {
605
    if (file_size > 0) {
A
Andrew Kryczka 已提交
606
      cf_opts->target_file_size_base = file_size;
607
    } else {
608 609
      exec_state_ =
          LDBCommandExecuteResult::Failed(ARG_FILE_SIZE + " must be > 0.");
610 611 612
    }
  }

A
Andrew Kryczka 已提交
613 614 615
  if (db_opts->db_paths.size() == 0) {
    db_opts->db_paths.emplace_back(db_path_,
                                   std::numeric_limits<uint64_t>::max());
616 617
  }

S
sdong 已提交
618
  int fix_prefix_len;
619 620
  if (ParseIntOption(option_map_, ARG_FIX_PREFIX_LEN, fix_prefix_len,
                     exec_state_)) {
S
sdong 已提交
621
    if (fix_prefix_len > 0) {
A
Andrew Kryczka 已提交
622
      cf_opts->prefix_extractor.reset(
S
sdong 已提交
623 624
          NewFixedPrefixTransform(static_cast<size_t>(fix_prefix_len)));
    } else {
625
      exec_state_ =
626
          LDBCommandExecuteResult::Failed(ARG_FIX_PREFIX_LEN + " must be > 0.");
S
sdong 已提交
627 628
    }
  }
A
Andrew Kryczka 已提交
629 630 631 632
  // TODO(ajkr): this return value doesn't reflect the CF options changed, so
  // subcommands that rely on this won't see the effect of CF-related CLI args.
  // Such subcommands need to be changed to properly support CFs.
  return options_;
633 634
}

635 636 637
bool LDBCommand::ParseKeyValue(const std::string& line, std::string* key,
                               std::string* value, bool is_key_hex,
                               bool is_value_hex) {
638
  size_t pos = line.find(DELIM);
639
  if (pos != std::string::npos) {
640 641 642 643 644 645 646 647 648 649 650 651 652
    *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;
  }
}
653

654 655 656 657 658 659 660 661
/**
 * 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() {
662 663 664 665 666 667
  for (std::map<std::string, std::string>::const_iterator itr =
           option_map_.begin();
       itr != option_map_.end(); ++itr) {
    if (std::find(valid_cmd_line_options_.begin(),
                  valid_cmd_line_options_.end(),
                  itr->first) == valid_cmd_line_options_.end()) {
668 669 670 671
      fprintf(stderr, "Invalid command-line option %s\n", itr->first.c_str());
      return false;
    }
  }
672

673 674 675 676 677
  for (std::vector<std::string>::const_iterator itr = flags_.begin();
       itr != flags_.end(); ++itr) {
    if (std::find(valid_cmd_line_options_.begin(),
                  valid_cmd_line_options_.end(),
                  *itr) == valid_cmd_line_options_.end()) {
678 679
      fprintf(stderr, "Invalid command-line flag %s\n", itr->c_str());
      return false;
680 681 682
    }
  }

683 684 685 686
  if (!NoDBOpen() && option_map_.find(ARG_DB) == option_map_.end() &&
      option_map_.find(ARG_PATH) == option_map_.end()) {
    fprintf(stderr, "Either %s or %s must be specified.\n", ARG_DB.c_str(),
            ARG_PATH.c_str());
687 688 689 690 691 692
    return false;
  }

  return true;
}

693 694
std::string LDBCommand::HexToString(const std::string& str) {
  std::string result;
A
Arun Sharma 已提交
695 696 697 698 699 700 701 702 703 704 705
  std::string::size_type len = str.length();
  if (len < 2 || str[0] != '0' || str[1] != 'x') {
    fprintf(stderr, "Invalid hex input %s.  Must start with 0x\n", str.c_str());
    throw "Invalid hex input";
  }
  if (!Slice(str.data() + 2, len - 2).DecodeHex(&result)) {
    throw "Invalid hex input";
  }
  return result;
}

706 707
std::string LDBCommand::StringToHex(const std::string& str) {
  std::string result("0x");
A
Arun Sharma 已提交
708 709 710 711
  result.append(Slice(str).ToString(true));
  return result;
}

712 713 714 715
std::string LDBCommand::PrintKeyValue(const std::string& key,
                                      const std::string& value, bool is_key_hex,
                                      bool is_value_hex) {
  std::string result;
A
Arun Sharma 已提交
716 717 718 719 720 721
  result.append(is_key_hex ? StringToHex(key) : key);
  result.append(DELIM);
  result.append(is_value_hex ? StringToHex(value) : value);
  return result;
}

722 723
std::string LDBCommand::PrintKeyValue(const std::string& key,
                                      const std::string& value, bool is_hex) {
A
Arun Sharma 已提交
724 725 726
  return PrintKeyValue(key, value, is_hex, is_hex);
}

727
std::string LDBCommand::HelpRangeCmdArgs() {
A
Arun Sharma 已提交
728 729 730 731 732 733 734
  std::ostringstream str_stream;
  str_stream << " ";
  str_stream << "[--" << ARG_FROM << "] ";
  str_stream << "[--" << ARG_TO << "] ";
  return str_stream.str();
}

735 736
bool LDBCommand::IsKeyHex(const std::map<std::string, std::string>& options,
                          const std::vector<std::string>& flags) {
A
Arun Sharma 已提交
737 738 739 740 741
  return (IsFlagPresent(flags, ARG_HEX) || IsFlagPresent(flags, ARG_KEY_HEX) ||
          ParseBooleanOption(options, ARG_HEX, false) ||
          ParseBooleanOption(options, ARG_KEY_HEX, false));
}

742 743
bool LDBCommand::IsValueHex(const std::map<std::string, std::string>& options,
                            const std::vector<std::string>& flags) {
A
Arun Sharma 已提交
744 745 746 747 748 749
  return (IsFlagPresent(flags, ARG_HEX) ||
          IsFlagPresent(flags, ARG_VALUE_HEX) ||
          ParseBooleanOption(options, ARG_HEX, false) ||
          ParseBooleanOption(options, ARG_VALUE_HEX, false));
}

750 751 752 753
bool LDBCommand::ParseBooleanOption(
    const std::map<std::string, std::string>& options,
    const std::string& option, bool default_val) {
  std::map<std::string, std::string>::const_iterator itr = options.find(option);
A
Arun Sharma 已提交
754
  if (itr != options.end()) {
755
    std::string option_val = itr->second;
A
Arun Sharma 已提交
756 757 758 759 760
    return StringToBool(itr->second);
  }
  return default_val;
}

761
bool LDBCommand::StringToBool(std::string val) {
A
Arun Sharma 已提交
762 763 764 765 766 767 768 769 770 771 772 773
  std::transform(val.begin(), val.end(), val.begin(),
                 [](char ch) -> char { return (char)::tolower(ch); });

  if (val == "true") {
    return true;
  } else if (val == "false") {
    return false;
  } else {
    throw "Invalid value for boolean argument";
  }
}

774
CompactorCommand::CompactorCommand(
775
    const std::vector<std::string>& params,
776 777 778 779 780 781 782 783 784
    const std::map<std::string, std::string>& options,
    const std::vector<std::string>& flags)
    : LDBCommand(options, flags, false,
                 BuildCmdLineOptions({ARG_FROM, ARG_TO, ARG_HEX, ARG_KEY_HEX,
                                      ARG_VALUE_HEX, ARG_TTL})),
      null_from_(true),
      null_to_(true) {
  std::map<std::string, std::string>::const_iterator itr =
      options.find(ARG_FROM);
785 786 787 788 789 790 791 792 793 794 795 796
  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_) {
797 798 799 800 801 802 803 804 805
    if (!null_from_) {
      from_ = HexToString(from_);
    }
    if (!null_to_) {
      to_ = HexToString(to_);
    }
  }
}

806
void CompactorCommand::Help(std::string& ret) {
807 808 809 810
  ret.append("  ");
  ret.append(CompactorCommand::Name());
  ret.append(HelpRangeCmdArgs());
  ret.append("\n");
811 812
}

813
void CompactorCommand::DoCommand() {
S
sdong 已提交
814 815 816 817
  if (!db_) {
    assert(GetExecuteState().IsFailed());
    return;
  }
818

819 820
  Slice* begin = nullptr;
  Slice* end = nullptr;
821
  if (!null_from_) {
822
    begin = new Slice(from_);
823 824
  }
  if (!null_to_) {
825
    end = new Slice(to_);
826 827
  }

828 829 830
  CompactRangeOptions cro;
  cro.bottommost_level_compaction = BottommostLevelCompaction::kForce;

831
  db_->CompactRange(cro, GetCfHandle(), begin, end);
832
  exec_state_ = LDBCommandExecuteResult::Succeed("");
833 834 835 836 837

  delete begin;
  delete end;
}

838 839
// ----------------------------------------------------------------------------

840 841 842
const std::string DBLoaderCommand::ARG_DISABLE_WAL = "disable_wal";
const std::string DBLoaderCommand::ARG_BULK_LOAD = "bulk_load";
const std::string DBLoaderCommand::ARG_COMPACT = "compact";
843

844
DBLoaderCommand::DBLoaderCommand(
845
    const std::vector<std::string>& params,
846 847 848 849 850 851 852 853 854 855
    const std::map<std::string, std::string>& options,
    const std::vector<std::string>& flags)
    : LDBCommand(
          options, flags, false,
          BuildCmdLineOptions({ARG_HEX, ARG_KEY_HEX, ARG_VALUE_HEX, ARG_FROM,
                               ARG_TO, ARG_CREATE_IF_MISSING, ARG_DISABLE_WAL,
                               ARG_BULK_LOAD, ARG_COMPACT})),
      disable_wal_(false),
      bulk_load_(false),
      compact_(false) {
856 857
  create_if_missing_ = IsFlagPresent(flags, ARG_CREATE_IF_MISSING);
  disable_wal_ = IsFlagPresent(flags, ARG_DISABLE_WAL);
858 859
  bulk_load_ = IsFlagPresent(flags, ARG_BULK_LOAD);
  compact_ = IsFlagPresent(flags, ARG_COMPACT);
Z
Zheng Shao 已提交
860 861
}

862
void DBLoaderCommand::Help(std::string& ret) {
863 864 865 866 867 868 869
  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 已提交
870 871
}

872 873
Options DBLoaderCommand::PrepareOptionsForOpenDB() {
  Options opt = LDBCommand::PrepareOptionsForOpenDB();
Z
Zheng Shao 已提交
874
  opt.create_if_missing = create_if_missing_;
875 876 877
  if (bulk_load_) {
    opt.PrepareForBulkLoad();
  }
Z
Zheng Shao 已提交
878 879 880
  return opt;
}

881
void DBLoaderCommand::DoCommand() {
Z
Zheng Shao 已提交
882
  if (!db_) {
S
sdong 已提交
883
    assert(GetExecuteState().IsFailed());
Z
Zheng Shao 已提交
884 885 886 887 888 889 890 891 892
    return;
  }

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

  int bad_lines = 0;
893
  std::string line;
894 895 896 897
  // prefer ifstream getline performance vs that from std::cin istream
  std::ifstream ifs_stdin("/dev/stdin");
  std::istream* istream_p = ifs_stdin.is_open() ? &ifs_stdin : &std::cin;
  while (getline(*istream_p, line, '\n')) {
898 899
    std::string key;
    std::string value;
900
    if (ParseKeyValue(line, &key, &value, is_key_hex_, is_value_hex_)) {
S
sdong 已提交
901
      db_->Put(write_options, GetCfHandle(), Slice(key), Slice(value));
Z
Zheng Shao 已提交
902 903 904 905 906 907 908 909
    } 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 ++;
    }
  }
910

Z
Zheng Shao 已提交
911
  if (bad_lines > 0) {
912
    std::cout << "Warning: " << bad_lines << " bad lines ignored." << std::endl;
Z
Zheng Shao 已提交
913
  }
914
  if (compact_) {
S
sdong 已提交
915
    db_->CompactRange(CompactRangeOptions(), GetCfHandle(), nullptr, nullptr);
916
  }
Z
Zheng Shao 已提交
917 918
}

919 920
// ----------------------------------------------------------------------------

921 922
namespace {

923
void DumpManifestFile(std::string file, bool verbose, bool hex, bool json) {
924 925 926
  Options options;
  EnvOptions sopt;
  std::string dbname("dummy");
927 928
  std::shared_ptr<Cache> tc(NewLRUCache(options.max_open_files - 10,
                                        options.table_cache_numshardbits));
929 930 931 932
  // 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);
933
  options.num_levels = 64;
S
sdong 已提交
934
  WriteController wc(options.delayed_write_rate);
935
  WriteBufferManager wb(options.db_write_buffer_size);
936 937
  ImmutableDBOptions immutable_db_options(options);
  VersionSet versions(dbname, &immutable_db_options, sopt, tc.get(), &wb, &wc);
938
  Status s = versions.DumpManifest(options, file, verbose, hex, json);
939 940 941 942 943 944 945 946
  if (!s.ok()) {
    printf("Error in processing file %s %s\n", file.c_str(),
           s.ToString().c_str());
  }
}

}  // namespace

947 948 949
const std::string ManifestDumpCommand::ARG_VERBOSE = "verbose";
const std::string ManifestDumpCommand::ARG_JSON = "json";
const std::string ManifestDumpCommand::ARG_PATH = "path";
950

951
void ManifestDumpCommand::Help(std::string& ret) {
952 953 954
  ret.append("  ");
  ret.append(ManifestDumpCommand::Name());
  ret.append(" [--" + ARG_VERBOSE + "]");
955
  ret.append(" [--" + ARG_JSON + "]");
956 957
  ret.append(" [--" + ARG_PATH + "=<path_to_manifest_file>]");
  ret.append("\n");
958 959
}

960
ManifestDumpCommand::ManifestDumpCommand(
961
    const std::vector<std::string>& params,
962 963 964 965 966 967 968 969
    const std::map<std::string, std::string>& options,
    const std::vector<std::string>& flags)
    : LDBCommand(
          options, flags, false,
          BuildCmdLineOptions({ARG_VERBOSE, ARG_PATH, ARG_HEX, ARG_JSON})),
      verbose_(false),
      json_(false),
      path_("") {
970
  verbose_ = IsFlagPresent(flags, ARG_VERBOSE);
971
  json_ = IsFlagPresent(flags, ARG_JSON);
972

973 974
  std::map<std::string, std::string>::const_iterator itr =
      options.find(ARG_PATH);
975 976 977
  if (itr != options.end()) {
    path_ = itr->second;
    if (path_.empty()) {
978
      exec_state_ = LDBCommandExecuteResult::Failed("--path: missing pathname");
979 980 981 982 983 984 985 986 987 988 989 990 991 992
    }
  }
}

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 已提交
993 994

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

998
    if (d == nullptr) {
999 1000
      exec_state_ =
          LDBCommandExecuteResult::Failed(db_path_ + " is not a directory");
1001 1002 1003
      return;
    }
    struct dirent* entry;
D
Dmitri Smirnov 已提交
1004
    while ((entry = readdir(d.get())) != nullptr) {
1005
      unsigned int match;
1006
      uint64_t num;
1007
      if (sscanf(entry->d_name, "MANIFEST-%" PRIu64 "%n", &num, &match) &&
1008
          match == strlen(entry->d_name)) {
1009 1010 1011 1012
        if (!found) {
          manifestfile = db_path_ + "/" + std::string(entry->d_name);
          found = true;
        } else {
1013
          exec_state_ = LDBCommandExecuteResult::Failed(
1014
              "Multiple MANIFEST files found; use --path to select one");
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
          return;
        }
      }
    }
  }

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

1025 1026
  DumpManifestFile(manifestfile, verbose_, is_key_hex_, json_);

1027 1028 1029 1030 1031 1032
  if (verbose_) {
    printf("Processing Manifest file %s done\n", manifestfile.c_str());
  }
}

// ----------------------------------------------------------------------------
1033

1034
void ListColumnFamiliesCommand::Help(std::string& ret) {
1035 1036 1037 1038
  ret.append("  ");
  ret.append(ListColumnFamiliesCommand::Name());
  ret.append(" full_path_to_db_directory ");
  ret.append("\n");
1039 1040 1041
}

ListColumnFamiliesCommand::ListColumnFamiliesCommand(
1042 1043 1044
    const std::vector<std::string>& params,
    const std::map<std::string, std::string>& options,
    const std::vector<std::string>& flags)
1045 1046
    : LDBCommand(options, flags, false, {}) {
  if (params.size() != 1) {
1047
    exec_state_ = LDBCommandExecuteResult::Failed(
1048 1049 1050 1051 1052 1053 1054
        "dbname must be specified for the list_column_families command");
  } else {
    dbname_ = params[0];
  }
}

void ListColumnFamiliesCommand::DoCommand() {
1055
  std::vector<std::string> column_families;
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
  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");
  }
}

1074
void CreateColumnFamilyCommand::Help(std::string& ret) {
S
sdong 已提交
1075 1076 1077 1078 1079 1080 1081
  ret.append("  ");
  ret.append(CreateColumnFamilyCommand::Name());
  ret.append(" --db=<db_path> <new_column_family_name>");
  ret.append("\n");
}

CreateColumnFamilyCommand::CreateColumnFamilyCommand(
1082 1083 1084
    const std::vector<std::string>& params,
    const std::map<std::string, std::string>& options,
    const std::vector<std::string>& flags)
S
sdong 已提交
1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
    : LDBCommand(options, flags, true, {ARG_DB}) {
  if (params.size() != 1) {
    exec_state_ = LDBCommandExecuteResult::Failed(
        "new column family name must be specified");
  } else {
    new_cf_name_ = params[0];
  }
}

void CreateColumnFamilyCommand::DoCommand() {
1095
  ColumnFamilyHandle* new_cf_handle = nullptr;
S
sdong 已提交
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106
  Status st = db_->CreateColumnFamily(options_, new_cf_name_, &new_cf_handle);
  if (st.ok()) {
    fprintf(stdout, "OK\n");
  } else {
    exec_state_ = LDBCommandExecuteResult::Failed(
        "Fail to create new column family: " + st.ToString());
  }
  delete new_cf_handle;
  CloseDB();
}

1107
// ----------------------------------------------------------------------------
1108

I
Igor Canadi 已提交
1109 1110
namespace {

1111
std::string ReadableTime(int unixtime) {
1112 1113
  char time_buffer [80];
  time_t rawtime = unixtime;
1114 1115 1116
  struct tm tInfo;
  struct tm* timeinfo = localtime_r(&rawtime, &tInfo);
  assert(timeinfo == &tInfo);
1117
  strftime(time_buffer, 80, "%c", timeinfo);
1118
  return std::string(time_buffer);
1119 1120 1121 1122
}

// 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
1123 1124 1125
void IncBucketCounts(std::vector<uint64_t>& bucket_counts, int ttl_start,
                     int time_range, int bucket_size, int timekv,
                     int num_buckets) {
1126 1127 1128
  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;
1129
  bucket_counts[bucket]++;
1130 1131
}

1132 1133 1134
void PrintBucketCounts(const std::vector<uint64_t>& bucket_counts,
                       int ttl_start, int ttl_end, int bucket_size,
                       int num_buckets) {
1135
  int time_point = ttl_start;
1136 1137
  for(int i = 0; i < num_buckets - 1; i++, time_point += bucket_size) {
    fprintf(stdout, "Keys in range %s to %s : %lu\n",
1138
            ReadableTime(time_point).c_str(),
K
Kai Liu 已提交
1139
            ReadableTime(time_point + bucket_size).c_str(),
1140
            (unsigned long)bucket_counts[i]);
1141
  }
1142
  fprintf(stdout, "Keys in range %s to %s : %lu\n",
1143
          ReadableTime(time_point).c_str(),
K
Kai Liu 已提交
1144
          ReadableTime(ttl_end).c_str(),
1145
          (unsigned long)bucket_counts[num_buckets - 1]);
1146 1147
}

I
Igor Canadi 已提交
1148 1149
}  // namespace

1150 1151 1152 1153
const std::string InternalDumpCommand::ARG_COUNT_ONLY = "count_only";
const std::string InternalDumpCommand::ARG_COUNT_DELIM = "count_delim";
const std::string InternalDumpCommand::ARG_STATS = "stats";
const std::string InternalDumpCommand::ARG_INPUT_KEY_HEX = "input_key_hex";
1154

1155
InternalDumpCommand::InternalDumpCommand(
1156
    const std::vector<std::string>& params,
1157 1158
    const std::map<std::string, std::string>& options,
    const std::vector<std::string>& flags)
1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171
    : LDBCommand(
          options, flags, true,
          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})),
      has_from_(false),
      has_to_(false),
      max_keys_(-1),
      delim_("."),
      count_only_(false),
      count_delim_(false),
      print_stats_(false),
      is_input_key_hex_(false) {
1172 1173 1174
  has_from_ = ParseStringOption(options, ARG_FROM, &from_);
  has_to_ = ParseStringOption(options, ARG_TO, &to_);

1175
  ParseIntOption(options, ARG_MAX_KEYS, max_keys_, exec_state_);
1176 1177
  std::map<std::string, std::string>::const_iterator itr =
      options.find(ARG_COUNT_DELIM);
1178 1179 1180
  if (itr != options.end()) {
    delim_ = itr->second;
    count_delim_ = true;
1181
   // fprintf(stdout,"delim = %c\n",delim_[0]);
1182 1183
  } else {
    count_delim_ = IsFlagPresent(flags, ARG_COUNT_DELIM);
1184
    delim_=".";
1185
  }
1186 1187 1188

  print_stats_ = IsFlagPresent(flags, ARG_STATS);
  count_only_ = IsFlagPresent(flags, ARG_COUNT_ONLY);
1189
  is_input_key_hex_ = IsFlagPresent(flags, ARG_INPUT_KEY_HEX);
1190

1191
  if (is_input_key_hex_) {
1192 1193 1194 1195 1196 1197 1198 1199 1200
    if (has_from_) {
      from_ = HexToString(from_);
    }
    if (has_to_) {
      to_ = HexToString(to_);
    }
  }
}

1201
void InternalDumpCommand::Help(std::string& ret) {
1202 1203 1204 1205 1206 1207 1208 1209 1210
  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");
1211 1212 1213 1214
}

void InternalDumpCommand::DoCommand() {
  if (!db_) {
S
sdong 已提交
1215
    assert(GetExecuteState().IsFailed());
1216 1217 1218 1219
    return;
  }

  if (print_stats_) {
1220
    std::string stats;
S
sdong 已提交
1221
    if (db_->GetProperty(GetCfHandle(), "rocksdb.stats", &stats)) {
1222 1223 1224 1225 1226
      fprintf(stdout, "%s\n", stats.c_str());
    }
  }

  // Cast as DBImpl to get internal iterator
A
Andrew Kryczka 已提交
1227 1228 1229 1230
  std::vector<KeyVersion> key_versions;
  Status st = GetAllKeyVersions(db_, from_, to_, &key_versions);
  if (!st.ok()) {
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
1231 1232
    return;
  }
1233
  std::string rtype1, rtype2, row, val;
1234
  rtype2 = "";
1235 1236
  uint64_t c=0;
  uint64_t s1=0,s2=0;
1237

1238
  long long count = 0;
A
Andrew Kryczka 已提交
1239 1240 1241 1242 1243 1244
  for (auto& key_version : key_versions) {
    InternalKey ikey(key_version.user_key, key_version.sequence,
                     static_cast<ValueType>(key_version.type));
    if (has_to_ && ikey.user_key() == to_) {
      // GetAllKeyVersions() includes keys with user key `to_`, but idump has
      // traditionally excluded such keys.
1245 1246 1247
      break;
    }
    ++count;
1248 1249 1250
    int k;
    if (count_delim_) {
      rtype1 = "";
1251
      s1=0;
A
Andrew Kryczka 已提交
1252 1253
      row = ikey.Encode().ToString();
      val = key_version.value;
1254
      for(k=0;row[k]!='\x01' && row[k]!='\0';k++)
1255
        s1++;
1256
      for(k=0;val[k]!='\x01' && val[k]!='\0';k++)
1257
        s1++;
1258 1259 1260 1261 1262 1263 1264
      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;
1265 1266 1267
        rtype2 = rtype1;
      } else {
        c++;
1268 1269
        s2+=s1;
        rtype2=rtype1;
A
Andrew Kryczka 已提交
1270
      }
1271
    }
1272

1273
    if (!count_only_ && !count_delim_) {
1274
      std::string key = ikey.DebugString(is_key_hex_);
A
Andrew Kryczka 已提交
1275
      std::string value = Slice(key_version.value).ToString(is_value_hex_);
1276
      std::cout << key << " => " << value << "\n";
1277 1278 1279
    }

    // Terminate if maximum number of keys have been dumped
1280
    if (max_keys_ > 0 && count >= max_keys_) break;
1281
  }
1282 1283 1284
  if(count_delim_) {
    fprintf(stdout,"%s => count:%lld\tsize:%lld\n", rtype2.c_str(),
        (long long)c,(long long)s2);
1285
  } else
1286
  fprintf(stdout, "Internal keys in range: %lld\n", (long long) count);
1287 1288
}

1289 1290 1291 1292
const std::string DBDumperCommand::ARG_COUNT_ONLY = "count_only";
const std::string DBDumperCommand::ARG_COUNT_DELIM = "count_delim";
const std::string DBDumperCommand::ARG_STATS = "stats";
const std::string DBDumperCommand::ARG_TTL_BUCKET = "bucket";
1293

1294
DBDumperCommand::DBDumperCommand(
1295
    const std::vector<std::string>& params,
1296 1297
    const std::map<std::string, std::string>& options,
    const std::vector<std::string>& flags)
1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
    : LDBCommand(options, flags, true,
                 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, ARG_PATH})),
      null_from_(true),
      null_to_(true),
      max_keys_(-1),
      count_only_(false),
      count_delim_(false),
      print_stats_(false) {
1310 1311
  std::map<std::string, std::string>::const_iterator itr =
      options.find(ARG_FROM);
1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325
  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 已提交
1326 1327 1328
#if defined(CYGWIN)
      max_keys_ = strtol(itr->second.c_str(), 0, 10);
#else
1329
      max_keys_ = std::stoi(itr->second);
S
sdong 已提交
1330
#endif
1331
    } catch (const std::invalid_argument&) {
1332
      exec_state_ = LDBCommandExecuteResult::Failed(ARG_MAX_KEYS +
1333
                                                    " has an invalid value");
1334
    } catch (const std::out_of_range&) {
1335 1336
      exec_state_ = LDBCommandExecuteResult::Failed(
          ARG_MAX_KEYS + " has a value out-of-range");
1337 1338
    }
  }
1339 1340 1341 1342 1343 1344
  itr = options.find(ARG_COUNT_DELIM);
  if (itr != options.end()) {
    delim_ = itr->second;
    count_delim_ = true;
  } else {
    count_delim_ = IsFlagPresent(flags, ARG_COUNT_DELIM);
1345
    delim_=".";
1346
  }
1347

1348 1349 1350 1351
  print_stats_ = IsFlagPresent(flags, ARG_STATS);
  count_only_ = IsFlagPresent(flags, ARG_COUNT_ONLY);

  if (is_key_hex_) {
1352 1353 1354 1355 1356 1357 1358
    if (!null_from_) {
      from_ = HexToString(from_);
    }
    if (!null_to_) {
      to_ = HexToString(to_);
    }
  }
1359 1360 1361 1362

  itr = options.find(ARG_PATH);
  if (itr != options.end()) {
    path_ = itr->second;
1363 1364 1365
    if (db_path_.empty()) {
      db_path_ = path_;
    }
1366
  }
1367 1368
}

1369
void DBDumperCommand::Help(std::string& ret) {
1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381
  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]");
1382
  ret.append(" [--" + ARG_PATH + "=<path_to_a_file>]");
1383
  ret.append("\n");
1384 1385
}

1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396
/**
 * Handles two separate cases:
 *
 * 1) --db is specified - just dump the database.
 *
 * 2) --path is specified - determine based on file extension what dumping
 *    function to call. Please note that we intentionally use the extension
 *    and avoid probing the file contents under the assumption that renaming
 *    the files is not a supported scenario.
 *
 */
1397
void DBDumperCommand::DoCommand() {
1398
  if (!db_) {
1399
    assert(!path_.empty());
1400
    std::string fileName = GetFileNameFromPath(path_);
1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431
    uint64_t number;
    FileType type;

    exec_state_ = LDBCommandExecuteResult::Succeed("");

    if (!ParseFileName(fileName, &number, &type)) {
      exec_state_ =
          LDBCommandExecuteResult::Failed("Can't parse file type: " + path_);
      return;
    }

    switch (type) {
      case kLogFile:
        DumpWalFile(path_, /* print_header_ */ true, /* print_values_ */ true,
                    &exec_state_);
        break;
      case kTableFile:
        DumpSstFile(path_, is_key_hex_, /* show_properties */ true);
        break;
      case kDescriptorFile:
        DumpManifestFile(path_, /* verbose_ */ false, is_key_hex_,
                         /*  json_ */ false);
        break;
      default:
        exec_state_ = LDBCommandExecuteResult::Failed(
            "File type not supported: " + path_);
        break;
    }

  } else {
    DoDumpCommand();
1432
  }
1433 1434 1435 1436 1437 1438
}

void DBDumperCommand::DoDumpCommand() {
  assert(nullptr != db_);
  assert(path_.empty());

1439 1440 1441
  // Parse command line args
  uint64_t count = 0;
  if (print_stats_) {
1442
    std::string stats;
1443
    if (db_->GetProperty("rocksdb.stats", &stats)) {
1444 1445 1446 1447 1448
      fprintf(stdout, "%s\n", stats.c_str());
    }
  }

  // Setup key iterator
S
sdong 已提交
1449
  Iterator* iter = db_->NewIterator(ReadOptions(), GetCfHandle());
1450
  Status st = iter->status();
1451
  if (!st.ok()) {
1452 1453
    exec_state_ =
        LDBCommandExecuteResult::Failed("Iterator error." + st.ToString());
1454 1455 1456 1457 1458 1459 1460 1461 1462
  }

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

  int max_keys = max_keys_;
1463
  int ttl_start;
1464
  if (!ParseIntOption(option_map_, ARG_TTL_START, ttl_start, exec_state_)) {
1465
    ttl_start = DBWithTTLImpl::kMinTimestamp;  // TTL introduction time
1466 1467
  }
  int ttl_end;
1468
  if (!ParseIntOption(option_map_, ARG_TTL_END, ttl_end, exec_state_)) {
1469
    ttl_end = DBWithTTLImpl::kMaxTimestamp;  // Max time allowed by TTL feature
1470 1471 1472 1473 1474 1475 1476 1477
  }
  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;
1478
  if (!ParseIntOption(option_map_, ARG_TTL_BUCKET, bucket_size, exec_state_) ||
1479 1480 1481
      bucket_size <= 0) {
    bucket_size = time_range; // Will have just 1 bucket by default
  }
1482
  //cretaing variables for row count of each type
1483
  std::string rtype1, rtype2, row, val;
1484
  rtype2 = "";
1485 1486
  uint64_t c=0;
  uint64_t s1=0,s2=0;
1487

1488
  // At this point, bucket_size=0 => time_range=0
1489 1490 1491
  int num_buckets = (bucket_size >= time_range)
                        ? 1
                        : ((time_range + bucket_size - 1) / bucket_size);
1492
  std::vector<uint64_t> bucket_counts(num_buckets, 0);
1493
  if (is_db_ttl_ && !count_only_ && timestamp_ && !count_delim_) {
1494 1495 1496 1497
    fprintf(stdout, "Dumping key-values from %s to %s\n",
            ReadableTime(ttl_start).c_str(), ReadableTime(ttl_end).c_str());
  }

1498 1499
  HistogramImpl vsize_hist;

1500
  for (; iter->Valid(); iter->Next()) {
1501
    int rawtime = 0;
1502 1503 1504 1505 1506 1507
    // 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;
1508
    if (is_db_ttl_) {
S
Siying Dong 已提交
1509
      TtlIterator* it_ttl = static_cast_with_check<TtlIterator, Iterator>(iter);
1510 1511
      rawtime = it_ttl->timestamp();
      if (rawtime < ttl_start || rawtime >= ttl_end) {
1512 1513 1514
        continue;
      }
    }
1515 1516 1517
    if (max_keys > 0) {
      --max_keys;
    }
1518
    if (is_db_ttl_ && num_buckets > 1) {
1519
      IncBucketCounts(bucket_counts, ttl_start, time_range, bucket_size,
1520 1521
                      rawtime, num_buckets);
    }
1522
    ++count;
1523 1524 1525 1526 1527
    if (count_delim_) {
      rtype1 = "";
      row = iter->key().ToString();
      val = iter->value().ToString();
      s1 = row.size()+val.size();
1528 1529 1530 1531 1532 1533 1534
      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;
1535 1536
        rtype2 = rtype1;
      } else {
1537 1538 1539
          c++;
          s2+=s1;
          rtype2=rtype1;
1540
      }
1541

1542 1543
    }

1544 1545 1546
    if (count_only_) {
      vsize_hist.Add(iter->value().size());
    }
1547

1548
    if (!count_only_ && !count_delim_) {
1549 1550 1551
      if (is_db_ttl_ && timestamp_) {
        fprintf(stdout, "%s ", ReadableTime(rawtime).c_str());
      }
1552 1553 1554
      std::string str =
          PrintKeyValue(iter->key().ToString(), iter->value().ToString(),
                        is_key_hex_, is_value_hex_);
1555
      fprintf(stdout, "%s\n", str.c_str());
1556 1557
    }
  }
1558

1559
  if (num_buckets > 1 && is_db_ttl_) {
1560
    PrintBucketCounts(bucket_counts, ttl_start, ttl_end, bucket_size,
1561
                      num_buckets);
1562 1563 1564
  } else if(count_delim_) {
    fprintf(stdout,"%s => count:%lld\tsize:%lld\n",rtype2.c_str(),
        (long long )c,(long long)s2);
1565
  } else {
1566
    fprintf(stdout, "Keys in range: %lld\n", (long long) count);
1567
  }
1568 1569 1570 1571 1572

  if (count_only_) {
    fprintf(stdout, "Value size distribution: \n");
    fprintf(stdout, "%s\n", vsize_hist.ToString().c_str());
  }
1573 1574 1575 1576
  // Clean up
  delete iter;
}

1577 1578 1579
const std::string ReduceDBLevelsCommand::ARG_NEW_LEVELS = "new_levels";
const std::string ReduceDBLevelsCommand::ARG_PRINT_OLD_LEVELS =
    "print_old_levels";
1580

1581
ReduceDBLevelsCommand::ReduceDBLevelsCommand(
1582
    const std::vector<std::string>& params,
1583 1584 1585 1586 1587 1588 1589
    const std::map<std::string, std::string>& options,
    const std::vector<std::string>& flags)
    : LDBCommand(options, flags, false,
                 BuildCmdLineOptions({ARG_NEW_LEVELS, ARG_PRINT_OLD_LEVELS})),
      old_levels_(1 << 7),
      new_levels_(-1),
      print_old_levels_(false) {
1590
  ParseIntOption(option_map_, ARG_NEW_LEVELS, new_levels_, exec_state_);
1591
  print_old_levels_ = IsFlagPresent(flags, ARG_PRINT_OLD_LEVELS);
1592

1593
  if(new_levels_ <= 0) {
1594
    exec_state_ = LDBCommandExecuteResult::Failed(
1595
        " Use --" + ARG_NEW_LEVELS + " to specify a new level number\n");
1596 1597 1598
  }
}

1599 1600 1601
std::vector<std::string> ReduceDBLevelsCommand::PrepareArgs(
    const std::string& db_path, int new_levels, bool print_old_level) {
  std::vector<std::string> ret;
1602
  ret.push_back("reduce_levels");
1603
  ret.push_back("--" + ARG_DB + "=" + db_path);
S
sdong 已提交
1604
  ret.push_back("--" + ARG_NEW_LEVELS + "=" + rocksdb::ToString(new_levels));
1605
  if(print_old_level) {
1606
    ret.push_back("--" + ARG_PRINT_OLD_LEVELS);
1607 1608 1609 1610
  }
  return ret;
}

1611
void ReduceDBLevelsCommand::Help(std::string& ret) {
1612 1613 1614 1615 1616
  ret.append("  ");
  ret.append(ReduceDBLevelsCommand::Name());
  ret.append(" --" + ARG_NEW_LEVELS + "=<New number of levels>");
  ret.append(" [--" + ARG_PRINT_OLD_LEVELS + "]");
  ret.append("\n");
1617 1618
}

1619 1620
Options ReduceDBLevelsCommand::PrepareOptionsForOpenDB() {
  Options opt = LDBCommand::PrepareOptionsForOpenDB();
1621
  opt.num_levels = old_levels_;
1622
  opt.max_bytes_for_level_multiplier_additional.resize(opt.num_levels, 1);
1623
  // Disable size compaction
I
Igor Canadi 已提交
1624
  opt.max_bytes_for_level_base = 1ULL << 50;
1625
  opt.max_bytes_for_level_multiplier = 1;
1626 1627 1628
  return opt;
}

1629
Status ReduceDBLevelsCommand::GetOldNumOfLevels(Options& opt,
1630
    int* levels) {
1631
  ImmutableDBOptions db_options(opt);
H
Haobo Xu 已提交
1632
  EnvOptions soptions;
I
Igor Canadi 已提交
1633
  std::shared_ptr<Cache> tc(
1634
      NewLRUCache(opt.max_open_files - 10, opt.table_cache_numshardbits));
1635
  const InternalKeyComparator cmp(opt.comparator);
S
sdong 已提交
1636
  WriteController wc(opt.delayed_write_rate);
1637
  WriteBufferManager wb(opt.db_write_buffer_size);
1638
  VersionSet versions(db_path_, &db_options, soptions, tc.get(), &wb, &wc);
I
Igor Canadi 已提交
1639
  std::vector<ColumnFamilyDescriptor> dummy;
1640
  ColumnFamilyDescriptor dummy_descriptor(kDefaultColumnFamilyName,
I
Igor Canadi 已提交
1641 1642
                                          ColumnFamilyOptions(opt));
  dummy.push_back(dummy_descriptor);
1643 1644 1645
  // 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 已提交
1646
  Status st = versions.Recover(dummy);
1647 1648 1649 1650
  if (!st.ok()) {
    return st;
  }
  int max = -1;
1651
  auto default_cfd = versions.GetColumnFamilySet()->GetDefault();
I
Igor Canadi 已提交
1652
  for (int i = 0; i < default_cfd->NumberLevels(); i++) {
S
sdong 已提交
1653
    if (default_cfd->current()->storage_info()->NumLevelFiles(i)) {
1654 1655 1656 1657 1658 1659 1660 1661
      max = i;
    }
  }

  *levels = max + 1;
  return st;
}

1662
void ReduceDBLevelsCommand::DoCommand() {
1663
  if (new_levels_ <= 1) {
1664 1665
    exec_state_ =
        LDBCommandExecuteResult::Failed("Invalid number of levels.\n");
1666 1667 1668
    return;
  }

1669 1670
  Status st;
  Options opt = PrepareOptionsForOpenDB();
1671 1672 1673
  int old_level_num = -1;
  st = GetOldNumOfLevels(opt, &old_level_num);
  if (!st.ok()) {
1674
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
1675 1676 1677
    return;
  }

1678
  if (print_old_levels_) {
1679
    fprintf(stdout, "The old number of levels in use is %d\n", old_level_num);
1680
  }
1681

1682 1683
  if (old_level_num <= new_levels_) {
    return;
1684 1685
  }

1686 1687 1688
  old_levels_ = old_level_num;

  OpenDB();
1689
  if (exec_state_.IsFailed()) {
1690 1691
    return;
  }
1692
  // Compact the whole DB to put all files to the highest level.
1693
  fprintf(stdout, "Compacting the db...\n");
S
sdong 已提交
1694
  db_->CompactRange(CompactRangeOptions(), GetCfHandle(), nullptr, nullptr);
1695 1696
  CloseDB();

H
Haobo Xu 已提交
1697
  EnvOptions soptions;
1698
  st = VersionSet::ReduceNumberOfLevels(db_path_, &opt, soptions, new_levels_);
1699
  if (!st.ok()) {
1700
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
1701 1702 1703 1704
    return;
  }
}

1705 1706 1707 1708
const std::string ChangeCompactionStyleCommand::ARG_OLD_COMPACTION_STYLE =
    "old_compaction_style";
const std::string ChangeCompactionStyleCommand::ARG_NEW_COMPACTION_STYLE =
    "new_compaction_style";
1709 1710

ChangeCompactionStyleCommand::ChangeCompactionStyleCommand(
1711
    const std::vector<std::string>& params,
1712 1713 1714 1715 1716 1717 1718
    const std::map<std::string, std::string>& options,
    const std::vector<std::string>& flags)
    : LDBCommand(options, flags, false,
                 BuildCmdLineOptions(
                     {ARG_OLD_COMPACTION_STYLE, ARG_NEW_COMPACTION_STYLE})),
      old_compaction_style_(-1),
      new_compaction_style_(-1) {
1719 1720
  ParseIntOption(option_map_, ARG_OLD_COMPACTION_STYLE, old_compaction_style_,
    exec_state_);
1721 1722
  if (old_compaction_style_ != kCompactionStyleLevel &&
     old_compaction_style_ != kCompactionStyleUniversal) {
1723
    exec_state_ = LDBCommandExecuteResult::Failed(
1724 1725
        "Use --" + ARG_OLD_COMPACTION_STYLE + " to specify old compaction " +
        "style. Check ldb help for proper compaction style value.\n");
1726 1727 1728
    return;
  }

1729 1730
  ParseIntOption(option_map_, ARG_NEW_COMPACTION_STYLE, new_compaction_style_,
    exec_state_);
1731 1732
  if (new_compaction_style_ != kCompactionStyleLevel &&
     new_compaction_style_ != kCompactionStyleUniversal) {
1733
    exec_state_ = LDBCommandExecuteResult::Failed(
1734 1735
        "Use --" + ARG_NEW_COMPACTION_STYLE + " to specify new compaction " +
        "style. Check ldb help for proper compaction style value.\n");
1736 1737 1738 1739
    return;
  }

  if (new_compaction_style_ == old_compaction_style_) {
1740
    exec_state_ = LDBCommandExecuteResult::Failed(
1741 1742
        "Old compaction style is the same as new compaction style. "
        "Nothing to do.\n");
1743 1744 1745 1746 1747
    return;
  }

  if (old_compaction_style_ == kCompactionStyleUniversal &&
      new_compaction_style_ == kCompactionStyleLevel) {
1748
    exec_state_ = LDBCommandExecuteResult::Failed(
1749 1750
        "Convert from universal compaction to level compaction. "
        "Nothing to do.\n");
1751 1752 1753 1754
    return;
  }
}

1755
void ChangeCompactionStyleCommand::Help(std::string& ret) {
1756 1757 1758 1759 1760 1761 1762
  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");
1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785
}

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;
S
sdong 已提交
1786 1787 1788
  for (int i = 0; i < db_->NumberLevels(GetCfHandle()); i++) {
    db_->GetProperty(GetCfHandle(),
                     "rocksdb.num-files-at-level" + NumberToString(i),
1789 1790
                     &property);

1791
    // format print string
1792
    char buf[100];
1793
    snprintf(buf, sizeof(buf), "%s%s", (i ? "," : ""), property.c_str());
1794 1795 1796 1797 1798 1799
    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
1800 1801 1802
  CompactRangeOptions compact_options;
  compact_options.change_level = true;
  compact_options.target_level = 0;
S
sdong 已提交
1803
  db_->CompactRange(compact_options, GetCfHandle(), nullptr, nullptr);
1804 1805 1806 1807

  // verify compaction result
  files_per_level = "";
  int num_files = 0;
1808
  for (int i = 0; i < db_->NumberLevels(GetCfHandle()); i++) {
S
sdong 已提交
1809 1810
    db_->GetProperty(GetCfHandle(),
                     "rocksdb.num-files-at-level" + NumberToString(i),
1811 1812
                     &property);

1813
    // format print string
1814
    char buf[100];
1815
    snprintf(buf, sizeof(buf), "%s%s", (i ? "," : ""), property.c_str());
1816 1817 1818 1819 1820 1821
    files_per_level += buf;

    num_files = atoi(property.c_str());

    // level 0 should have only 1 file
    if (i == 0 && num_files != 1) {
1822 1823 1824 1825
      exec_state_ = LDBCommandExecuteResult::Failed(
          "Number of db files at "
          "level 0 after compaction is " +
          ToString(num_files) + ", not 1.\n");
1826 1827 1828 1829
      return;
    }
    // other levels should have no file
    if (i > 0 && num_files != 0) {
1830 1831 1832 1833 1834
      exec_state_ = LDBCommandExecuteResult::Failed(
          "Number of db files at "
          "level " +
          ToString(i) + " after compaction is " + ToString(num_files) +
          ", not 0.\n");
1835 1836 1837 1838 1839 1840 1841 1842
      return;
    }
  }

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

1843 1844 1845 1846 1847
// ----------------------------------------------------------------------------

namespace {

struct StdErrReporter : public log::Reader::Reporter {
1848
  virtual void Corruption(size_t bytes, const Status& s) override {
1849
    std::cerr << "Corruption detected in log file " << s.ToString() << "\n";
1850 1851 1852
  }
};

1853 1854
class InMemoryHandler : public WriteBatch::Handler {
 public:
1855 1856
  InMemoryHandler(std::stringstream& row, bool print_values)
      : Handler(), row_(row) {
1857 1858
    print_values_ = print_values;
  }
1859

1860
  void commonPutMerge(const Slice& key, const Slice& value) {
1861
    std::string k = LDBCommand::StringToHex(key.ToString());
1862
    if (print_values_) {
1863
      std::string v = LDBCommand::StringToHex(value.ToString());
1864 1865 1866 1867 1868
      row_ << k << " : ";
      row_ << v << " ";
    } else {
      row_ << k << " ";
    }
1869
  }
1870

R
Reid Horuff 已提交
1871 1872 1873
  virtual Status PutCF(uint32_t cf, const Slice& key,
                       const Slice& value) override {
    row_ << "PUT(" << cf << ") : ";
1874
    commonPutMerge(key, value);
R
Reid Horuff 已提交
1875
    return Status::OK();
1876 1877
  }

R
Reid Horuff 已提交
1878 1879 1880
  virtual Status MergeCF(uint32_t cf, const Slice& key,
                         const Slice& value) override {
    row_ << "MERGE(" << cf << ") : ";
1881
    commonPutMerge(key, value);
R
Reid Horuff 已提交
1882
    return Status::OK();
1883
  }
1884

R
Reid Horuff 已提交
1885 1886
  virtual Status DeleteCF(uint32_t cf, const Slice& key) override {
    row_ << "DELETE(" << cf << ") : ";
1887
    row_ << LDBCommand::StringToHex(key.ToString()) << " ";
R
Reid Horuff 已提交
1888 1889 1890 1891 1892 1893 1894 1895 1896
    return Status::OK();
  }

  virtual Status SingleDeleteCF(uint32_t cf, const Slice& key) override {
    row_ << "SINGLE_DELETE(" << cf << ") : ";
    row_ << LDBCommand::StringToHex(key.ToString()) << " ";
    return Status::OK();
  }

A
Andrew Kryczka 已提交
1897 1898 1899 1900 1901 1902 1903 1904
  virtual Status DeleteRangeCF(uint32_t cf, const Slice& begin_key,
                               const Slice& end_key) override {
    row_ << "DELETE_RANGE(" << cf << ") : ";
    row_ << LDBCommand::StringToHex(begin_key.ToString()) << " ";
    row_ << LDBCommand::StringToHex(end_key.ToString()) << " ";
    return Status::OK();
  }

1905
  virtual Status MarkBeginPrepare() override {
R
Reid Horuff 已提交
1906 1907 1908 1909
    row_ << "BEGIN_PREARE ";
    return Status::OK();
  }

1910
  virtual Status MarkEndPrepare(const Slice& xid) override {
R
Reid Horuff 已提交
1911 1912 1913 1914 1915
    row_ << "END_PREPARE(";
    row_ << LDBCommand::StringToHex(xid.ToString()) << ") ";
    return Status::OK();
  }

1916
  virtual Status MarkRollback(const Slice& xid) override {
R
Reid Horuff 已提交
1917 1918 1919 1920 1921
    row_ << "ROLLBACK(";
    row_ << LDBCommand::StringToHex(xid.ToString()) << ") ";
    return Status::OK();
  }

1922
  virtual Status MarkCommit(const Slice& xid) override {
R
Reid Horuff 已提交
1923 1924 1925
    row_ << "COMMIT(";
    row_ << LDBCommand::StringToHex(xid.ToString()) << ") ";
    return Status::OK();
1926 1927
  }

1928
  virtual ~InMemoryHandler() {}
1929

1930
 private:
1931
  std::stringstream& row_;
1932
  bool print_values_;
1933 1934
};

1935 1936 1937 1938
void DumpWalFile(std::string wal_file, bool print_header, bool print_values,
                 LDBCommandExecuteResult* exec_state) {
  Env* env_ = Env::Default();
  EnvOptions soptions;
1939 1940 1941 1942 1943 1944 1945 1946 1947 1948
  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)));
    }
  }
1949 1950
  if (!status.ok()) {
    if (exec_state) {
1951
      *exec_state = LDBCommandExecuteResult::Failed("Failed to open WAL file " +
1952 1953
                                                    status.ToString());
    } else {
1954 1955
      std::cerr << "Error: Failed to open WAL file " << status.ToString()
                << std::endl;
1956 1957 1958
    }
  } else {
    StdErrReporter reporter;
1959 1960 1961 1962
    uint64_t log_number;
    FileType type;

    // we need the log number, but ParseFilename expects dbname/NNN.log.
1963
    std::string sanitized = wal_file;
1964 1965 1966 1967 1968 1969 1970 1971
    size_t lastslash = sanitized.rfind('/');
    if (lastslash != std::string::npos)
      sanitized = sanitized.substr(lastslash + 1);
    if (!ParseFileName(sanitized, &log_number, &type)) {
      // bogus input, carry on as best we can
      log_number = 0;
    }
    DBOptions db_options;
1972 1973 1974
    log::Reader reader(db_options.info_log, std::move(wal_file_reader),
                       &reporter, true, 0, log_number);
    std::string scratch;
1975 1976
    WriteBatch batch;
    Slice record;
1977
    std::stringstream row;
1978
    if (print_header) {
1979
      std::cout << "Sequence,Count,ByteSize,Physical Offset,Key(s)";
1980
      if (print_values) {
1981
        std::cout << " : value ";
1982
      }
1983
      std::cout << "\n";
1984 1985 1986
    }
    while (reader.ReadRecord(&record, &scratch)) {
      row.str("");
1987
      if (record.size() < WriteBatchInternal::kHeader) {
1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999
        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";
      }
2000
      std::cout << row.str();
2001 2002 2003 2004 2005 2006
    }
  }
}

}  // namespace

2007 2008 2009
const std::string WALDumperCommand::ARG_WAL_FILE = "walfile";
const std::string WALDumperCommand::ARG_PRINT_VALUE = "print_value";
const std::string WALDumperCommand::ARG_PRINT_HEADER = "header";
2010

2011
WALDumperCommand::WALDumperCommand(
2012
    const std::vector<std::string>& params,
2013 2014 2015 2016 2017 2018 2019
    const std::map<std::string, std::string>& options,
    const std::vector<std::string>& flags)
    : LDBCommand(options, flags, true,
                 BuildCmdLineOptions(
                     {ARG_WAL_FILE, ARG_PRINT_HEADER, ARG_PRINT_VALUE})),
      print_header_(false),
      print_values_(false) {
A
Abhishek Kona 已提交
2020
  wal_file_.clear();
2021

2022 2023
  std::map<std::string, std::string>::const_iterator itr =
      options.find(ARG_WAL_FILE);
2024 2025
  if (itr != options.end()) {
    wal_file_ = itr->second;
A
Abhishek Kona 已提交
2026
  }
2027 2028


2029 2030
  print_header_ = IsFlagPresent(flags, ARG_PRINT_HEADER);
  print_values_ = IsFlagPresent(flags, ARG_PRINT_VALUE);
A
Abhishek Kona 已提交
2031
  if (wal_file_.empty()) {
2032 2033
    exec_state_ = LDBCommandExecuteResult::Failed("Argument " + ARG_WAL_FILE +
                                                  " must be specified.");
A
Abhishek Kona 已提交
2034 2035 2036
  }
}

2037
void WALDumperCommand::Help(std::string& ret) {
2038 2039 2040 2041 2042 2043
  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 已提交
2044 2045
}

2046
void WALDumperCommand::DoCommand() {
2047
  DumpWalFile(wal_file_, print_header_, print_values_, &exec_state_);
A
Abhishek Kona 已提交
2048 2049
}

2050
// ----------------------------------------------------------------------------
2051

2052 2053 2054 2055 2056 2057
GetCommand::GetCommand(const std::vector<std::string>& params,
                       const std::map<std::string, std::string>& options,
                       const std::vector<std::string>& flags)
    : LDBCommand(
          options, flags, true,
          BuildCmdLineOptions({ARG_TTL, ARG_HEX, ARG_KEY_HEX, ARG_VALUE_HEX})) {
2058
  if (params.size() != 1) {
2059
    exec_state_ = LDBCommandExecuteResult::Failed(
2060
        "<key> must be specified for the get command");
2061 2062 2063 2064 2065 2066 2067 2068 2069
  } else {
    key_ = params.at(0);
  }

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

2070
void GetCommand::Help(std::string& ret) {
2071 2072 2073 2074 2075
  ret.append("  ");
  ret.append(GetCommand::Name());
  ret.append(" <key>");
  ret.append(" [--" + ARG_TTL + "]");
  ret.append("\n");
2076 2077 2078
}

void GetCommand::DoCommand() {
S
sdong 已提交
2079 2080 2081 2082
  if (!db_) {
    assert(GetExecuteState().IsFailed());
    return;
  }
2083
  std::string value;
S
sdong 已提交
2084
  Status st = db_->Get(ReadOptions(), GetCfHandle(), key_, &value);
2085 2086 2087 2088
  if (st.ok()) {
    fprintf(stdout, "%s\n",
              (is_value_hex_ ? StringToHex(value) : value).c_str());
  } else {
2089
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
2090 2091 2092
  }
}

2093
// ----------------------------------------------------------------------------
2094

2095
ApproxSizeCommand::ApproxSizeCommand(
2096
    const std::vector<std::string>& params,
2097 2098 2099 2100 2101
    const std::map<std::string, std::string>& options,
    const std::vector<std::string>& flags)
    : LDBCommand(options, flags, true,
                 BuildCmdLineOptions(
                     {ARG_HEX, ARG_KEY_HEX, ARG_VALUE_HEX, ARG_FROM, ARG_TO})) {
2102 2103 2104
  if (options.find(ARG_FROM) != options.end()) {
    start_key_ = options.find(ARG_FROM)->second;
  } else {
2105 2106
    exec_state_ = LDBCommandExecuteResult::Failed(
        ARG_FROM + " must be specified for approxsize command");
2107 2108 2109 2110 2111 2112
    return;
  }

  if (options.find(ARG_TO) != options.end()) {
    end_key_ = options.find(ARG_TO)->second;
  } else {
2113 2114
    exec_state_ = LDBCommandExecuteResult::Failed(
        ARG_TO + " must be specified for approxsize command");
2115 2116 2117 2118 2119 2120 2121 2122 2123
    return;
  }

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

2124
void ApproxSizeCommand::Help(std::string& ret) {
2125 2126 2127 2128
  ret.append("  ");
  ret.append(ApproxSizeCommand::Name());
  ret.append(HelpRangeCmdArgs());
  ret.append("\n");
2129 2130 2131
}

void ApproxSizeCommand::DoCommand() {
S
sdong 已提交
2132 2133 2134 2135
  if (!db_) {
    assert(GetExecuteState().IsFailed());
    return;
  }
2136 2137
  Range ranges[1];
  ranges[0] = Range(start_key_, end_key_);
2138
  uint64_t sizes[1];
S
sdong 已提交
2139
  db_->GetApproximateSizes(GetCfHandle(), ranges, 1, sizes);
K
Kai Liu 已提交
2140
  fprintf(stdout, "%lu\n", (unsigned long)sizes[0]);
2141
  /* Weird that GetApproximateSizes() returns void, although documentation
2142 2143
   * says that it returns a Status object.
  if (!st.ok()) {
2144
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
2145 2146 2147 2148
  }
  */
}

2149
// ----------------------------------------------------------------------------
2150

2151 2152 2153 2154 2155 2156 2157
BatchPutCommand::BatchPutCommand(
    const std::vector<std::string>& params,
    const std::map<std::string, std::string>& options,
    const std::vector<std::string>& flags)
    : LDBCommand(options, flags, false,
                 BuildCmdLineOptions({ARG_TTL, ARG_HEX, ARG_KEY_HEX,
                                      ARG_VALUE_HEX, ARG_CREATE_IF_MISSING})) {
2158
  if (params.size() < 2) {
2159
    exec_state_ = LDBCommandExecuteResult::Failed(
2160
        "At least one <key> <value> pair must be specified batchput.");
2161
  } else if (params.size() % 2 != 0) {
2162
    exec_state_ = LDBCommandExecuteResult::Failed(
2163 2164 2165
        "Equal number of <key>s and <value>s must be specified for batchput.");
  } else {
    for (size_t i = 0; i < params.size(); i += 2) {
2166 2167 2168 2169 2170
      std::string key = params.at(i);
      std::string value = params.at(i + 1);
      key_values_.push_back(std::pair<std::string, std::string>(
          is_key_hex_ ? HexToString(key) : key,
          is_value_hex_ ? HexToString(value) : value));
2171 2172
    }
  }
2173
  create_if_missing_ = IsFlagPresent(flags_, ARG_CREATE_IF_MISSING);
2174 2175
}

2176
void BatchPutCommand::Help(std::string& ret) {
2177 2178 2179 2180 2181
  ret.append("  ");
  ret.append(BatchPutCommand::Name());
  ret.append(" <key> <value> [<key> <value>] [..]");
  ret.append(" [--" + ARG_TTL + "]");
  ret.append("\n");
2182 2183 2184
}

void BatchPutCommand::DoCommand() {
S
sdong 已提交
2185 2186 2187 2188
  if (!db_) {
    assert(GetExecuteState().IsFailed());
    return;
  }
2189
  WriteBatch batch;
2190

2191 2192 2193
  for (std::vector<std::pair<std::string, std::string>>::const_iterator itr =
           key_values_.begin();
       itr != key_values_.end(); ++itr) {
S
sdong 已提交
2194
    batch.Put(GetCfHandle(), itr->first, itr->second);
2195
  }
2196
  Status st = db_->Write(WriteOptions(), &batch);
2197 2198 2199
  if (st.ok()) {
    fprintf(stdout, "OK\n");
  } else {
2200
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
2201 2202 2203
  }
}

2204 2205
Options BatchPutCommand::PrepareOptionsForOpenDB() {
  Options opt = LDBCommand::PrepareOptionsForOpenDB();
2206
  opt.create_if_missing = create_if_missing_;
2207 2208 2209
  return opt;
}

2210
// ----------------------------------------------------------------------------
2211

2212
ScanCommand::ScanCommand(const std::vector<std::string>& params,
2213 2214 2215 2216 2217 2218 2219
                         const std::map<std::string, std::string>& options,
                         const std::vector<std::string>& flags)
    : LDBCommand(
          options, flags, true,
          BuildCmdLineOptions({ARG_TTL, ARG_NO_VALUE, ARG_HEX, ARG_KEY_HEX,
                               ARG_TO, ARG_VALUE_HEX, ARG_FROM, ARG_TIMESTAMP,
                               ARG_MAX_KEYS, ARG_TTL_START, ARG_TTL_END})),
A
Alexander Fenster 已提交
2220 2221 2222 2223
      start_key_specified_(false),
      end_key_specified_(false),
      max_keys_scanned_(-1),
      no_value_(false) {
2224 2225
  std::map<std::string, std::string>::const_iterator itr =
      options.find(ARG_FROM);
2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241
  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;
  }

2242
  std::vector<std::string>::const_iterator vitr =
A
Alexander Fenster 已提交
2243
      std::find(flags.begin(), flags.end(), ARG_NO_VALUE);
2244 2245 2246 2247
  if (vitr != flags.end()) {
    no_value_ = true;
  }

2248 2249 2250
  itr = options.find(ARG_MAX_KEYS);
  if (itr != options.end()) {
    try {
S
sdong 已提交
2251 2252 2253
#if defined(CYGWIN)
      max_keys_scanned_ = strtol(itr->second.c_str(), 0, 10);
#else
2254
      max_keys_scanned_ = std::stoi(itr->second);
S
sdong 已提交
2255
#endif
2256
    } catch (const std::invalid_argument&) {
2257
      exec_state_ = LDBCommandExecuteResult::Failed(ARG_MAX_KEYS +
2258
                                                    " has an invalid value");
2259
    } catch (const std::out_of_range&) {
2260 2261
      exec_state_ = LDBCommandExecuteResult::Failed(
          ARG_MAX_KEYS + " has a value out-of-range");
2262 2263 2264 2265
    }
  }
}

2266
void ScanCommand::Help(std::string& ret) {
2267 2268 2269 2270 2271 2272 2273 2274
  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]");
2275
  ret.append(" [--" + ARG_NO_VALUE + "]");
2276
  ret.append("\n");
2277 2278 2279
}

void ScanCommand::DoCommand() {
S
sdong 已提交
2280 2281 2282 2283
  if (!db_) {
    assert(GetExecuteState().IsFailed());
    return;
  }
2284 2285

  int num_keys_scanned = 0;
S
sdong 已提交
2286
  Iterator* it = db_->NewIterator(ReadOptions(), GetCfHandle());
2287 2288 2289 2290 2291
  if (start_key_specified_) {
    it->Seek(start_key_);
  } else {
    it->SeekToFirst();
  }
2292
  int ttl_start;
2293
  if (!ParseIntOption(option_map_, ARG_TTL_START, ttl_start, exec_state_)) {
2294
    ttl_start = DBWithTTLImpl::kMinTimestamp;  // TTL introduction time
2295 2296
  }
  int ttl_end;
2297
  if (!ParseIntOption(option_map_, ARG_TTL_END, ttl_end, exec_state_)) {
2298
    ttl_end = DBWithTTLImpl::kMaxTimestamp;  // Max time allowed by TTL feature
2299 2300 2301 2302 2303 2304 2305 2306 2307 2308
  }
  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());
  }
2309
  for ( ;
2310 2311
        it->Valid() && (!end_key_specified_ || it->key().ToString() < end_key_);
        it->Next()) {
2312
    if (is_db_ttl_) {
S
Siying Dong 已提交
2313
      TtlIterator* it_ttl = static_cast_with_check<TtlIterator, Iterator>(it);
2314 2315
      int rawtime = it_ttl->timestamp();
      if (rawtime < ttl_start || rawtime >= ttl_end) {
2316 2317 2318 2319 2320 2321
        continue;
      }
      if (timestamp_) {
        fprintf(stdout, "%s ", ReadableTime(rawtime).c_str());
      }
    }
2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333

    Slice key_slice = it->key();

    std::string formatted_key;
    if (is_key_hex_) {
      formatted_key = "0x" + key_slice.ToString(true /* hex */);
      key_slice = formatted_key;
    } else if (ldb_options_.key_formatter) {
      formatted_key = ldb_options_.key_formatter->Format(key_slice);
      key_slice = formatted_key;
    }

2334
    if (no_value_) {
A
Alexander Fenster 已提交
2335 2336
      fprintf(stdout, "%.*s\n", static_cast<int>(key_slice.size()),
              key_slice.data());
2337
    } else {
A
Alexander Fenster 已提交
2338 2339 2340 2341 2342 2343 2344 2345 2346
      Slice val_slice = it->value();
      std::string formatted_value;
      if (is_value_hex_) {
        formatted_value = "0x" + val_slice.ToString(true /* hex */);
        val_slice = formatted_value;
      }
      fprintf(stdout, "%.*s : %.*s\n", static_cast<int>(key_slice.size()),
              key_slice.data(), static_cast<int>(val_slice.size()),
              val_slice.data());
2347 2348
    }

2349 2350 2351 2352 2353 2354
    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
2355
    exec_state_ = LDBCommandExecuteResult::Failed(it->status().ToString());
2356 2357 2358 2359
  }
  delete it;
}

2360
// ----------------------------------------------------------------------------
2361

2362 2363 2364 2365 2366
DeleteCommand::DeleteCommand(const std::vector<std::string>& params,
                             const std::map<std::string, std::string>& options,
                             const std::vector<std::string>& flags)
    : LDBCommand(options, flags, false,
                 BuildCmdLineOptions({ARG_HEX, ARG_KEY_HEX, ARG_VALUE_HEX})) {
2367
  if (params.size() != 1) {
2368
    exec_state_ = LDBCommandExecuteResult::Failed(
2369
        "KEY must be specified for the delete command");
2370 2371 2372 2373 2374 2375 2376 2377
  } else {
    key_ = params.at(0);
    if (is_key_hex_) {
      key_ = HexToString(key_);
    }
  }
}

2378
void DeleteCommand::Help(std::string& ret) {
2379 2380 2381
  ret.append("  ");
  ret.append(DeleteCommand::Name() + " <key>");
  ret.append("\n");
2382 2383 2384
}

void DeleteCommand::DoCommand() {
S
sdong 已提交
2385 2386 2387 2388 2389
  if (!db_) {
    assert(GetExecuteState().IsFailed());
    return;
  }
  Status st = db_->Delete(WriteOptions(), GetCfHandle(), key_);
2390 2391 2392
  if (st.ok()) {
    fprintf(stdout, "OK\n");
  } else {
2393
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
2394 2395 2396
  }
}

A
Andrew Kryczka 已提交
2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435
DeleteRangeCommand::DeleteRangeCommand(
    const std::vector<std::string>& params,
    const std::map<std::string, std::string>& options,
    const std::vector<std::string>& flags)
    : LDBCommand(options, flags, false,
                 BuildCmdLineOptions({ARG_HEX, ARG_KEY_HEX, ARG_VALUE_HEX})) {
  if (params.size() != 2) {
    exec_state_ = LDBCommandExecuteResult::Failed(
        "begin and end keys must be specified for the delete command");
  } else {
    begin_key_ = params.at(0);
    end_key_ = params.at(1);
    if (is_key_hex_) {
      begin_key_ = HexToString(begin_key_);
      end_key_ = HexToString(end_key_);
    }
  }
}

void DeleteRangeCommand::Help(std::string& ret) {
  ret.append("  ");
  ret.append(DeleteRangeCommand::Name() + " <begin key> <end key>");
  ret.append("\n");
}

void DeleteRangeCommand::DoCommand() {
  if (!db_) {
    assert(GetExecuteState().IsFailed());
    return;
  }
  Status st =
      db_->DeleteRange(WriteOptions(), GetCfHandle(), begin_key_, end_key_);
  if (st.ok()) {
    fprintf(stdout, "OK\n");
  } else {
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
  }
}

2436 2437 2438 2439 2440 2441
PutCommand::PutCommand(const std::vector<std::string>& params,
                       const std::map<std::string, std::string>& options,
                       const std::vector<std::string>& flags)
    : LDBCommand(options, flags, false,
                 BuildCmdLineOptions({ARG_TTL, ARG_HEX, ARG_KEY_HEX,
                                      ARG_VALUE_HEX, ARG_CREATE_IF_MISSING})) {
2442
  if (params.size() != 2) {
2443
    exec_state_ = LDBCommandExecuteResult::Failed(
2444
        "<key> and <value> must be specified for the put command");
2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456
  } else {
    key_ = params.at(0);
    value_ = params.at(1);
  }

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

  if (is_value_hex_) {
    value_ = HexToString(value_);
  }
2457
  create_if_missing_ = IsFlagPresent(flags_, ARG_CREATE_IF_MISSING);
2458 2459
}

2460
void PutCommand::Help(std::string& ret) {
2461 2462 2463 2464 2465
  ret.append("  ");
  ret.append(PutCommand::Name());
  ret.append(" <key> <value> ");
  ret.append(" [--" + ARG_TTL + "]");
  ret.append("\n");
2466 2467 2468
}

void PutCommand::DoCommand() {
S
sdong 已提交
2469 2470 2471 2472 2473
  if (!db_) {
    assert(GetExecuteState().IsFailed());
    return;
  }
  Status st = db_->Put(WriteOptions(), GetCfHandle(), key_, value_);
2474 2475 2476
  if (st.ok()) {
    fprintf(stdout, "OK\n");
  } else {
2477
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
2478 2479 2480
  }
}

2481 2482
Options PutCommand::PrepareOptionsForOpenDB() {
  Options opt = LDBCommand::PrepareOptionsForOpenDB();
2483
  opt.create_if_missing = create_if_missing_;
2484 2485 2486
  return opt;
}

2487
// ----------------------------------------------------------------------------
2488 2489 2490 2491 2492 2493

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

2494
DBQuerierCommand::DBQuerierCommand(
2495
    const std::vector<std::string>& params,
2496 2497 2498 2499 2500
    const std::map<std::string, std::string>& options,
    const std::vector<std::string>& flags)
    : LDBCommand(
          options, flags, false,
          BuildCmdLineOptions({ARG_TTL, ARG_HEX, ARG_KEY_HEX, ARG_VALUE_HEX})) {
2501 2502 2503

}

2504
void DBQuerierCommand::Help(std::string& ret) {
2505 2506 2507 2508 2509
  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 "
2510
             "commands.");
2511
  ret.append("\n");
2512 2513 2514 2515
}

void DBQuerierCommand::DoCommand() {
  if (!db_) {
S
sdong 已提交
2516
    assert(GetExecuteState().IsFailed());
2517 2518
    return;
  }
2519

2520 2521
  ReadOptions read_options;
  WriteOptions write_options;
2522

2523 2524 2525 2526 2527 2528
  std::string line;
  std::string key;
  std::string value;
  while (getline(std::cin, line, '\n')) {
    // Parse line into std::vector<std::string>
    std::vector<std::string> tokens;
2529 2530 2531
    size_t pos = 0;
    while (true) {
      size_t pos2 = line.find(' ', pos);
2532
      if (pos2 == std::string::npos) {
2533 2534 2535 2536 2537 2538 2539
        break;
      }
      tokens.push_back(line.substr(pos, pos2-pos));
      pos = pos2 + 1;
    }
    tokens.push_back(line.substr(pos));

2540
    const std::string& cmd = tokens[0];
2541 2542 2543 2544 2545 2546 2547 2548

    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]);
S
sdong 已提交
2549
      db_->Delete(write_options, GetCfHandle(), Slice(key));
2550 2551 2552 2553
      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]);
S
sdong 已提交
2554
      db_->Put(write_options, GetCfHandle(), Slice(key), Slice(value));
2555 2556 2557 2558
      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]);
S
sdong 已提交
2559
      if (db_->Get(read_options, GetCfHandle(), Slice(key), &value).ok()) {
2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570
        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());
    }
  }
}

2571 2572
// ----------------------------------------------------------------------------

2573
CheckConsistencyCommand::CheckConsistencyCommand(
2574
    const std::vector<std::string>& params,
2575 2576 2577
    const std::map<std::string, std::string>& options,
    const std::vector<std::string>& flags)
    : LDBCommand(options, flags, false, BuildCmdLineOptions({})) {}
Y
Yiting Li 已提交
2578

2579
void CheckConsistencyCommand::Help(std::string& ret) {
2580 2581 2582
  ret.append("  ");
  ret.append(CheckConsistencyCommand::Name());
  ret.append("\n");
Y
Yiting Li 已提交
2583
}
2584

Y
Yiting Li 已提交
2585 2586
void CheckConsistencyCommand::DoCommand() {
  Options opt = PrepareOptionsForOpenDB();
I
Igor Canadi 已提交
2587
  opt.paranoid_checks = true;
Y
Yiting Li 已提交
2588 2589 2590
  if (!exec_state_.IsNotStarted()) {
    return;
  }
I
Igor Canadi 已提交
2591 2592 2593
  DB* db;
  Status st = DB::OpenForReadOnly(opt, db_path_, &db, false);
  delete db;
Y
Yiting Li 已提交
2594 2595 2596
  if (st.ok()) {
    fprintf(stdout, "OK\n");
  } else {
2597
    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());
Y
Yiting Li 已提交
2598
  }
2599
}
Y
Yiting Li 已提交
2600

2601
// ----------------------------------------------------------------------------
A
Andrew Kryczka 已提交
2602

A
Aaron Gao 已提交
2603 2604 2605
const std::string CheckPointCommand::ARG_CHECKPOINT_DIR = "checkpoint_dir";

CheckPointCommand::CheckPointCommand(
2606
    const std::vector<std::string>& params,
A
Aaron Gao 已提交
2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643
    const std::map<std::string, std::string>& options,
    const std::vector<std::string>& flags)
    : LDBCommand(options, flags, false /* is_read_only */,
                 BuildCmdLineOptions({ARG_CHECKPOINT_DIR})) {
  auto itr = options.find(ARG_CHECKPOINT_DIR);
  if (itr == options.end()) {
    exec_state_ = LDBCommandExecuteResult::Failed(
        "--" + ARG_CHECKPOINT_DIR + ": missing checkpoint directory");
  } else {
    checkpoint_dir_ = itr->second;
  }
}

void CheckPointCommand::Help(std::string& ret) {
  ret.append("  ");
  ret.append(CheckPointCommand::Name());
  ret.append(" [--" + ARG_CHECKPOINT_DIR + "] ");
  ret.append("\n");
}

void CheckPointCommand::DoCommand() {
  if (!db_) {
    assert(GetExecuteState().IsFailed());
    return;
  }
  Checkpoint* checkpoint;
  Status status = Checkpoint::Create(db_, &checkpoint);
  status = checkpoint->CreateCheckpoint(checkpoint_dir_);
  if (status.ok()) {
    printf("OK\n");
  } else {
    exec_state_ = LDBCommandExecuteResult::Failed(status.ToString());
  }
}

// ----------------------------------------------------------------------------

2644
RepairCommand::RepairCommand(const std::vector<std::string>& params,
2645 2646
                             const std::map<std::string, std::string>& options,
                             const std::vector<std::string>& flags)
A
Andrew Kryczka 已提交
2647 2648
    : LDBCommand(options, flags, false, BuildCmdLineOptions({})) {}

2649
void RepairCommand::Help(std::string& ret) {
A
Andrew Kryczka 已提交
2650 2651 2652 2653 2654 2655 2656
  ret.append("  ");
  ret.append(RepairCommand::Name());
  ret.append("\n");
}

void RepairCommand::DoCommand() {
  Options options = PrepareOptionsForOpenDB();
A
Andrew Kryczka 已提交
2657
  options.info_log.reset(new StderrLogger(InfoLogLevel::WARN_LEVEL));
A
Andrew Kryczka 已提交
2658 2659 2660 2661 2662 2663 2664 2665 2666
  Status status = RepairDB(db_path_, options);
  if (status.ok()) {
    printf("OK\n");
  } else {
    exec_state_ = LDBCommandExecuteResult::Failed(status.ToString());
  }
}

// ----------------------------------------------------------------------------
W
Wanning Jiang 已提交
2667

2668 2669 2670 2671
const std::string BackupableCommand::ARG_NUM_THREADS = "num_threads";
const std::string BackupableCommand::ARG_BACKUP_ENV_URI = "backup_env_uri";
const std::string BackupableCommand::ARG_BACKUP_DIR = "backup_dir";
const std::string BackupableCommand::ARG_STDERR_LOG_LEVEL = "stderr_log_level";
W
Wanning Jiang 已提交
2672

2673
BackupableCommand::BackupableCommand(
2674
    const std::vector<std::string>& params,
2675 2676 2677 2678 2679 2680 2681
    const std::map<std::string, std::string>& options,
    const std::vector<std::string>& flags)
    : LDBCommand(options, flags, false /* is_read_only */,
                 BuildCmdLineOptions({ARG_BACKUP_ENV_URI, ARG_BACKUP_DIR,
                                      ARG_NUM_THREADS, ARG_STDERR_LOG_LEVEL})),
      num_threads_(1) {
  auto itr = options.find(ARG_NUM_THREADS);
W
Wanning Jiang 已提交
2682
  if (itr != options.end()) {
2683
    num_threads_ = std::stoi(itr->second);
W
Wanning Jiang 已提交
2684
  }
2685
  itr = options.find(ARG_BACKUP_ENV_URI);
A
Andrew Kryczka 已提交
2686
  if (itr != options.end()) {
2687
    backup_env_uri_ = itr->second;
W
Wanning Jiang 已提交
2688 2689 2690 2691 2692 2693
  }
  itr = options.find(ARG_BACKUP_DIR);
  if (itr == options.end()) {
    exec_state_ = LDBCommandExecuteResult::Failed("--" + ARG_BACKUP_DIR +
                                                  ": missing backup directory");
  } else {
2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708
    backup_dir_ = itr->second;
  }

  itr = options.find(ARG_STDERR_LOG_LEVEL);
  if (itr != options.end()) {
    int stderr_log_level = std::stoi(itr->second);
    if (stderr_log_level < 0 ||
        stderr_log_level >= InfoLogLevel::NUM_INFO_LOG_LEVELS) {
      exec_state_ = LDBCommandExecuteResult::Failed(
          ARG_STDERR_LOG_LEVEL + " must be >= 0 and < " +
          std::to_string(InfoLogLevel::NUM_INFO_LOG_LEVELS) + ".");
    } else {
      logger_.reset(
          new StderrLogger(static_cast<InfoLogLevel>(stderr_log_level)));
    }
W
Wanning Jiang 已提交
2709 2710 2711
  }
}

2712
void BackupableCommand::Help(const std::string& name, std::string& ret) {
W
Wanning Jiang 已提交
2713
  ret.append("  ");
2714 2715
  ret.append(name);
  ret.append(" [--" + ARG_BACKUP_ENV_URI + "] ");
W
Wanning Jiang 已提交
2716
  ret.append(" [--" + ARG_BACKUP_DIR + "] ");
2717 2718
  ret.append(" [--" + ARG_NUM_THREADS + "] ");
  ret.append(" [--" + ARG_STDERR_LOG_LEVEL + "=<int (InfoLogLevel)>] ");
W
Wanning Jiang 已提交
2719 2720 2721
  ret.append("\n");
}

2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732
// ----------------------------------------------------------------------------

BackupCommand::BackupCommand(const std::vector<std::string>& params,
                             const std::map<std::string, std::string>& options,
                             const std::vector<std::string>& flags)
    : BackupableCommand(params, options, flags) {}

void BackupCommand::Help(std::string& ret) {
  BackupableCommand::Help(Name(), ret);
}

W
Wanning Jiang 已提交
2733 2734 2735 2736 2737 2738 2739 2740 2741
void BackupCommand::DoCommand() {
  BackupEngine* backup_engine;
  Status status;
  if (!db_) {
    assert(GetExecuteState().IsFailed());
    return;
  }
  printf("open db OK\n");
  std::unique_ptr<Env> custom_env_guard;
2742
  Env* custom_env = NewCustomObject<Env>(backup_env_uri_, &custom_env_guard);
W
Wanning Jiang 已提交
2743
  BackupableDBOptions backup_options =
2744 2745 2746
      BackupableDBOptions(backup_dir_, custom_env);
  backup_options.info_log = logger_.get();
  backup_options.max_background_operations = num_threads_;
W
Wanning Jiang 已提交
2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763
  status = BackupEngine::Open(Env::Default(), backup_options, &backup_engine);
  if (status.ok()) {
    printf("open backup engine OK\n");
  } else {
    exec_state_ = LDBCommandExecuteResult::Failed(status.ToString());
    return;
  }
  status = backup_engine->CreateNewBackup(db_);
  if (status.ok()) {
    printf("create new backup OK\n");
  } else {
    exec_state_ = LDBCommandExecuteResult::Failed(status.ToString());
    return;
  }
}

// ----------------------------------------------------------------------------
A
Andrew Kryczka 已提交
2764 2765 2766 2767 2768

RestoreCommand::RestoreCommand(
    const std::vector<std::string>& params,
    const std::map<std::string, std::string>& options,
    const std::vector<std::string>& flags)
2769
    : BackupableCommand(params, options, flags) {}
A
Andrew Kryczka 已提交
2770 2771

void RestoreCommand::Help(std::string& ret) {
2772
  BackupableCommand::Help(Name(), ret);
A
Andrew Kryczka 已提交
2773 2774 2775 2776
}

void RestoreCommand::DoCommand() {
  std::unique_ptr<Env> custom_env_guard;
2777
  Env* custom_env = NewCustomObject<Env>(backup_env_uri_, &custom_env_guard);
A
Andrew Kryczka 已提交
2778 2779 2780 2781
  std::unique_ptr<BackupEngineReadOnly> restore_engine;
  Status status;
  {
    BackupableDBOptions opts(backup_dir_, custom_env);
2782
    opts.info_log = logger_.get();
A
Andrew Kryczka 已提交
2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802
    opts.max_background_operations = num_threads_;
    BackupEngineReadOnly* raw_restore_engine_ptr;
    status = BackupEngineReadOnly::Open(Env::Default(), opts,
                                        &raw_restore_engine_ptr);
    if (status.ok()) {
      restore_engine.reset(raw_restore_engine_ptr);
    }
  }
  if (status.ok()) {
    printf("open restore engine OK\n");
    status = restore_engine->RestoreDBFromLatestBackup(db_path_, db_path_);
  }
  if (status.ok()) {
    printf("restore from backup OK\n");
  } else {
    exec_state_ = LDBCommandExecuteResult::Failed(status.ToString());
  }
}

// ----------------------------------------------------------------------------
2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815

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);
2816
  Status st = reader.ReadSequential(true, std::numeric_limits<uint64_t>::max(), false,  // has_from
2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850
                                    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

2851
DBFileDumperCommand::DBFileDumperCommand(
2852
    const std::vector<std::string>& params,
2853 2854
    const std::map<std::string, std::string>& options,
    const std::vector<std::string>& flags)
2855 2856
    : LDBCommand(options, flags, true, BuildCmdLineOptions({})) {}

2857
void DBFileDumperCommand::Help(std::string& ret) {
2858 2859 2860 2861 2862 2863 2864
  ret.append("  ");
  ret.append(DBFileDumperCommand::Name());
  ret.append("\n");
}

void DBFileDumperCommand::DoCommand() {
  if (!db_) {
S
sdong 已提交
2865
    assert(GetExecuteState().IsFailed());
2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881
    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);
2882
  std::string manifest_filepath = db_->GetName() + "/" + manifest_filename;
2883
  std::cout << manifest_filepath << std::endl;
2884
  DumpManifestFile(manifest_filepath, false, false, false);
2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915
  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 已提交
2916
}   // namespace rocksdb
I
Igor Canadi 已提交
2917
#endif  // ROCKSDB_LITE