| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437 | 
//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.//  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).//#ifndef ROCKSDB_LITE#include "rocksdb/utilities/ldb_cmd.h"#include <cinttypes>#include "db/db_impl/db_impl.h"#include "db/dbformat.h"#include "db/log_reader.h"#include "db/write_batch_internal.h"#include "env/composite_env_wrapper.h"#include "file/filename.h"#include "port/port_dirent.h"#include "rocksdb/cache.h"#include "rocksdb/file_checksum.h"#include "rocksdb/table_properties.h"#include "rocksdb/utilities/backupable_db.h"#include "rocksdb/utilities/checkpoint.h"#include "rocksdb/utilities/debug.h"#include "rocksdb/utilities/options_util.h"#include "rocksdb/write_batch.h"#include "rocksdb/write_buffer_manager.h"#include "table/scoped_arena_iterator.h"#include "tools/ldb_cmd_impl.h"#include "tools/sst_dump_tool_imp.h"#include "util/cast_util.h"#include "util/coding.h"#include "util/file_checksum_helper.h"#include "util/stderr_logger.h"#include "util/string_util.h"#include "utilities/merge_operators.h"#include "utilities/ttl/db_ttl_impl.h"#include <cstdlib>#include <ctime>#include <fstream>#include <functional>#include <iostream>#include <limits>#include <sstream>#include <stdexcept>#include <string>namespace ROCKSDB_NAMESPACE {class FileChecksumFuncCrc32c;const std::string LDBCommand::ARG_ENV_URI = "env_uri";const std::string LDBCommand::ARG_DB = "db";const std::string LDBCommand::ARG_PATH = "path";const std::string LDBCommand::ARG_SECONDARY_PATH = "secondary_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";const std::string LDBCommand::ARG_TRY_LOAD_OPTIONS = "try_load_options";const std::string LDBCommand::ARG_IGNORE_UNKNOWN_OPTIONS =    "ignore_unknown_options";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 =    "compression_max_dict_bytes";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";const char* LDBCommand::DELIM = " ==> ";namespace {void DumpWalFile(Options options, std::string wal_file, bool print_header,                 bool print_values, bool is_write_committed,                 LDBCommandExecuteResult* exec_state);void DumpSstFile(Options options, std::string filename, bool output_hex,                 bool show_properties);};LDBCommand* LDBCommand::InitFromCmdLineArgs(    int argc, char** argv, const Options& options,    const LDBOptions& ldb_options,    const std::vector<ColumnFamilyDescriptor>* column_families) {  std::vector<std::string> args;  for (int i = 1; i < argc; i++) {    args.push_back(argv[i]);  }  return InitFromCmdLineArgs(args, options, ldb_options, column_families,                             SelectCommand);}/** * Parse the command-line arguments and create the appropriate LDBCommand2 * instance. * The command line arguments must be in the following format: * ./ldb --db=PATH_TO_DB [--commonOpt1=commonOpt1Val] .. *        COMMAND <PARAM1> <PARAM2> ... [-cmdSpecificOpt1=cmdSpecificOpt1Val] .. * This is similar to the command line format used by HBaseClientTool. * Command name is not included in args. * Returns nullptr if the command-line cannot be parsed. */LDBCommand* LDBCommand::InitFromCmdLineArgs(    const std::vector<std::string>& args, const Options& options,    const LDBOptions& ldb_options,    const std::vector<ColumnFamilyDescriptor>* /*column_families*/,    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;  // Everything other than option_map and flags. Represents commands  // and their parameters.  For eg: put key1 value1 go into this vector.  std::vector<std::string> cmdTokens;  const std::string OPTION_PREFIX = "--";  for (const auto& arg : args) {    if (arg[0] == '-' && arg[1] == '-'){      std::vector<std::string> splits = StringSplit(arg, '=');      // --option_name=option_value      if (splits.size() == 2) {        std::string optionKey = splits[0].substr(OPTION_PREFIX.size());        parsed_params.option_map[optionKey] = splits[1];      } else if (splits.size() == 1) {        // --flag_name        std::string optionKey = splits[0].substr(OPTION_PREFIX.size());        parsed_params.flags.push_back(optionKey);      } else {        // --option_name=option_value, option_value contains '='        std::string optionKey = splits[0].substr(OPTION_PREFIX.size());        parsed_params.option_map[optionKey] =            arg.substr(splits[0].length() + 1);      }    } else {      cmdTokens.push_back(arg);    }  }  if (cmdTokens.size() < 1) {    fprintf(stderr, "Command not specified!");    return nullptr;  }  parsed_params.cmd = cmdTokens[0];  parsed_params.cmd_params.assign(cmdTokens.begin() + 1, cmdTokens.end());  LDBCommand* command = selector(parsed_params);  if (command) {    command->SetDBOptions(options);    command->SetLDBOptions(ldb_options);  }  return command;}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);  } else if (parsed_params.cmd == DeleteRangeCommand::Name()) {    return new DeleteRangeCommand(parsed_params.cmd_params,                                  parsed_params.option_map,                                  parsed_params.flags);  } 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 == FileChecksumDumpCommand::Name()) {    return new FileChecksumDumpCommand(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 == DropColumnFamilyCommand::Name()) {    return new DropColumnFamilyCommand(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);  } else if (parsed_params.cmd == CheckPointCommand::Name()) {    return new CheckPointCommand(parsed_params.cmd_params,                                 parsed_params.option_map,                                 parsed_params.flags);  } else if (parsed_params.cmd == RepairCommand::Name()) {    return new RepairCommand(parsed_params.cmd_params, parsed_params.option_map,                             parsed_params.flags);  } else if (parsed_params.cmd == BackupCommand::Name()) {    return new BackupCommand(parsed_params.cmd_params, parsed_params.option_map,                             parsed_params.flags);  } else if (parsed_params.cmd == RestoreCommand::Name()) {    return new RestoreCommand(parsed_params.cmd_params,                              parsed_params.option_map, parsed_params.flags);  } else if (parsed_params.cmd == WriteExternalSstFilesCommand::Name()) {    return new WriteExternalSstFilesCommand(parsed_params.cmd_params,                                            parsed_params.option_map,                                            parsed_params.flags);  } else if (parsed_params.cmd == IngestExternalSstFilesCommand::Name()) {    return new IngestExternalSstFilesCommand(parsed_params.cmd_params,                                             parsed_params.option_map,                                             parsed_params.flags);  } else if (parsed_params.cmd == ListFileRangeDeletesCommand::Name()) {    return new ListFileRangeDeletesCommand(parsed_params.option_map,                                           parsed_params.flags);  }  return nullptr;}/* Run the command, and return the execute result. */void LDBCommand::Run() {  if (!exec_state_.IsNotStarted()) {    return;  }  if (!options_.env || options_.env == Env::Default()) {    Env* env = Env::Default();    Status s = Env::LoadEnv(env_uri_, &env, &env_guard_);    if (!s.ok() && !s.IsNotFound()) {      fprintf(stderr, "LoadEnv: %s\n", s.ToString().c_str());      exec_state_ = LDBCommandExecuteResult::Failed(s.ToString());      return;    }    options_.env = env;  }  options_.file_system.reset(new LegacyFileSystemWrapper(options_.env));  if (db_ == nullptr && !NoDBOpen()) {    OpenDB();    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;    }  }  // 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();  }}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)    : db_(nullptr),      db_ttl_(nullptr),      is_read_only_(is_read_only),      is_key_hex_(false),      is_value_hex_(false),      is_db_ttl_(false),      timestamp_(false),      try_load_options_(false),      ignore_unknown_options_(false),      create_if_missing_(false),      option_map_(options),      flags_(flags),      valid_cmd_line_options_(valid_cmd_line_options) {  std::map<std::string, std::string>::const_iterator itr = options.find(ARG_DB);  if (itr != options.end()) {    db_path_ = itr->second;  }  itr = options.find(ARG_ENV_URI);  if (itr != options.end()) {    env_uri_ = itr->second;  }  itr = options.find(ARG_CF_NAME);  if (itr != options.end()) {    column_family_name_ = itr->second;  } else {    column_family_name_ = kDefaultColumnFamilyName;  }  itr = options.find(ARG_SECONDARY_PATH);  secondary_path_ = "";  if (itr != options.end()) {    secondary_path_ = itr->second;  }  is_key_hex_ = IsKeyHex(options, flags);  is_value_hex_ = IsValueHex(options, flags);  is_db_ttl_ = IsFlagPresent(flags, ARG_TTL);  timestamp_ = IsFlagPresent(flags, ARG_TIMESTAMP);  try_load_options_ = IsFlagPresent(flags, ARG_TRY_LOAD_OPTIONS);  ignore_unknown_options_ = IsFlagPresent(flags, ARG_IGNORE_UNKNOWN_OPTIONS);}void LDBCommand::OpenDB() {  if (!create_if_missing_ && try_load_options_) {    Status s = LoadLatestOptions(db_path_, options_.env, &options_,                                 &column_families_, ignore_unknown_options_);    if (!s.ok() && !s.IsNotFound()) {      // Option file exists but load option file error.      std::string msg = s.ToString();      exec_state_ = LDBCommandExecuteResult::Failed(msg);      db_ = nullptr;      return;    }    if (options_.env->FileExists(options_.wal_dir).IsNotFound()) {      options_.wal_dir = db_path_;      fprintf(          stderr,          "wal_dir loaded from the option file doesn't exist. Ignore it.\n");    }    // If merge operator is not set, set a string append operator. There is    // no harm doing it.    for (auto& cf_entry : column_families_) {      if (!cf_entry.options.merge_operator) {        cf_entry.options.merge_operator =            MergeOperators::CreateStringAppendOperator(':');      }    }  }  options_ = PrepareOptionsForOpenDB();  if (!exec_state_.IsNotStarted()) {    return;  }  if (column_families_.empty() && !options_.merge_operator) {    // No harm to add a general merge operator if it is not specified.    options_.merge_operator = MergeOperators::CreateStringAppendOperator(':');  }  // 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 (!secondary_path_.empty()) {      exec_state_ = LDBCommandExecuteResult::Failed(          "Open as secondary is not supported for TTL DB yet.");    }    if (is_read_only_) {      st = DBWithTTL::Open(options_, db_path_, &db_ttl_, 0, true);    } else {      st = DBWithTTL::Open(options_, db_path_, &db_ttl_);    }    db_ = db_ttl_;  } else {    if (column_families_.empty()) {      // Try to figure out column family lists      std::vector<std::string> cf_list;      st = DB::ListColumnFamilies(options_, 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) {          column_families_.emplace_back(cf_name, options_);        }      }    }    if (is_read_only_ && secondary_path_.empty()) {      if (column_families_.empty()) {        st = DB::OpenForReadOnly(options_, db_path_, &db_);      } else {        st = DB::OpenForReadOnly(options_, db_path_, column_families_,                                 &handles_opened, &db_);      }    } else {      if (column_families_.empty()) {        if (secondary_path_.empty()) {          st = DB::Open(options_, db_path_, &db_);        } else {          st = DB::OpenAsSecondary(options_, db_path_, secondary_path_, &db_);        }      } else {        if (secondary_path_.empty()) {          st = DB::Open(options_, db_path_, column_families_, &handles_opened,                        &db_);        } else {          st = DB::OpenAsSecondary(options_, db_path_, secondary_path_,                                   column_families_, &handles_opened, &db_);        }      }    }  }  if (!st.ok()) {    std::string msg = st.ToString();    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();}std::vector<std::string> LDBCommand::BuildCmdLineOptions(    std::vector<std::string> options) {  std::vector<std::string> ret = {ARG_ENV_URI,                                  ARG_DB,                                  ARG_SECONDARY_PATH,                                  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,                                  ARG_TRY_LOAD_OPTIONS,                                  ARG_IGNORE_UNKNOWN_OPTIONS,                                  ARG_CF_NAME};  ret.insert(ret.end(), options.begin(), options.end());  return ret;}/** * 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. */bool LDBCommand::ParseIntOption(    const std::map<std::string, std::string>& /*options*/,    const std::string& option, int& value,    LDBCommandExecuteResult& exec_state) {  std::map<std::string, std::string>::const_iterator itr =      option_map_.find(option);  if (itr != option_map_.end()) {    try {#if defined(CYGWIN)      value = strtol(itr->second.c_str(), 0, 10);#else      value = std::stoi(itr->second);#endif      return true;    } catch (const std::invalid_argument&) {      exec_state =          LDBCommandExecuteResult::Failed(option + " has an invalid value.");    } catch (const std::out_of_range&) {      exec_state = LDBCommandExecuteResult::Failed(          option + " has a value out-of-range.");    }  }  return false;}/** * Parses the specified option and fills in the value. * Returns true if the option is found. * Returns false otherwise. */bool LDBCommand::ParseStringOption(    const std::map<std::string, std::string>& /*options*/,    const std::string& option, std::string* value) {  auto itr = option_map_.find(option);  if (itr != option_map_.end()) {    *value = itr->second;    return true;  }  return false;}Options LDBCommand::PrepareOptionsForOpenDB() {  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;  std::map<std::string, std::string>::const_iterator itr;  BlockBasedTableOptions table_options;  bool use_table_options = false;  int bits;  if (ParseIntOption(option_map_, ARG_BLOOM_BITS, bits, exec_state_)) {    if (bits > 0) {      use_table_options = true;      table_options.filter_policy.reset(NewBloomFilterPolicy(bits));    } else {      exec_state_ =          LDBCommandExecuteResult::Failed(ARG_BLOOM_BITS + " must be > 0.");    }  }  int block_size;  if (ParseIntOption(option_map_, ARG_BLOCK_SIZE, block_size, exec_state_)) {    if (block_size > 0) {      use_table_options = true;      table_options.block_size = block_size;    } else {      exec_state_ =          LDBCommandExecuteResult::Failed(ARG_BLOCK_SIZE + " must be > 0.");    }  }  if (use_table_options) {    cf_opts->table_factory.reset(NewBlockBasedTableFactory(table_options));  }  itr = option_map_.find(ARG_AUTO_COMPACTION);  if (itr != option_map_.end()) {    cf_opts->disable_auto_compactions = !StringToBool(itr->second);  }  itr = option_map_.find(ARG_COMPRESSION_TYPE);  if (itr != option_map_.end()) {    std::string comp = itr->second;    if (comp == "no") {      cf_opts->compression = kNoCompression;    } else if (comp == "snappy") {      cf_opts->compression = kSnappyCompression;    } else if (comp == "zlib") {      cf_opts->compression = kZlibCompression;    } else if (comp == "bzip2") {      cf_opts->compression = kBZip2Compression;    } else if (comp == "lz4") {      cf_opts->compression = kLZ4Compression;    } else if (comp == "lz4hc") {      cf_opts->compression = kLZ4HCCompression;    } else if (comp == "xpress") {      cf_opts->compression = kXpressCompression;    } else if (comp == "zstd") {      cf_opts->compression = kZSTD;    } else {      // Unknown compression.      exec_state_ =          LDBCommandExecuteResult::Failed("Unknown compression level: " + comp);    }  }  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) {      cf_opts->compression_opts.max_dict_bytes = compression_max_dict_bytes;    } else {      exec_state_ = LDBCommandExecuteResult::Failed(          ARG_COMPRESSION_MAX_DICT_BYTES + " must be >= 0.");    }  }  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) {      db_opts->db_write_buffer_size = db_write_buffer_size;    } else {      exec_state_ = LDBCommandExecuteResult::Failed(ARG_DB_WRITE_BUFFER_SIZE +                                                    " must be >= 0.");    }  }  int write_buffer_size;  if (ParseIntOption(option_map_, ARG_WRITE_BUFFER_SIZE, write_buffer_size,        exec_state_)) {    if (write_buffer_size > 0) {      cf_opts->write_buffer_size = write_buffer_size;    } else {      exec_state_ = LDBCommandExecuteResult::Failed(ARG_WRITE_BUFFER_SIZE +                                                    " must be > 0.");    }  }  int file_size;  if (ParseIntOption(option_map_, ARG_FILE_SIZE, file_size, exec_state_)) {    if (file_size > 0) {      cf_opts->target_file_size_base = file_size;    } else {      exec_state_ =          LDBCommandExecuteResult::Failed(ARG_FILE_SIZE + " must be > 0.");    }  }  if (db_opts->db_paths.size() == 0) {    db_opts->db_paths.emplace_back(db_path_,                                   std::numeric_limits<uint64_t>::max());  }  int fix_prefix_len;  if (ParseIntOption(option_map_, ARG_FIX_PREFIX_LEN, fix_prefix_len,                     exec_state_)) {    if (fix_prefix_len > 0) {      cf_opts->prefix_extractor.reset(          NewFixedPrefixTransform(static_cast<size_t>(fix_prefix_len)));    } else {      exec_state_ =          LDBCommandExecuteResult::Failed(ARG_FIX_PREFIX_LEN + " must be > 0.");    }  }  // 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_;}bool LDBCommand::ParseKeyValue(const std::string& line, std::string* key,                               std::string* value, bool is_key_hex,                               bool is_value_hex) {  size_t pos = line.find(DELIM);  if (pos != std::string::npos) {    *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;  }}/** * 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() {  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()) {      fprintf(stderr, "Invalid command-line option %s\n", itr->first.c_str());      return false;    }  }  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()) {      fprintf(stderr, "Invalid command-line flag %s\n", itr->c_str());      return false;    }  }  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());    return false;  }  return true;}std::string LDBCommand::HexToString(const std::string& str) {  std::string result;  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;}std::string LDBCommand::StringToHex(const std::string& str) {  std::string result("0x");  result.append(Slice(str).ToString(true));  return result;}std::string LDBCommand::PrintKeyValue(const std::string& key,                                      const std::string& value, bool is_key_hex,                                      bool is_value_hex) {  std::string result;  result.append(is_key_hex ? StringToHex(key) : key);  result.append(DELIM);  result.append(is_value_hex ? StringToHex(value) : value);  return result;}std::string LDBCommand::PrintKeyValue(const std::string& key,                                      const std::string& value, bool is_hex) {  return PrintKeyValue(key, value, is_hex, is_hex);}std::string LDBCommand::HelpRangeCmdArgs() {  std::ostringstream str_stream;  str_stream << " ";  str_stream << "[--" << ARG_FROM << "] ";  str_stream << "[--" << ARG_TO << "] ";  return str_stream.str();}bool LDBCommand::IsKeyHex(const std::map<std::string, std::string>& options,                          const std::vector<std::string>& flags) {  return (IsFlagPresent(flags, ARG_HEX) || IsFlagPresent(flags, ARG_KEY_HEX) ||          ParseBooleanOption(options, ARG_HEX, false) ||          ParseBooleanOption(options, ARG_KEY_HEX, false));}bool LDBCommand::IsValueHex(const std::map<std::string, std::string>& options,                            const std::vector<std::string>& flags) {  return (IsFlagPresent(flags, ARG_HEX) ||          IsFlagPresent(flags, ARG_VALUE_HEX) ||          ParseBooleanOption(options, ARG_HEX, false) ||          ParseBooleanOption(options, ARG_VALUE_HEX, false));}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);  if (itr != options.end()) {    std::string option_val = itr->second;    return StringToBool(itr->second);  }  return default_val;}bool LDBCommand::StringToBool(std::string val) {  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";  }}CompactorCommand::CompactorCommand(    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_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);  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_) {    if (!null_from_) {      from_ = HexToString(from_);    }    if (!null_to_) {      to_ = HexToString(to_);    }  }}void CompactorCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(CompactorCommand::Name());  ret.append(HelpRangeCmdArgs());  ret.append("\n");}void CompactorCommand::DoCommand() {  if (!db_) {    assert(GetExecuteState().IsFailed());    return;  }  Slice* begin = nullptr;  Slice* end = nullptr;  if (!null_from_) {    begin = new Slice(from_);  }  if (!null_to_) {    end = new Slice(to_);  }  CompactRangeOptions cro;  cro.bottommost_level_compaction = BottommostLevelCompaction::kForceOptimized;  db_->CompactRange(cro, GetCfHandle(), begin, end);  exec_state_ = LDBCommandExecuteResult::Succeed("");  delete begin;  delete end;}// ---------------------------------------------------------------------------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";DBLoaderCommand::DBLoaderCommand(    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, ARG_FROM,                               ARG_TO, ARG_CREATE_IF_MISSING, ARG_DISABLE_WAL,                               ARG_BULK_LOAD, ARG_COMPACT})),      disable_wal_(false),      bulk_load_(false),      compact_(false) {  create_if_missing_ = IsFlagPresent(flags, ARG_CREATE_IF_MISSING);  disable_wal_ = IsFlagPresent(flags, ARG_DISABLE_WAL);  bulk_load_ = IsFlagPresent(flags, ARG_BULK_LOAD);  compact_ = IsFlagPresent(flags, ARG_COMPACT);}void DBLoaderCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(DBLoaderCommand::Name());  ret.append(" [--" + ARG_CREATE_IF_MISSING + "]");  ret.append(" [--" + ARG_DISABLE_WAL + "]");  ret.append(" [--" + ARG_BULK_LOAD + "]");  ret.append(" [--" + ARG_COMPACT + "]");  ret.append("\n");}Options DBLoaderCommand::PrepareOptionsForOpenDB() {  Options opt = LDBCommand::PrepareOptionsForOpenDB();  opt.create_if_missing = create_if_missing_;  if (bulk_load_) {    opt.PrepareForBulkLoad();  }  return opt;}void DBLoaderCommand::DoCommand() {  if (!db_) {    assert(GetExecuteState().IsFailed());    return;  }  WriteOptions write_options;  if (disable_wal_) {    write_options.disableWAL = true;  }  int bad_lines = 0;  std::string line;  // 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')) {    std::string key;    std::string value;    if (ParseKeyValue(line, &key, &value, is_key_hex_, is_value_hex_)) {      db_->Put(write_options, GetCfHandle(), Slice(key), Slice(value));    } else if (0 == line.find("Keys in range:")) {      // ignore this line    } else if (0 == line.find("Created bg thread 0x")) {      // ignore this line    } else {      bad_lines ++;    }  }  if (bad_lines > 0) {    std::cout << "Warning: " << bad_lines << " bad lines ignored." << std::endl;  }  if (compact_) {    db_->CompactRange(CompactRangeOptions(), GetCfHandle(), nullptr, nullptr);  }}// ----------------------------------------------------------------------------namespace {void DumpManifestFile(Options options, std::string file, bool verbose, bool hex,                      bool json) {  EnvOptions sopt;  std::string dbname("dummy");  std::shared_ptr<Cache> tc(NewLRUCache(options.max_open_files - 10,                                        options.table_cache_numshardbits));  // 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);  options.num_levels = 64;  WriteController wc(options.delayed_write_rate);  WriteBufferManager wb(options.db_write_buffer_size);  ImmutableDBOptions immutable_db_options(options);  VersionSet versions(dbname, &immutable_db_options, sopt, tc.get(), &wb, &wc,                      /*block_cache_tracer=*/nullptr);  Status s = versions.DumpManifest(options, file, verbose, hex, json);  if (!s.ok()) {    fprintf(stderr, "Error in processing file %s %s\n", file.c_str(),            s.ToString().c_str());  }}}  // namespaceconst std::string ManifestDumpCommand::ARG_VERBOSE = "verbose";const std::string ManifestDumpCommand::ARG_JSON = "json";const std::string ManifestDumpCommand::ARG_PATH = "path";void ManifestDumpCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(ManifestDumpCommand::Name());  ret.append(" [--" + ARG_VERBOSE + "]");  ret.append(" [--" + ARG_JSON + "]");  ret.append(" [--" + ARG_PATH + "=<path_to_manifest_file>]");  ret.append("\n");}ManifestDumpCommand::ManifestDumpCommand(    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_VERBOSE, ARG_PATH, ARG_HEX, ARG_JSON})),      verbose_(false),      json_(false),      path_("") {  verbose_ = IsFlagPresent(flags, ARG_VERBOSE);  json_ = IsFlagPresent(flags, ARG_JSON);  std::map<std::string, std::string>::const_iterator itr =      options.find(ARG_PATH);  if (itr != options.end()) {    path_ = itr->second;    if (path_.empty()) {      exec_state_ = LDBCommandExecuteResult::Failed("--path: missing pathname");    }  }}void ManifestDumpCommand::DoCommand() {  std::string manifestfile;  if (!path_.empty()) {    manifestfile = path_;  } else {    // We need to find the manifest file by searching the directory    // containing the db for files of the form MANIFEST_[0-9]+    std::vector<std::string> files;    Status s = options_.env->GetChildren(db_path_, &files);    if (!s.ok()) {      std::string err_msg = s.ToString();      err_msg.append(": Failed to list the content of ");      err_msg.append(db_path_);      exec_state_ = LDBCommandExecuteResult::Failed(err_msg);      return;    }    const std::string kManifestNamePrefix = "MANIFEST-";    std::string matched_file;#ifdef OS_WIN    const char kPathDelim = '\\';#else    const char kPathDelim = '/';#endif    for (const auto& file_path : files) {      // Some Env::GetChildren() return absolute paths. Some directories' path      // end with path delim, e.g. '/' or '\\'.      size_t pos = file_path.find_last_of(kPathDelim);      if (pos == file_path.size() - 1) {        continue;      }      std::string fname;      if (pos != std::string::npos) {        // Absolute path.        fname.assign(file_path, pos + 1, file_path.size() - pos - 1);      } else {        fname = file_path;      }      uint64_t file_num = 0;      FileType file_type = kLogFile;  // Just for initialization      if (ParseFileName(fname, &file_num, &file_type) &&          file_type == kDescriptorFile) {        if (!matched_file.empty()) {          exec_state_ = LDBCommandExecuteResult::Failed(              "Multiple MANIFEST files found; use --path to select one");          return;        } else {          matched_file.swap(fname);        }      }    }    if (matched_file.empty()) {      std::string err_msg("No MANIFEST found in ");      err_msg.append(db_path_);      exec_state_ = LDBCommandExecuteResult::Failed(err_msg);      return;    }    if (db_path_[db_path_.length() - 1] != '/') {      db_path_.append("/");    }    manifestfile = db_path_ + matched_file;  }  if (verbose_) {    fprintf(stdout, "Processing Manifest file %s\n", manifestfile.c_str());  }  DumpManifestFile(options_, manifestfile, verbose_, is_key_hex_, json_);  if (verbose_) {    fprintf(stdout, "Processing Manifest file %s done\n", manifestfile.c_str());  }}// ----------------------------------------------------------------------------namespace {void GetLiveFilesChecksumInfoFromVersionSet(Options options,                                            const std::string& db_path,                                            FileChecksumList* checksum_list) {  EnvOptions sopt;  Status s;  std::string dbname(db_path);  std::shared_ptr<Cache> tc(NewLRUCache(options.max_open_files - 10,                                        options.table_cache_numshardbits));  // Notice we are using the default options not through SanitizeOptions(),  // if VersionSet::GetLiveFilesChecksumInfo depends on any option done by  // SanitizeOptions(), we need to initialize it manually.  options.db_paths.emplace_back(db_path, 0);  options.num_levels = 64;  WriteController wc(options.delayed_write_rate);  WriteBufferManager wb(options.db_write_buffer_size);  ImmutableDBOptions immutable_db_options(options);  VersionSet versions(dbname, &immutable_db_options, sopt, tc.get(), &wb, &wc,                      /*block_cache_tracer=*/nullptr);  std::vector<std::string> cf_name_list;  s = versions.ListColumnFamilies(&cf_name_list, db_path,                                  options.file_system.get());  if (s.ok()) {    std::vector<ColumnFamilyDescriptor> cf_list;    for (const auto& name : cf_name_list) {      cf_list.emplace_back(name, ColumnFamilyOptions(options));    }    s = versions.Recover(cf_list, true);  }  if (s.ok()) {    s = versions.GetLiveFilesChecksumInfo(checksum_list);  }  if (!s.ok()) {    fprintf(stderr, "Error Status: %s", s.ToString().c_str());  }}}  // namespaceconst std::string FileChecksumDumpCommand::ARG_PATH = "path";void FileChecksumDumpCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(FileChecksumDumpCommand::Name());  ret.append(" [--" + ARG_PATH + "=<path_to_manifest_file>]");  ret.append("\n");}FileChecksumDumpCommand::FileChecksumDumpCommand(    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_PATH})),      path_("") {  std::map<std::string, std::string>::const_iterator itr =      options.find(ARG_PATH);  if (itr != options.end()) {    path_ = itr->second;    if (path_.empty()) {      exec_state_ = LDBCommandExecuteResult::Failed("--path: missing pathname");    }  }}void FileChecksumDumpCommand::DoCommand() {  // print out the checksum information in the following format:  //  sst file number, checksum function name, checksum value  //  sst file number, checksum function name, checksum value  //  ......  std::unique_ptr<FileChecksumList> checksum_list(NewFileChecksumList());  GetLiveFilesChecksumInfoFromVersionSet(options_, db_path_,                                         checksum_list.get());  if (checksum_list != nullptr) {    std::vector<uint64_t> file_numbers;    std::vector<std::string> checksums;    std::vector<std::string> checksum_func_names;    Status s = checksum_list->GetAllFileChecksums(&file_numbers, &checksums,                                                  &checksum_func_names);    if (s.ok()) {      for (size_t i = 0; i < file_numbers.size(); i++) {        assert(i < file_numbers.size());        assert(i < checksums.size());        assert(i < checksum_func_names.size());        fprintf(stdout, "%" PRId64 ", %s, %s\n", file_numbers[i],                checksum_func_names[i].c_str(), checksums[i].c_str());      }    }    fprintf(stdout, "Print SST file checksum information finished \n");  }}// ----------------------------------------------------------------------------void ListColumnFamiliesCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(ListColumnFamiliesCommand::Name());  ret.append("\n");}ListColumnFamiliesCommand::ListColumnFamiliesCommand(    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({})) {}void ListColumnFamiliesCommand::DoCommand() {  std::vector<std::string> column_families;  Status s = DB::ListColumnFamilies(options_, db_path_, &column_families);  if (!s.ok()) {    fprintf(stderr, "Error in processing db %s %s\n", db_path_.c_str(),            s.ToString().c_str());  } else {    fprintf(stdout, "Column families in %s: \n{", db_path_.c_str());    bool first = true;    for (auto cf : column_families) {      if (!first) {        fprintf(stdout, ", ");      }      first = false;      fprintf(stdout, "%s", cf.c_str());    }    fprintf(stdout, "}\n");  }}void CreateColumnFamilyCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(CreateColumnFamilyCommand::Name());  ret.append(" --db=<db_path> <new_column_family_name>");  ret.append("\n");}CreateColumnFamilyCommand::CreateColumnFamilyCommand(    const std::vector<std::string>& params,    const std::map<std::string, std::string>& options,    const std::vector<std::string>& flags)    : 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() {  ColumnFamilyHandle* new_cf_handle = nullptr;  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();}void DropColumnFamilyCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(DropColumnFamilyCommand::Name());  ret.append(" --db=<db_path> <column_family_name_to_drop>");  ret.append("\n");}DropColumnFamilyCommand::DropColumnFamilyCommand(    const std::vector<std::string>& params,    const std::map<std::string, std::string>& options,    const std::vector<std::string>& flags)    : LDBCommand(options, flags, true, {ARG_DB}) {  if (params.size() != 1) {    exec_state_ = LDBCommandExecuteResult::Failed(        "The name of column family to drop must be specified");  } else {    cf_name_to_drop_ = params[0];  }}void DropColumnFamilyCommand::DoCommand() {  auto iter = cf_handles_.find(cf_name_to_drop_);  if (iter == cf_handles_.end()) {    exec_state_ = LDBCommandExecuteResult::Failed(        "Column family: " + cf_name_to_drop_ + " doesn't exist in db.");    return;  }  ColumnFamilyHandle* cf_handle_to_drop = iter->second;  Status st = db_->DropColumnFamily(cf_handle_to_drop);  if (st.ok()) {    fprintf(stdout, "OK\n");  } else {    exec_state_ = LDBCommandExecuteResult::Failed(        "Fail to drop column family: " + st.ToString());  }  CloseDB();}// ----------------------------------------------------------------------------namespace {// 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 providedvoid IncBucketCounts(std::vector<uint64_t>& bucket_counts, int ttl_start,                     int time_range, int bucket_size, int timekv,                     int num_buckets) {#ifdef NDEBUG  (void)time_range;  (void)num_buckets;#endif  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;  bucket_counts[bucket]++;}void PrintBucketCounts(const std::vector<uint64_t>& bucket_counts,                       int ttl_start, int ttl_end, int bucket_size,                       int num_buckets) {  int time_point = ttl_start;  for(int i = 0; i < num_buckets - 1; i++, time_point += bucket_size) {    fprintf(stdout, "Keys in range %s to %s : %lu\n",            TimeToHumanString(time_point).c_str(),            TimeToHumanString(time_point + bucket_size).c_str(),            (unsigned long)bucket_counts[i]);  }  fprintf(stdout, "Keys in range %s to %s : %lu\n",          TimeToHumanString(time_point).c_str(),          TimeToHumanString(ttl_end).c_str(),          (unsigned long)bucket_counts[num_buckets - 1]);}}  // namespaceconst 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";InternalDumpCommand::InternalDumpCommand(    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_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) {  has_from_ = ParseStringOption(options, ARG_FROM, &from_);  has_to_ = ParseStringOption(options, ARG_TO, &to_);  ParseIntOption(options, ARG_MAX_KEYS, max_keys_, exec_state_);  std::map<std::string, std::string>::const_iterator itr =      options.find(ARG_COUNT_DELIM);  if (itr != options.end()) {    delim_ = itr->second;    count_delim_ = true;   // fprintf(stdout,"delim = %c\n",delim_[0]);  } else {    count_delim_ = IsFlagPresent(flags, ARG_COUNT_DELIM);    delim_=".";  }  print_stats_ = IsFlagPresent(flags, ARG_STATS);  count_only_ = IsFlagPresent(flags, ARG_COUNT_ONLY);  is_input_key_hex_ = IsFlagPresent(flags, ARG_INPUT_KEY_HEX);  if (is_input_key_hex_) {    if (has_from_) {      from_ = HexToString(from_);    }    if (has_to_) {      to_ = HexToString(to_);    }  }}void InternalDumpCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(InternalDumpCommand::Name());  ret.append(HelpRangeCmdArgs());  ret.append(" [--" + ARG_INPUT_KEY_HEX + "]");  ret.append(" [--" + ARG_MAX_KEYS + "=<N>]");  ret.append(" [--" + ARG_COUNT_ONLY + "]");  ret.append(" [--" + ARG_COUNT_DELIM + "=<char>]");  ret.append(" [--" + ARG_STATS + "]");  ret.append("\n");}void InternalDumpCommand::DoCommand() {  if (!db_) {    assert(GetExecuteState().IsFailed());    return;  }  if (print_stats_) {    std::string stats;    if (db_->GetProperty(GetCfHandle(), "rocksdb.stats", &stats)) {      fprintf(stdout, "%s\n", stats.c_str());    }  }  // Cast as DBImpl to get internal iterator  std::vector<KeyVersion> key_versions;  Status st = GetAllKeyVersions(db_, GetCfHandle(), from_, to_, max_keys_,                                &key_versions);  if (!st.ok()) {    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());    return;  }  std::string rtype1, rtype2, row, val;  rtype2 = "";  uint64_t c=0;  uint64_t s1=0,s2=0;  long long count = 0;  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.      break;    }    ++count;    int k;    if (count_delim_) {      rtype1 = "";      s1=0;      row = ikey.Encode().ToString();      val = key_version.value;      for(k=0;row[k]!='\x01' && row[k]!='\0';k++)        s1++;      for(k=0;val[k]!='\x01' && val[k]!='\0';k++)        s1++;      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:%" PRIu64 "\tsize:%" PRIu64 "\n",                rtype2.c_str(), c, s2);        c=1;        s2=s1;        rtype2 = rtype1;      } else {        c++;        s2+=s1;        rtype2=rtype1;      }    }    if (!count_only_ && !count_delim_) {      std::string key = ikey.DebugString(is_key_hex_);      std::string value = Slice(key_version.value).ToString(is_value_hex_);      std::cout << key << " => " << value << "\n";    }    // Terminate if maximum number of keys have been dumped    if (max_keys_ > 0 && count >= max_keys_) break;  }  if(count_delim_) {    fprintf(stdout, "%s => count:%" PRIu64 "\tsize:%" PRIu64 "\n",            rtype2.c_str(), c, s2);  } else {    fprintf(stdout, "Internal keys in range: %lld\n", count);  }}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";DBDumperCommand::DBDumperCommand(    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, 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) {  std::map<std::string, std::string>::const_iterator itr =      options.find(ARG_FROM);  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 {#if defined(CYGWIN)      max_keys_ = strtol(itr->second.c_str(), 0, 10);#else      max_keys_ = std::stoi(itr->second);#endif    } catch (const std::invalid_argument&) {      exec_state_ = LDBCommandExecuteResult::Failed(ARG_MAX_KEYS +                                                    " has an invalid value");    } catch (const std::out_of_range&) {      exec_state_ = LDBCommandExecuteResult::Failed(          ARG_MAX_KEYS + " has a value out-of-range");    }  }  itr = options.find(ARG_COUNT_DELIM);  if (itr != options.end()) {    delim_ = itr->second;    count_delim_ = true;  } else {    count_delim_ = IsFlagPresent(flags, ARG_COUNT_DELIM);    delim_=".";  }  print_stats_ = IsFlagPresent(flags, ARG_STATS);  count_only_ = IsFlagPresent(flags, ARG_COUNT_ONLY);  if (is_key_hex_) {    if (!null_from_) {      from_ = HexToString(from_);    }    if (!null_to_) {      to_ = HexToString(to_);    }  }  itr = options.find(ARG_PATH);  if (itr != options.end()) {    path_ = itr->second;    if (db_path_.empty()) {      db_path_ = path_;    }  }}void DBDumperCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(DBDumperCommand::Name());  ret.append(HelpRangeCmdArgs());  ret.append(" [--" + ARG_TTL + "]");  ret.append(" [--" + ARG_MAX_KEYS + "=<N>]");  ret.append(" [--" + ARG_TIMESTAMP + "]");  ret.append(" [--" + ARG_COUNT_ONLY + "]");  ret.append(" [--" + ARG_COUNT_DELIM + "=<char>]");  ret.append(" [--" + ARG_STATS + "]");  ret.append(" [--" + ARG_TTL_BUCKET + "=<N>]");  ret.append(" [--" + ARG_TTL_START + "=<N>:- is inclusive]");  ret.append(" [--" + ARG_TTL_END + "=<N>:- is exclusive]");  ret.append(" [--" + ARG_PATH + "=<path_to_a_file>]");  ret.append("\n");}/** * 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. * */void DBDumperCommand::DoCommand() {  if (!db_) {    assert(!path_.empty());    std::string fileName = GetFileNameFromPath(path_);    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:        // TODO(myabandeh): allow configuring is_write_commited        DumpWalFile(options_, path_, /* print_header_ */ true,                    /* print_values_ */ true, true /* is_write_commited */,                    &exec_state_);        break;      case kTableFile:        DumpSstFile(options_, path_, is_key_hex_, /* show_properties */ true);        break;      case kDescriptorFile:        DumpManifestFile(options_, path_, /* verbose_ */ false, is_key_hex_,                         /*  json_ */ false);        break;      default:        exec_state_ = LDBCommandExecuteResult::Failed(            "File type not supported: " + path_);        break;    }  } else {    DoDumpCommand();  }}void DBDumperCommand::DoDumpCommand() {  assert(nullptr != db_);  assert(path_.empty());  // Parse command line args  uint64_t count = 0;  if (print_stats_) {    std::string stats;    if (db_->GetProperty("rocksdb.stats", &stats)) {      fprintf(stdout, "%s\n", stats.c_str());    }  }  // Setup key iterator  ReadOptions scan_read_opts;  scan_read_opts.total_order_seek = true;  Iterator* iter = db_->NewIterator(scan_read_opts, GetCfHandle());  Status st = iter->status();  if (!st.ok()) {    exec_state_ =        LDBCommandExecuteResult::Failed("Iterator error." + st.ToString());  }  if (!null_from_) {    iter->Seek(from_);  } else {    iter->SeekToFirst();  }  int max_keys = max_keys_;  int ttl_start;  if (!ParseIntOption(option_map_, ARG_TTL_START, ttl_start, exec_state_)) {    ttl_start = DBWithTTLImpl::kMinTimestamp;  // TTL introduction time  }  int ttl_end;  if (!ParseIntOption(option_map_, ARG_TTL_END, ttl_end, exec_state_)) {    ttl_end = DBWithTTLImpl::kMaxTimestamp;  // Max time allowed by TTL feature  }  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;  if (!ParseIntOption(option_map_, ARG_TTL_BUCKET, bucket_size, exec_state_) ||      bucket_size <= 0) {    bucket_size = time_range; // Will have just 1 bucket by default  }  //cretaing variables for row count of each type  std::string rtype1, rtype2, row, val;  rtype2 = "";  uint64_t c=0;  uint64_t s1=0,s2=0;  // At this point, bucket_size=0 => time_range=0  int num_buckets = (bucket_size >= time_range)                        ? 1                        : ((time_range + bucket_size - 1) / bucket_size);  std::vector<uint64_t> bucket_counts(num_buckets, 0);  if (is_db_ttl_ && !count_only_ && timestamp_ && !count_delim_) {    fprintf(stdout, "Dumping key-values from %s to %s\n",            TimeToHumanString(ttl_start).c_str(),            TimeToHumanString(ttl_end).c_str());  }  HistogramImpl vsize_hist;  for (; iter->Valid(); iter->Next()) {    int rawtime = 0;    // 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;    if (is_db_ttl_) {      TtlIterator* it_ttl = static_cast_with_check<TtlIterator, Iterator>(iter);      rawtime = it_ttl->timestamp();      if (rawtime < ttl_start || rawtime >= ttl_end) {        continue;      }    }    if (max_keys > 0) {      --max_keys;    }    if (is_db_ttl_ && num_buckets > 1) {      IncBucketCounts(bucket_counts, ttl_start, time_range, bucket_size,                      rawtime, num_buckets);    }    ++count;    if (count_delim_) {      rtype1 = "";      row = iter->key().ToString();      val = iter->value().ToString();      s1 = row.size()+val.size();      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:%" PRIu64 "\tsize:%" PRIu64 "\n",                rtype2.c_str(), c, s2);        c=1;        s2=s1;        rtype2 = rtype1;      } else {          c++;          s2+=s1;          rtype2=rtype1;      }    }    if (count_only_) {      vsize_hist.Add(iter->value().size());    }    if (!count_only_ && !count_delim_) {      if (is_db_ttl_ && timestamp_) {        fprintf(stdout, "%s ", TimeToHumanString(rawtime).c_str());      }      std::string str =          PrintKeyValue(iter->key().ToString(), iter->value().ToString(),                        is_key_hex_, is_value_hex_);      fprintf(stdout, "%s\n", str.c_str());    }  }  if (num_buckets > 1 && is_db_ttl_) {    PrintBucketCounts(bucket_counts, ttl_start, ttl_end, bucket_size,                      num_buckets);  } else if(count_delim_) {    fprintf(stdout, "%s => count:%" PRIu64 "\tsize:%" PRIu64 "\n",            rtype2.c_str(), c, s2);  } else {    fprintf(stdout, "Keys in range: %" PRIu64 "\n", count);  }  if (count_only_) {    fprintf(stdout, "Value size distribution: \n");    fprintf(stdout, "%s\n", vsize_hist.ToString().c_str());  }  // Clean up  delete iter;}const std::string ReduceDBLevelsCommand::ARG_NEW_LEVELS = "new_levels";const std::string ReduceDBLevelsCommand::ARG_PRINT_OLD_LEVELS =    "print_old_levels";ReduceDBLevelsCommand::ReduceDBLevelsCommand(    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_NEW_LEVELS, ARG_PRINT_OLD_LEVELS})),      old_levels_(1 << 7),      new_levels_(-1),      print_old_levels_(false) {  ParseIntOption(option_map_, ARG_NEW_LEVELS, new_levels_, exec_state_);  print_old_levels_ = IsFlagPresent(flags, ARG_PRINT_OLD_LEVELS);  if(new_levels_ <= 0) {    exec_state_ = LDBCommandExecuteResult::Failed(        " Use --" + ARG_NEW_LEVELS + " to specify a new level number\n");  }}std::vector<std::string> ReduceDBLevelsCommand::PrepareArgs(    const std::string& db_path, int new_levels, bool print_old_level) {  std::vector<std::string> ret;  ret.push_back("reduce_levels");  ret.push_back("--" + ARG_DB + "=" + db_path);  ret.push_back("--" + ARG_NEW_LEVELS + "=" +                ROCKSDB_NAMESPACE::ToString(new_levels));  if(print_old_level) {    ret.push_back("--" + ARG_PRINT_OLD_LEVELS);  }  return ret;}void ReduceDBLevelsCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(ReduceDBLevelsCommand::Name());  ret.append(" --" + ARG_NEW_LEVELS + "=<New number of levels>");  ret.append(" [--" + ARG_PRINT_OLD_LEVELS + "]");  ret.append("\n");}Options ReduceDBLevelsCommand::PrepareOptionsForOpenDB() {  Options opt = LDBCommand::PrepareOptionsForOpenDB();  opt.num_levels = old_levels_;  opt.max_bytes_for_level_multiplier_additional.resize(opt.num_levels, 1);  // Disable size compaction  opt.max_bytes_for_level_base = 1ULL << 50;  opt.max_bytes_for_level_multiplier = 1;  return opt;}Status ReduceDBLevelsCommand::GetOldNumOfLevels(Options& opt,    int* levels) {  ImmutableDBOptions db_options(opt);  EnvOptions soptions;  std::shared_ptr<Cache> tc(      NewLRUCache(opt.max_open_files - 10, opt.table_cache_numshardbits));  const InternalKeyComparator cmp(opt.comparator);  WriteController wc(opt.delayed_write_rate);  WriteBufferManager wb(opt.db_write_buffer_size);  VersionSet versions(db_path_, &db_options, soptions, tc.get(), &wb, &wc,                      /*block_cache_tracer=*/nullptr);  std::vector<ColumnFamilyDescriptor> dummy;  ColumnFamilyDescriptor dummy_descriptor(kDefaultColumnFamilyName,                                          ColumnFamilyOptions(opt));  dummy.push_back(dummy_descriptor);  // 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.  Status st = versions.Recover(dummy);  if (!st.ok()) {    return st;  }  int max = -1;  auto default_cfd = versions.GetColumnFamilySet()->GetDefault();  for (int i = 0; i < default_cfd->NumberLevels(); i++) {    if (default_cfd->current()->storage_info()->NumLevelFiles(i)) {      max = i;    }  }  *levels = max + 1;  return st;}void ReduceDBLevelsCommand::DoCommand() {  if (new_levels_ <= 1) {    exec_state_ =        LDBCommandExecuteResult::Failed("Invalid number of levels.\n");    return;  }  Status st;  Options opt = PrepareOptionsForOpenDB();  int old_level_num = -1;  opt.file_system.reset(new LegacyFileSystemWrapper(opt.env));  ;  st = GetOldNumOfLevels(opt, &old_level_num);  if (!st.ok()) {    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());    return;  }  if (print_old_levels_) {    fprintf(stdout, "The old number of levels in use is %d\n", old_level_num);  }  if (old_level_num <= new_levels_) {    return;  }  old_levels_ = old_level_num;  OpenDB();  if (exec_state_.IsFailed()) {    return;  }  assert(db_ != nullptr);  // Compact the whole DB to put all files to the highest level.  fprintf(stdout, "Compacting the db...\n");  db_->CompactRange(CompactRangeOptions(), GetCfHandle(), nullptr, nullptr);  CloseDB();  EnvOptions soptions;  st = VersionSet::ReduceNumberOfLevels(db_path_, &opt, soptions, new_levels_);  if (!st.ok()) {    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());    return;  }}const std::string ChangeCompactionStyleCommand::ARG_OLD_COMPACTION_STYLE =    "old_compaction_style";const std::string ChangeCompactionStyleCommand::ARG_NEW_COMPACTION_STYLE =    "new_compaction_style";ChangeCompactionStyleCommand::ChangeCompactionStyleCommand(    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_OLD_COMPACTION_STYLE, ARG_NEW_COMPACTION_STYLE})),      old_compaction_style_(-1),      new_compaction_style_(-1) {  ParseIntOption(option_map_, ARG_OLD_COMPACTION_STYLE, old_compaction_style_,    exec_state_);  if (old_compaction_style_ != kCompactionStyleLevel &&     old_compaction_style_ != kCompactionStyleUniversal) {    exec_state_ = LDBCommandExecuteResult::Failed(        "Use --" + ARG_OLD_COMPACTION_STYLE + " to specify old compaction " +        "style. Check ldb help for proper compaction style value.\n");    return;  }  ParseIntOption(option_map_, ARG_NEW_COMPACTION_STYLE, new_compaction_style_,    exec_state_);  if (new_compaction_style_ != kCompactionStyleLevel &&     new_compaction_style_ != kCompactionStyleUniversal) {    exec_state_ = LDBCommandExecuteResult::Failed(        "Use --" + ARG_NEW_COMPACTION_STYLE + " to specify new compaction " +        "style. Check ldb help for proper compaction style value.\n");    return;  }  if (new_compaction_style_ == old_compaction_style_) {    exec_state_ = LDBCommandExecuteResult::Failed(        "Old compaction style is the same as new compaction style. "        "Nothing to do.\n");    return;  }  if (old_compaction_style_ == kCompactionStyleUniversal &&      new_compaction_style_ == kCompactionStyleLevel) {    exec_state_ = LDBCommandExecuteResult::Failed(        "Convert from universal compaction to level compaction. "        "Nothing to do.\n");    return;  }}void ChangeCompactionStyleCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(ChangeCompactionStyleCommand::Name());  ret.append(" --" + ARG_OLD_COMPACTION_STYLE + "=<Old compaction style: 0 " +             "for level compaction, 1 for universal compaction>");  ret.append(" --" + ARG_NEW_COMPACTION_STYLE + "=<New compaction style: 0 " +             "for level compaction, 1 for universal compaction>");  ret.append("\n");}Options ChangeCompactionStyleCommand::PrepareOptionsForOpenDB() {  Options opt = LDBCommand::PrepareOptionsForOpenDB();  if (old_compaction_style_ == kCompactionStyleLevel &&      new_compaction_style_ == kCompactionStyleUniversal) {    // In order to convert from level compaction to universal compaction, we    // need to compact all data into a single file and move it to level 0.    opt.disable_auto_compactions = true;    opt.target_file_size_base = INT_MAX;    opt.target_file_size_multiplier = 1;    opt.max_bytes_for_level_base = INT_MAX;    opt.max_bytes_for_level_multiplier = 1;  }  return opt;}void ChangeCompactionStyleCommand::DoCommand() {  // print db stats before we have made any change  std::string property;  std::string files_per_level;  for (int i = 0; i < db_->NumberLevels(GetCfHandle()); i++) {    db_->GetProperty(GetCfHandle(),                     "rocksdb.num-files-at-level" + NumberToString(i),                     &property);    // format print string    char buf[100];    snprintf(buf, sizeof(buf), "%s%s", (i ? "," : ""), property.c_str());    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  CompactRangeOptions compact_options;  compact_options.change_level = true;  compact_options.target_level = 0;  db_->CompactRange(compact_options, GetCfHandle(), nullptr, nullptr);  // verify compaction result  files_per_level = "";  int num_files = 0;  for (int i = 0; i < db_->NumberLevels(GetCfHandle()); i++) {    db_->GetProperty(GetCfHandle(),                     "rocksdb.num-files-at-level" + NumberToString(i),                     &property);    // format print string    char buf[100];    snprintf(buf, sizeof(buf), "%s%s", (i ? "," : ""), property.c_str());    files_per_level += buf;    num_files = atoi(property.c_str());    // level 0 should have only 1 file    if (i == 0 && num_files != 1) {      exec_state_ = LDBCommandExecuteResult::Failed(          "Number of db files at "          "level 0 after compaction is " +          ToString(num_files) + ", not 1.\n");      return;    }    // other levels should have no file    if (i > 0 && num_files != 0) {      exec_state_ = LDBCommandExecuteResult::Failed(          "Number of db files at "          "level " +          ToString(i) + " after compaction is " + ToString(num_files) +          ", not 0.\n");      return;    }  }  fprintf(stdout, "files per level after compaction: %s\n",          files_per_level.c_str());}// ----------------------------------------------------------------------------namespace {struct StdErrReporter : public log::Reader::Reporter {  void Corruption(size_t /*bytes*/, const Status& s) override {    std::cerr << "Corruption detected in log file " << s.ToString() << "\n";  }};class InMemoryHandler : public WriteBatch::Handler { public:  InMemoryHandler(std::stringstream& row, bool print_values,                  bool write_after_commit = false)      : Handler(),        row_(row),        print_values_(print_values),        write_after_commit_(write_after_commit) {}  void commonPutMerge(const Slice& key, const Slice& value) {    std::string k = LDBCommand::StringToHex(key.ToString());    if (print_values_) {      std::string v = LDBCommand::StringToHex(value.ToString());      row_ << k << " : ";      row_ << v << " ";    } else {      row_ << k << " ";    }  }  Status PutCF(uint32_t cf, const Slice& key, const Slice& value) override {    row_ << "PUT(" << cf << ") : ";    commonPutMerge(key, value);    return Status::OK();  }  Status MergeCF(uint32_t cf, const Slice& key, const Slice& value) override {    row_ << "MERGE(" << cf << ") : ";    commonPutMerge(key, value);    return Status::OK();  }  Status MarkNoop(bool) override {    row_ << "NOOP ";    return Status::OK();  }  Status DeleteCF(uint32_t cf, const Slice& key) override {    row_ << "DELETE(" << cf << ") : ";    row_ << LDBCommand::StringToHex(key.ToString()) << " ";    return Status::OK();  }  Status SingleDeleteCF(uint32_t cf, const Slice& key) override {    row_ << "SINGLE_DELETE(" << cf << ") : ";    row_ << LDBCommand::StringToHex(key.ToString()) << " ";    return Status::OK();  }  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();  }  Status MarkBeginPrepare(bool unprepare) override {    row_ << "BEGIN_PREPARE(";    row_ << (unprepare ? "true" : "false") << ") ";    return Status::OK();  }  Status MarkEndPrepare(const Slice& xid) override {    row_ << "END_PREPARE(";    row_ << LDBCommand::StringToHex(xid.ToString()) << ") ";    return Status::OK();  }  Status MarkRollback(const Slice& xid) override {    row_ << "ROLLBACK(";    row_ << LDBCommand::StringToHex(xid.ToString()) << ") ";    return Status::OK();  }  Status MarkCommit(const Slice& xid) override {    row_ << "COMMIT(";    row_ << LDBCommand::StringToHex(xid.ToString()) << ") ";    return Status::OK();  }  ~InMemoryHandler() override {} protected:  bool WriteAfterCommit() const override { return write_after_commit_; } private:  std::stringstream& row_;  bool print_values_;  bool write_after_commit_;};void DumpWalFile(Options options, std::string wal_file, bool print_header,                 bool print_values, bool is_write_committed,                 LDBCommandExecuteResult* exec_state) {  Env* env = options.env;  EnvOptions soptions(options);  std::unique_ptr<SequentialFileReader> wal_file_reader;  Status status;  {    std::unique_ptr<SequentialFile> file;    status = env->NewSequentialFile(wal_file, &file, soptions);    if (status.ok()) {      wal_file_reader.reset(new SequentialFileReader(          NewLegacySequentialFileWrapper(file), wal_file));    }  }  if (!status.ok()) {    if (exec_state) {      *exec_state = LDBCommandExecuteResult::Failed("Failed to open WAL file " +                                                    status.ToString());    } else {      std::cerr << "Error: Failed to open WAL file " << status.ToString()                << std::endl;    }  } else {    StdErrReporter reporter;    uint64_t log_number;    FileType type;    // we need the log number, but ParseFilename expects dbname/NNN.log.    std::string sanitized = wal_file;    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;    }    log::Reader reader(options.info_log, std::move(wal_file_reader), &reporter,                       true /* checksum */, log_number);    std::string scratch;    WriteBatch batch;    Slice record;    std::stringstream row;    if (print_header) {      std::cout << "Sequence,Count,ByteSize,Physical Offset,Key(s)";      if (print_values) {        std::cout << " : value ";      }      std::cout << "\n";    }    while (reader.ReadRecord(&record, &scratch)) {      row.str("");      if (record.size() < WriteBatchInternal::kHeader) {        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, is_write_committed);        batch.Iterate(&handler);        row << "\n";      }      std::cout << row.str();    }  }}}  // namespaceconst std::string WALDumperCommand::ARG_WAL_FILE = "walfile";const std::string WALDumperCommand::ARG_WRITE_COMMITTED = "write_committed";const std::string WALDumperCommand::ARG_PRINT_VALUE = "print_value";const std::string WALDumperCommand::ARG_PRINT_HEADER = "header";WALDumperCommand::WALDumperCommand(    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_WAL_FILE, ARG_WRITE_COMMITTED,                                      ARG_PRINT_HEADER, ARG_PRINT_VALUE})),      print_header_(false),      print_values_(false),      is_write_committed_(false) {  wal_file_.clear();  std::map<std::string, std::string>::const_iterator itr =      options.find(ARG_WAL_FILE);  if (itr != options.end()) {    wal_file_ = itr->second;  }  print_header_ = IsFlagPresent(flags, ARG_PRINT_HEADER);  print_values_ = IsFlagPresent(flags, ARG_PRINT_VALUE);  is_write_committed_ = ParseBooleanOption(options, ARG_WRITE_COMMITTED, true);  if (wal_file_.empty()) {    exec_state_ = LDBCommandExecuteResult::Failed("Argument " + ARG_WAL_FILE +                                                  " must be specified.");  }}void WALDumperCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(WALDumperCommand::Name());  ret.append(" --" + ARG_WAL_FILE + "=<write_ahead_log_file_path>");  ret.append(" [--" + ARG_PRINT_HEADER + "] ");  ret.append(" [--" + ARG_PRINT_VALUE + "] ");  ret.append(" [--" + ARG_WRITE_COMMITTED + "=true|false] ");  ret.append("\n");}void WALDumperCommand::DoCommand() {  DumpWalFile(options_, wal_file_, print_header_, print_values_,              is_write_committed_, &exec_state_);}// ----------------------------------------------------------------------------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})) {  if (params.size() != 1) {    exec_state_ = LDBCommandExecuteResult::Failed(        "<key> must be specified for the get command");  } else {    key_ = params.at(0);  }  if (is_key_hex_) {    key_ = HexToString(key_);  }}void GetCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(GetCommand::Name());  ret.append(" <key>");  ret.append(" [--" + ARG_TTL + "]");  ret.append("\n");}void GetCommand::DoCommand() {  if (!db_) {    assert(GetExecuteState().IsFailed());    return;  }  std::string value;  Status st = db_->Get(ReadOptions(), GetCfHandle(), key_, &value);  if (st.ok()) {    fprintf(stdout, "%s\n",              (is_value_hex_ ? StringToHex(value) : value).c_str());  } else {    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());  }}// ----------------------------------------------------------------------------ApproxSizeCommand::ApproxSizeCommand(    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_HEX, ARG_KEY_HEX, ARG_VALUE_HEX, ARG_FROM, ARG_TO})) {  if (options.find(ARG_FROM) != options.end()) {    start_key_ = options.find(ARG_FROM)->second;  } else {    exec_state_ = LDBCommandExecuteResult::Failed(        ARG_FROM + " must be specified for approxsize command");    return;  }  if (options.find(ARG_TO) != options.end()) {    end_key_ = options.find(ARG_TO)->second;  } else {    exec_state_ = LDBCommandExecuteResult::Failed(        ARG_TO + " must be specified for approxsize command");    return;  }  if (is_key_hex_) {    start_key_ = HexToString(start_key_);    end_key_ = HexToString(end_key_);  }}void ApproxSizeCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(ApproxSizeCommand::Name());  ret.append(HelpRangeCmdArgs());  ret.append("\n");}void ApproxSizeCommand::DoCommand() {  if (!db_) {    assert(GetExecuteState().IsFailed());    return;  }  Range ranges[1];  ranges[0] = Range(start_key_, end_key_);  uint64_t sizes[1];  db_->GetApproximateSizes(GetCfHandle(), ranges, 1, sizes);  fprintf(stdout, "%lu\n", (unsigned long)sizes[0]);  /* Weird that GetApproximateSizes() returns void, although documentation   * says that it returns a Status object.  if (!st.ok()) {    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());  }  */}// ----------------------------------------------------------------------------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})) {  if (params.size() < 2) {    exec_state_ = LDBCommandExecuteResult::Failed(        "At least one <key> <value> pair must be specified batchput.");  } else if (params.size() % 2 != 0) {    exec_state_ = LDBCommandExecuteResult::Failed(        "Equal number of <key>s and <value>s must be specified for batchput.");  } else {    for (size_t i = 0; i < params.size(); i += 2) {      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));    }  }  create_if_missing_ = IsFlagPresent(flags_, ARG_CREATE_IF_MISSING);}void BatchPutCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(BatchPutCommand::Name());  ret.append(" <key> <value> [<key> <value>] [..]");  ret.append(" [--" + ARG_TTL + "]");  ret.append("\n");}void BatchPutCommand::DoCommand() {  if (!db_) {    assert(GetExecuteState().IsFailed());    return;  }  WriteBatch batch;  for (std::vector<std::pair<std::string, std::string>>::const_iterator itr =           key_values_.begin();       itr != key_values_.end(); ++itr) {    batch.Put(GetCfHandle(), itr->first, itr->second);  }  Status st = db_->Write(WriteOptions(), &batch);  if (st.ok()) {    fprintf(stdout, "OK\n");  } else {    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());  }}Options BatchPutCommand::PrepareOptionsForOpenDB() {  Options opt = LDBCommand::PrepareOptionsForOpenDB();  opt.create_if_missing = create_if_missing_;  return opt;}// ----------------------------------------------------------------------------ScanCommand::ScanCommand(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_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})),      start_key_specified_(false),      end_key_specified_(false),      max_keys_scanned_(-1),      no_value_(false) {  std::map<std::string, std::string>::const_iterator itr =      options.find(ARG_FROM);  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;  }  std::vector<std::string>::const_iterator vitr =      std::find(flags.begin(), flags.end(), ARG_NO_VALUE);  if (vitr != flags.end()) {    no_value_ = true;  }  itr = options.find(ARG_MAX_KEYS);  if (itr != options.end()) {    try {#if defined(CYGWIN)      max_keys_scanned_ = strtol(itr->second.c_str(), 0, 10);#else      max_keys_scanned_ = std::stoi(itr->second);#endif    } catch (const std::invalid_argument&) {      exec_state_ = LDBCommandExecuteResult::Failed(ARG_MAX_KEYS +                                                    " has an invalid value");    } catch (const std::out_of_range&) {      exec_state_ = LDBCommandExecuteResult::Failed(          ARG_MAX_KEYS + " has a value out-of-range");    }  }}void ScanCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(ScanCommand::Name());  ret.append(HelpRangeCmdArgs());  ret.append(" [--" + ARG_TTL + "]");  ret.append(" [--" + ARG_TIMESTAMP + "]");  ret.append(" [--" + ARG_MAX_KEYS + "=<N>q] ");  ret.append(" [--" + ARG_TTL_START + "=<N>:- is inclusive]");  ret.append(" [--" + ARG_TTL_END + "=<N>:- is exclusive]");  ret.append(" [--" + ARG_NO_VALUE + "]");  ret.append("\n");}void ScanCommand::DoCommand() {  if (!db_) {    assert(GetExecuteState().IsFailed());    return;  }  int num_keys_scanned = 0;  ReadOptions scan_read_opts;  scan_read_opts.total_order_seek = true;  Iterator* it = db_->NewIterator(scan_read_opts, GetCfHandle());  if (start_key_specified_) {    it->Seek(start_key_);  } else {    it->SeekToFirst();  }  int ttl_start;  if (!ParseIntOption(option_map_, ARG_TTL_START, ttl_start, exec_state_)) {    ttl_start = DBWithTTLImpl::kMinTimestamp;  // TTL introduction time  }  int ttl_end;  if (!ParseIntOption(option_map_, ARG_TTL_END, ttl_end, exec_state_)) {    ttl_end = DBWithTTLImpl::kMaxTimestamp;  // Max time allowed by TTL feature  }  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",            TimeToHumanString(ttl_start).c_str(),            TimeToHumanString(ttl_end).c_str());  }  for ( ;        it->Valid() && (!end_key_specified_ || it->key().ToString() < end_key_);        it->Next()) {    if (is_db_ttl_) {      TtlIterator* it_ttl = static_cast_with_check<TtlIterator, Iterator>(it);      int rawtime = it_ttl->timestamp();      if (rawtime < ttl_start || rawtime >= ttl_end) {        continue;      }      if (timestamp_) {        fprintf(stdout, "%s ", TimeToHumanString(rawtime).c_str());      }    }    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;    }    if (no_value_) {      fprintf(stdout, "%.*s\n", static_cast<int>(key_slice.size()),              key_slice.data());    } else {      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());    }    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    exec_state_ = LDBCommandExecuteResult::Failed(it->status().ToString());  }  delete it;}// ----------------------------------------------------------------------------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})) {  if (params.size() != 1) {    exec_state_ = LDBCommandExecuteResult::Failed(        "KEY must be specified for the delete command");  } else {    key_ = params.at(0);    if (is_key_hex_) {      key_ = HexToString(key_);    }  }}void DeleteCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(DeleteCommand::Name() + " <key>");  ret.append("\n");}void DeleteCommand::DoCommand() {  if (!db_) {    assert(GetExecuteState().IsFailed());    return;  }  Status st = db_->Delete(WriteOptions(), GetCfHandle(), key_);  if (st.ok()) {    fprintf(stdout, "OK\n");  } else {    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());  }}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());  }}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})) {  if (params.size() != 2) {    exec_state_ = LDBCommandExecuteResult::Failed(        "<key> and <value> must be specified for the put command");  } else {    key_ = params.at(0);    value_ = params.at(1);  }  if (is_key_hex_) {    key_ = HexToString(key_);  }  if (is_value_hex_) {    value_ = HexToString(value_);  }  create_if_missing_ = IsFlagPresent(flags_, ARG_CREATE_IF_MISSING);}void PutCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(PutCommand::Name());  ret.append(" <key> <value> ");  ret.append(" [--" + ARG_TTL + "]");  ret.append("\n");}void PutCommand::DoCommand() {  if (!db_) {    assert(GetExecuteState().IsFailed());    return;  }  Status st = db_->Put(WriteOptions(), GetCfHandle(), key_, value_);  if (st.ok()) {    fprintf(stdout, "OK\n");  } else {    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());  }}Options PutCommand::PrepareOptionsForOpenDB() {  Options opt = LDBCommand::PrepareOptionsForOpenDB();  opt.create_if_missing = create_if_missing_;  return opt;}// ----------------------------------------------------------------------------const char* DBQuerierCommand::HELP_CMD = "help";const char* DBQuerierCommand::GET_CMD = "get";const char* DBQuerierCommand::PUT_CMD = "put";const char* DBQuerierCommand::DELETE_CMD = "delete";DBQuerierCommand::DBQuerierCommand(    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})) {}void DBQuerierCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(DBQuerierCommand::Name());  ret.append(" [--" + ARG_TTL + "]");  ret.append("\n");  ret.append("    Starts a REPL shell.  Type help for list of available "             "commands.");  ret.append("\n");}void DBQuerierCommand::DoCommand() {  if (!db_) {    assert(GetExecuteState().IsFailed());    return;  }  ReadOptions read_options;  WriteOptions write_options;  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;    size_t pos = 0;    while (true) {      size_t pos2 = line.find(' ', pos);      if (pos2 == std::string::npos) {        break;      }      tokens.push_back(line.substr(pos, pos2-pos));      pos = pos2 + 1;    }    tokens.push_back(line.substr(pos));    const std::string& cmd = tokens[0];    if (cmd == HELP_CMD) {      fprintf(stdout,              "get <key>\n"              "put <key> <value>\n"              "delete <key>\n");    } else if (cmd == DELETE_CMD && tokens.size() == 2) {      key = (is_key_hex_ ? HexToString(tokens[1]) : tokens[1]);      db_->Delete(write_options, GetCfHandle(), Slice(key));      fprintf(stdout, "Successfully deleted %s\n", tokens[1].c_str());    } else if (cmd == PUT_CMD && tokens.size() == 3) {      key = (is_key_hex_ ? HexToString(tokens[1]) : tokens[1]);      value = (is_value_hex_ ? HexToString(tokens[2]) : tokens[2]);      db_->Put(write_options, GetCfHandle(), Slice(key), Slice(value));      fprintf(stdout, "Successfully put %s %s\n",              tokens[1].c_str(), tokens[2].c_str());    } else if (cmd == GET_CMD && tokens.size() == 2) {      key = (is_key_hex_ ? HexToString(tokens[1]) : tokens[1]);      if (db_->Get(read_options, GetCfHandle(), Slice(key), &value).ok()) {        fprintf(stdout, "%s\n", PrintKeyValue(key, value,              is_key_hex_, is_value_hex_).c_str());      } else {        fprintf(stdout, "Not found %s\n", tokens[1].c_str());      }    } else {      fprintf(stdout, "Unknown command %s\n", line.c_str());    }  }}// ----------------------------------------------------------------------------CheckConsistencyCommand::CheckConsistencyCommand(    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({})) {}void CheckConsistencyCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(CheckConsistencyCommand::Name());  ret.append("\n");}void CheckConsistencyCommand::DoCommand() {  Options opt = PrepareOptionsForOpenDB();  opt.paranoid_checks = true;  if (!exec_state_.IsNotStarted()) {    return;  }  DB* db;  Status st = DB::OpenForReadOnly(opt, db_path_, &db, false);  delete db;  if (st.ok()) {    fprintf(stdout, "OK\n");  } else {    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());  }}// ----------------------------------------------------------------------------const std::string CheckPointCommand::ARG_CHECKPOINT_DIR = "checkpoint_dir";CheckPointCommand::CheckPointCommand(    const std::vector<std::string>& /*params*/,    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()) {    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()) {    fprintf(stdout, "OK\n");  } else {    exec_state_ = LDBCommandExecuteResult::Failed(status.ToString());  }}// ----------------------------------------------------------------------------RepairCommand::RepairCommand(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({})) {}void RepairCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(RepairCommand::Name());  ret.append("\n");}void RepairCommand::DoCommand() {  Options options = PrepareOptionsForOpenDB();  options.info_log.reset(new StderrLogger(InfoLogLevel::WARN_LEVEL));  Status status = RepairDB(db_path_, options);  if (status.ok()) {    fprintf(stdout, "OK\n");  } else {    exec_state_ = LDBCommandExecuteResult::Failed(status.ToString());  }}// ----------------------------------------------------------------------------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";BackupableCommand::BackupableCommand(    const std::vector<std::string>& /*params*/,    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);  if (itr != options.end()) {    num_threads_ = std::stoi(itr->second);  }  itr = options.find(ARG_BACKUP_ENV_URI);  if (itr != options.end()) {    backup_env_uri_ = itr->second;  }  itr = options.find(ARG_BACKUP_DIR);  if (itr == options.end()) {    exec_state_ = LDBCommandExecuteResult::Failed("--" + ARG_BACKUP_DIR +                                                  ": missing backup directory");  } else {    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)));    }  }}void BackupableCommand::Help(const std::string& name, std::string& ret) {  ret.append("  ");  ret.append(name);  ret.append(" [--" + ARG_BACKUP_ENV_URI + "] ");  ret.append(" [--" + ARG_BACKUP_DIR + "] ");  ret.append(" [--" + ARG_NUM_THREADS + "] ");  ret.append(" [--" + ARG_STDERR_LOG_LEVEL + "=<int (InfoLogLevel)>] ");  ret.append("\n");}// ----------------------------------------------------------------------------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);}void BackupCommand::DoCommand() {  BackupEngine* backup_engine;  Status status;  if (!db_) {    assert(GetExecuteState().IsFailed());    return;  }  fprintf(stdout, "open db OK\n");  Env* custom_env = nullptr;  Env::LoadEnv(backup_env_uri_, &custom_env, &backup_env_guard_);  assert(custom_env != nullptr);  BackupableDBOptions backup_options =      BackupableDBOptions(backup_dir_, custom_env);  backup_options.info_log = logger_.get();  backup_options.max_background_operations = num_threads_;  status = BackupEngine::Open(custom_env, backup_options, &backup_engine);  if (status.ok()) {    fprintf(stdout, "open backup engine OK\n");  } else {    exec_state_ = LDBCommandExecuteResult::Failed(status.ToString());    return;  }  status = backup_engine->CreateNewBackup(db_);  if (status.ok()) {    fprintf(stdout, "create new backup OK\n");  } else {    exec_state_ = LDBCommandExecuteResult::Failed(status.ToString());    return;  }}// ----------------------------------------------------------------------------RestoreCommand::RestoreCommand(    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 RestoreCommand::Help(std::string& ret) {  BackupableCommand::Help(Name(), ret);}void RestoreCommand::DoCommand() {  Env* custom_env = nullptr;  Env::LoadEnv(backup_env_uri_, &custom_env, &backup_env_guard_);  assert(custom_env != nullptr);  std::unique_ptr<BackupEngineReadOnly> restore_engine;  Status status;  {    BackupableDBOptions opts(backup_dir_, custom_env);    opts.info_log = logger_.get();    opts.max_background_operations = num_threads_;    BackupEngineReadOnly* raw_restore_engine_ptr;    status =        BackupEngineReadOnly::Open(custom_env, opts, &raw_restore_engine_ptr);    if (status.ok()) {      restore_engine.reset(raw_restore_engine_ptr);    }  }  if (status.ok()) {    fprintf(stdout, "open restore engine OK\n");    status = restore_engine->RestoreDBFromLatestBackup(db_path_, db_path_);  }  if (status.ok()) {    fprintf(stdout, "restore from backup OK\n");  } else {    exec_state_ = LDBCommandExecuteResult::Failed(status.ToString());  }}// ----------------------------------------------------------------------------namespace {void DumpSstFile(Options options, 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  // TODO: add support for decoding blob indexes in ldb as well  ROCKSDB_NAMESPACE::SstFileDumper dumper(      options, filename, /* verify_checksum */ false, output_hex,      /* decode_blob_index */ false);  Status st = dumper.ReadSequential(true, std::numeric_limits<uint64_t>::max(),                                    false,            // has_from                                    from_key, false,  // has_to                                    to_key);  if (!st.ok()) {    std::cerr << "Error in reading SST file " << filename << st.ToString()              << std::endl;    return;  }  if (show_properties) {    const ROCKSDB_NAMESPACE::TableProperties* table_properties;    std::shared_ptr<const ROCKSDB_NAMESPACE::TableProperties>        table_properties_from_reader;    st = dumper.ReadTableProperties(&table_properties_from_reader);    if (!st.ok()) {      std::cerr << filename << ": " << st.ToString()                << ". Try to use initial table properties" << std::endl;      table_properties = dumper.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;    }  }}}  // namespaceDBFileDumperCommand::DBFileDumperCommand(    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({})) {}void DBFileDumperCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(DBFileDumperCommand::Name());  ret.append("\n");}void DBFileDumperCommand::DoCommand() {  if (!db_) {    assert(GetExecuteState().IsFailed());    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);  std::string manifest_filepath = db_->GetName() + "/" + manifest_filename;  std::cout << manifest_filepath << std::endl;  DumpManifestFile(options_, manifest_filepath, false, false, false);  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(options_, filename, false, true);    std::cout << std::endl;  }  std::cout << std::endl;  std::cout << "Write Ahead Log Files" << std::endl;  std::cout << "==============================" << std::endl;  ROCKSDB_NAMESPACE::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;      // TODO(myabandeh): allow configuring is_write_commited      DumpWalFile(options_, filename, true, true, true /* is_write_commited */,                  &exec_state_);    }  }}void WriteExternalSstFilesCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(WriteExternalSstFilesCommand::Name());  ret.append(" <output_sst_path>");  ret.append("\n");}WriteExternalSstFilesCommand::WriteExternalSstFilesCommand(    const std::vector<std::string>& params,    const std::map<std::string, std::string>& options,    const std::vector<std::string>& flags)    : LDBCommand(          options, flags, false /* is_read_only */,          BuildCmdLineOptions({ARG_HEX, ARG_KEY_HEX, ARG_VALUE_HEX, ARG_FROM,                               ARG_TO, ARG_CREATE_IF_MISSING})) {  create_if_missing_ =      IsFlagPresent(flags, ARG_CREATE_IF_MISSING) ||      ParseBooleanOption(options, ARG_CREATE_IF_MISSING, false);  if (params.size() != 1) {    exec_state_ = LDBCommandExecuteResult::Failed(        "output SST file path must be specified");  } else {    output_sst_path_ = params.at(0);  }}void WriteExternalSstFilesCommand::DoCommand() {  if (!db_) {    assert(GetExecuteState().IsFailed());    return;  }  ColumnFamilyHandle* cfh = GetCfHandle();  SstFileWriter sst_file_writer(EnvOptions(), db_->GetOptions(), cfh);  Status status = sst_file_writer.Open(output_sst_path_);  if (!status.ok()) {    exec_state_ = LDBCommandExecuteResult::Failed("failed to open SST file: " +                                                  status.ToString());    return;  }  int bad_lines = 0;  std::string line;  std::ifstream ifs_stdin("/dev/stdin");  std::istream* istream_p = ifs_stdin.is_open() ? &ifs_stdin : &std::cin;  while (getline(*istream_p, line, '\n')) {    std::string key;    std::string value;    if (ParseKeyValue(line, &key, &value, is_key_hex_, is_value_hex_)) {      status = sst_file_writer.Put(key, value);      if (!status.ok()) {        exec_state_ = LDBCommandExecuteResult::Failed(            "failed to write record to file: " + status.ToString());        return;      }    } 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++;    }  }  status = sst_file_writer.Finish();  if (!status.ok()) {    exec_state_ = LDBCommandExecuteResult::Failed(        "Failed to finish writing to file: " + status.ToString());    return;  }  if (bad_lines > 0) {    fprintf(stderr, "Warning: %d bad lines ignored.\n", bad_lines);  }  exec_state_ = LDBCommandExecuteResult::Succeed(      "external SST file written to " + output_sst_path_);}Options WriteExternalSstFilesCommand::PrepareOptionsForOpenDB() {  Options opt = LDBCommand::PrepareOptionsForOpenDB();  opt.create_if_missing = create_if_missing_;  return opt;}const std::string IngestExternalSstFilesCommand::ARG_MOVE_FILES = "move_files";const std::string IngestExternalSstFilesCommand::ARG_SNAPSHOT_CONSISTENCY =    "snapshot_consistency";const std::string IngestExternalSstFilesCommand::ARG_ALLOW_GLOBAL_SEQNO =    "allow_global_seqno";const std::string IngestExternalSstFilesCommand::ARG_ALLOW_BLOCKING_FLUSH =    "allow_blocking_flush";const std::string IngestExternalSstFilesCommand::ARG_INGEST_BEHIND =    "ingest_behind";const std::string IngestExternalSstFilesCommand::ARG_WRITE_GLOBAL_SEQNO =    "write_global_seqno";void IngestExternalSstFilesCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(IngestExternalSstFilesCommand::Name());  ret.append(" <input_sst_path>");  ret.append(" [--" + ARG_MOVE_FILES + "] ");  ret.append(" [--" + ARG_SNAPSHOT_CONSISTENCY + "] ");  ret.append(" [--" + ARG_ALLOW_GLOBAL_SEQNO + "] ");  ret.append(" [--" + ARG_ALLOW_BLOCKING_FLUSH + "] ");  ret.append(" [--" + ARG_INGEST_BEHIND + "] ");  ret.append(" [--" + ARG_WRITE_GLOBAL_SEQNO + "] ");  ret.append("\n");}IngestExternalSstFilesCommand::IngestExternalSstFilesCommand(    const std::vector<std::string>& params,    const std::map<std::string, std::string>& options,    const std::vector<std::string>& flags)    : LDBCommand(          options, flags, false /* is_read_only */,          BuildCmdLineOptions({ARG_MOVE_FILES, ARG_SNAPSHOT_CONSISTENCY,                               ARG_ALLOW_GLOBAL_SEQNO, ARG_CREATE_IF_MISSING,                               ARG_ALLOW_BLOCKING_FLUSH, ARG_INGEST_BEHIND,                               ARG_WRITE_GLOBAL_SEQNO})),      move_files_(false),      snapshot_consistency_(true),      allow_global_seqno_(true),      allow_blocking_flush_(true),      ingest_behind_(false),      write_global_seqno_(true) {  create_if_missing_ =      IsFlagPresent(flags, ARG_CREATE_IF_MISSING) ||      ParseBooleanOption(options, ARG_CREATE_IF_MISSING, false);  move_files_ = IsFlagPresent(flags, ARG_MOVE_FILES) ||                ParseBooleanOption(options, ARG_MOVE_FILES, false);  snapshot_consistency_ =      IsFlagPresent(flags, ARG_SNAPSHOT_CONSISTENCY) ||      ParseBooleanOption(options, ARG_SNAPSHOT_CONSISTENCY, true);  allow_global_seqno_ =      IsFlagPresent(flags, ARG_ALLOW_GLOBAL_SEQNO) ||      ParseBooleanOption(options, ARG_ALLOW_GLOBAL_SEQNO, true);  allow_blocking_flush_ =      IsFlagPresent(flags, ARG_ALLOW_BLOCKING_FLUSH) ||      ParseBooleanOption(options, ARG_ALLOW_BLOCKING_FLUSH, true);  ingest_behind_ = IsFlagPresent(flags, ARG_INGEST_BEHIND) ||                   ParseBooleanOption(options, ARG_INGEST_BEHIND, false);  write_global_seqno_ =      IsFlagPresent(flags, ARG_WRITE_GLOBAL_SEQNO) ||      ParseBooleanOption(options, ARG_WRITE_GLOBAL_SEQNO, true);  if (allow_global_seqno_) {    if (!write_global_seqno_) {      fprintf(stderr,              "Warning: not writing global_seqno to the ingested SST can\n"              "prevent older versions of RocksDB from being able to open it\n");    }  } else {    if (write_global_seqno_) {      exec_state_ = LDBCommandExecuteResult::Failed(          "ldb cannot write global_seqno to the ingested SST when global_seqno "          "is not allowed");    }  }  if (params.size() != 1) {    exec_state_ =        LDBCommandExecuteResult::Failed("input SST path must be specified");  } else {    input_sst_path_ = params.at(0);  }}void IngestExternalSstFilesCommand::DoCommand() {  if (!db_) {    assert(GetExecuteState().IsFailed());    return;  }  if (GetExecuteState().IsFailed()) {    return;  }  ColumnFamilyHandle* cfh = GetCfHandle();  IngestExternalFileOptions ifo;  ifo.move_files = move_files_;  ifo.snapshot_consistency = snapshot_consistency_;  ifo.allow_global_seqno = allow_global_seqno_;  ifo.allow_blocking_flush = allow_blocking_flush_;  ifo.ingest_behind = ingest_behind_;  ifo.write_global_seqno = write_global_seqno_;  Status status = db_->IngestExternalFile(cfh, {input_sst_path_}, ifo);  if (!status.ok()) {    exec_state_ = LDBCommandExecuteResult::Failed(        "failed to ingest external SST: " + status.ToString());  } else {    exec_state_ =        LDBCommandExecuteResult::Succeed("external SST files ingested");  }}Options IngestExternalSstFilesCommand::PrepareOptionsForOpenDB() {  Options opt = LDBCommand::PrepareOptionsForOpenDB();  opt.create_if_missing = create_if_missing_;  return opt;}ListFileRangeDeletesCommand::ListFileRangeDeletesCommand(    const std::map<std::string, std::string>& options,    const std::vector<std::string>& flags)    : LDBCommand(options, flags, true, BuildCmdLineOptions({ARG_MAX_KEYS})) {  std::map<std::string, std::string>::const_iterator itr =      options.find(ARG_MAX_KEYS);  if (itr != options.end()) {    try {#if defined(CYGWIN)      max_keys_ = strtol(itr->second.c_str(), 0, 10);#else      max_keys_ = std::stoi(itr->second);#endif    } catch (const std::invalid_argument&) {      exec_state_ = LDBCommandExecuteResult::Failed(ARG_MAX_KEYS +                                                    " has an invalid value");    } catch (const std::out_of_range&) {      exec_state_ = LDBCommandExecuteResult::Failed(          ARG_MAX_KEYS + " has a value out-of-range");    }  }}void ListFileRangeDeletesCommand::Help(std::string& ret) {  ret.append("  ");  ret.append(ListFileRangeDeletesCommand::Name());  ret.append(" [--" + ARG_MAX_KEYS + "=<N>]");  ret.append(" : print tombstones in SST files.\n");}void ListFileRangeDeletesCommand::DoCommand() {  if (!db_) {    assert(GetExecuteState().IsFailed());    return;  }  DBImpl* db_impl = static_cast_with_check<DBImpl, DB>(db_->GetRootDB());  std::string out_str;  Status st =      db_impl->TablesRangeTombstoneSummary(GetCfHandle(), max_keys_, &out_str);  if (st.ok()) {    TEST_SYNC_POINT_CALLBACK(        "ListFileRangeDeletesCommand::DoCommand:BeforePrint", &out_str);    fprintf(stdout, "%s\n", out_str.c_str());  } else {    exec_state_ = LDBCommandExecuteResult::Failed(st.ToString());  }}}  // namespace ROCKSDB_NAMESPACE#endif  // ROCKSDB_LITE
 |