1 //  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 //
6 #pragma once
7 
8 #ifndef ROCKSDB_LITE
9 
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <algorithm>
13 #include <functional>
14 #include <map>
15 #include <sstream>
16 #include <string>
17 #include <vector>
18 
19 #include "rocksdb/env.h"
20 #include "rocksdb/iterator.h"
21 #include "rocksdb/ldb_tool.h"
22 #include "rocksdb/options.h"
23 #include "rocksdb/slice.h"
24 #include "rocksdb/utilities/db_ttl.h"
25 #include "rocksdb/utilities/ldb_cmd_execute_result.h"
26 
27 namespace ROCKSDB_NAMESPACE {
28 
29 class LDBCommand {
30  public:
31   // Command-line arguments
32   static const std::string ARG_ENV_URI;
33   static const std::string ARG_DB;
34   static const std::string ARG_PATH;
35   static const std::string ARG_SECONDARY_PATH;
36   static const std::string ARG_HEX;
37   static const std::string ARG_KEY_HEX;
38   static const std::string ARG_VALUE_HEX;
39   static const std::string ARG_CF_NAME;
40   static const std::string ARG_TTL;
41   static const std::string ARG_TTL_START;
42   static const std::string ARG_TTL_END;
43   static const std::string ARG_TIMESTAMP;
44   static const std::string ARG_TRY_LOAD_OPTIONS;
45   static const std::string ARG_IGNORE_UNKNOWN_OPTIONS;
46   static const std::string ARG_FROM;
47   static const std::string ARG_TO;
48   static const std::string ARG_MAX_KEYS;
49   static const std::string ARG_BLOOM_BITS;
50   static const std::string ARG_FIX_PREFIX_LEN;
51   static const std::string ARG_COMPRESSION_TYPE;
52   static const std::string ARG_COMPRESSION_MAX_DICT_BYTES;
53   static const std::string ARG_BLOCK_SIZE;
54   static const std::string ARG_AUTO_COMPACTION;
55   static const std::string ARG_DB_WRITE_BUFFER_SIZE;
56   static const std::string ARG_WRITE_BUFFER_SIZE;
57   static const std::string ARG_FILE_SIZE;
58   static const std::string ARG_CREATE_IF_MISSING;
59   static const std::string ARG_NO_VALUE;
60 
61   struct ParsedParams {
62     std::string cmd;
63     std::vector<std::string> cmd_params;
64     std::map<std::string, std::string> option_map;
65     std::vector<std::string> flags;
66   };
67 
68   static LDBCommand* SelectCommand(const ParsedParams& parsed_parms);
69 
70   static LDBCommand* InitFromCmdLineArgs(
71       const std::vector<std::string>& args, const Options& options,
72       const LDBOptions& ldb_options,
73       const std::vector<ColumnFamilyDescriptor>* column_families,
74       const std::function<LDBCommand*(const ParsedParams&)>& selector =
75           SelectCommand);
76 
77   static LDBCommand* InitFromCmdLineArgs(
78       int argc, char** argv, const Options& options,
79       const LDBOptions& ldb_options,
80       const std::vector<ColumnFamilyDescriptor>* column_families);
81 
82   bool ValidateCmdLineOptions();
83 
84   virtual Options PrepareOptionsForOpenDB();
85 
SetDBOptions(Options options)86   virtual void SetDBOptions(Options options) { options_ = options; }
87 
SetColumnFamilies(const std::vector<ColumnFamilyDescriptor> * column_families)88   virtual void SetColumnFamilies(
89       const std::vector<ColumnFamilyDescriptor>* column_families) {
90     if (column_families != nullptr) {
91       column_families_ = *column_families;
92     } else {
93       column_families_.clear();
94     }
95   }
96 
SetLDBOptions(const LDBOptions & ldb_options)97   void SetLDBOptions(const LDBOptions& ldb_options) {
98     ldb_options_ = ldb_options;
99   }
100 
TEST_GetOptionMap()101   const std::map<std::string, std::string>& TEST_GetOptionMap() {
102     return option_map_;
103   }
104 
TEST_GetFlags()105   const std::vector<std::string>& TEST_GetFlags() { return flags_; }
106 
NoDBOpen()107   virtual bool NoDBOpen() { return false; }
108 
~LDBCommand()109   virtual ~LDBCommand() { CloseDB(); }
110 
111   /* Run the command, and return the execute result. */
112   void Run();
113 
114   virtual void DoCommand() = 0;
115 
GetExecuteState()116   LDBCommandExecuteResult GetExecuteState() { return exec_state_; }
117 
ClearPreviousRunState()118   void ClearPreviousRunState() { exec_state_.Reset(); }
119 
120   // Consider using Slice::DecodeHex directly instead if you don't need the
121   // 0x prefix
122   static std::string HexToString(const std::string& str);
123 
124   // Consider using Slice::ToString(true) directly instead if
125   // you don't need the 0x prefix
126   static std::string StringToHex(const std::string& str);
127 
128   static const char* DELIM;
129 
130  protected:
131   LDBCommandExecuteResult exec_state_;
132   std::string env_uri_;
133   std::string db_path_;
134   // If empty, open DB as primary. If non-empty, open the DB as secondary
135   // with this secondary path. When running against a database opened by
136   // another process, ldb wll leave the source directory completely intact.
137   std::string secondary_path_;
138   std::string column_family_name_;
139   DB* db_;
140   DBWithTTL* db_ttl_;
141   std::map<std::string, ColumnFamilyHandle*> cf_handles_;
142 
143   /**
144    * true implies that this command can work if the db is opened in read-only
145    * mode.
146    */
147   bool is_read_only_;
148 
149   /** If true, the key is input/output as hex in get/put/scan/delete etc. */
150   bool is_key_hex_;
151 
152   /** If true, the value is input/output as hex in get/put/scan/delete etc. */
153   bool is_value_hex_;
154 
155   /** If true, the value is treated as timestamp suffixed */
156   bool is_db_ttl_;
157 
158   // If true, the kvs are output with their insert/modify timestamp in a ttl db
159   bool timestamp_;
160 
161   // If true, try to construct options from DB's option files.
162   bool try_load_options_;
163 
164   bool ignore_unknown_options_;
165 
166   bool create_if_missing_;
167 
168   /**
169    * Map of options passed on the command-line.
170    */
171   const std::map<std::string, std::string> option_map_;
172 
173   /**
174    * Flags passed on the command-line.
175    */
176   const std::vector<std::string> flags_;
177 
178   /** List of command-line options valid for this command */
179   const std::vector<std::string> valid_cmd_line_options_;
180 
181   /** Shared pointer to underlying environment if applicable **/
182   std::shared_ptr<Env> env_guard_;
183 
184   bool ParseKeyValue(const std::string& line, std::string* key,
185                      std::string* value, bool is_key_hex, bool is_value_hex);
186 
187   LDBCommand(const std::map<std::string, std::string>& options,
188              const std::vector<std::string>& flags, bool is_read_only,
189              const std::vector<std::string>& valid_cmd_line_options);
190 
191   void OpenDB();
192 
193   void CloseDB();
194 
195   ColumnFamilyHandle* GetCfHandle();
196 
197   static std::string PrintKeyValue(const std::string& key,
198                                    const std::string& value, bool is_key_hex,
199                                    bool is_value_hex);
200 
201   static std::string PrintKeyValue(const std::string& key,
202                                    const std::string& value, bool is_hex);
203 
204   /**
205    * Return true if the specified flag is present in the specified flags vector
206    */
IsFlagPresent(const std::vector<std::string> & flags,const std::string & flag)207   static bool IsFlagPresent(const std::vector<std::string>& flags,
208                             const std::string& flag) {
209     return (std::find(flags.begin(), flags.end(), flag) != flags.end());
210   }
211 
212   static std::string HelpRangeCmdArgs();
213 
214   /**
215    * A helper function that returns a list of command line options
216    * used by this command.  It includes the common options and the ones
217    * passed in.
218    */
219   static std::vector<std::string> BuildCmdLineOptions(
220       std::vector<std::string> options);
221 
222   bool ParseIntOption(const std::map<std::string, std::string>& options,
223                       const std::string& option, int& value,
224                       LDBCommandExecuteResult& exec_state);
225 
226   bool ParseStringOption(const std::map<std::string, std::string>& options,
227                          const std::string& option, std::string* value);
228 
229   /**
230    * Returns the value of the specified option as a boolean.
231    * default_val is used if the option is not found in options.
232    * Throws an exception if the value of the option is not
233    * "true" or "false" (case insensitive).
234    */
235   bool ParseBooleanOption(const std::map<std::string, std::string>& options,
236                           const std::string& option, bool default_val);
237 
238   Options options_;
239   std::vector<ColumnFamilyDescriptor> column_families_;
240   LDBOptions ldb_options_;
241 
242  private:
243   /**
244    * Interpret command line options and flags to determine if the key
245    * should be input/output in hex.
246    */
247   bool IsKeyHex(const std::map<std::string, std::string>& options,
248                 const std::vector<std::string>& flags);
249 
250   /**
251    * Interpret command line options and flags to determine if the value
252    * should be input/output in hex.
253    */
254   bool IsValueHex(const std::map<std::string, std::string>& options,
255                   const std::vector<std::string>& flags);
256 
257   /**
258    * Converts val to a boolean.
259    * val must be either true or false (case insensitive).
260    * Otherwise an exception is thrown.
261    */
262   bool StringToBool(std::string val);
263 };
264 
265 class LDBCommandRunner {
266  public:
267   static void PrintHelp(const LDBOptions& ldb_options, const char* exec_name);
268 
269   // Returns the status code to return. 0 is no error.
270   static int RunCommand(
271       int argc, char** argv, Options options, const LDBOptions& ldb_options,
272       const std::vector<ColumnFamilyDescriptor>* column_families);
273 };
274 
275 }  // namespace ROCKSDB_NAMESPACE
276 
277 #endif  // ROCKSDB_LITE
278