]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/ceph_kvstore_tool.cc
import 15.2.4
[ceph.git] / ceph / src / tools / ceph_kvstore_tool.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4* Ceph - scalable distributed file system
5*
6* Copyright (C) 2012 Inktank, Inc.
7*
8* This is free software; you can redistribute it and/or
9* modify it under the terms of the GNU Lesser General Public
10* License version 2.1, as published by the Free Software
11* Foundation. See file COPYING.
12*/
13#include <map>
14#include <set>
15#include <string>
11fdf7f2 16#include <fstream>
7c673cae
FG
17
18#include "common/ceph_argparse.h"
19#include "common/config.h"
20#include "common/errno.h"
21#include "common/strtol.h"
7c673cae
FG
22#include "common/url_escape.h"
23
11fdf7f2
TL
24#include "global/global_context.h"
25#include "global/global_init.h"
7c673cae 26
11fdf7f2 27#include "kvstore_tool.h"
7c673cae
FG
28
29void usage(const char *pname)
30{
11fdf7f2 31 std::cout << "Usage: " << pname << " <leveldb|rocksdb|bluestore-kv> <store path> command [args...]\n"
7c673cae
FG
32 << "\n"
33 << "Commands:\n"
34 << " list [prefix]\n"
35 << " list-crc [prefix]\n"
11fdf7f2 36 << " dump [prefix]\n"
7c673cae
FG
37 << " exists <prefix> [key]\n"
38 << " get <prefix> <key> [out <file>]\n"
39 << " crc <prefix> <key>\n"
40 << " get-size [<prefix> <key>]\n"
41 << " set <prefix> <key> [ver <N>|in <file>]\n"
31f18b77
FG
42 << " rm <prefix> <key>\n"
43 << " rm-prefix <prefix>\n"
11fdf7f2 44 << " store-copy <path> [num-keys-per-tx] [leveldb|rocksdb|...] \n"
7c673cae
FG
45 << " store-crc <path>\n"
46 << " compact\n"
47 << " compact-prefix <prefix>\n"
48 << " compact-range <prefix> <start> <end>\n"
11fdf7f2 49 << " destructive-repair (use only as last resort! may corrupt healthy data)\n"
494da23a 50 << " stats\n"
7c673cae
FG
51 << std::endl;
52}
53
54int main(int argc, const char *argv[])
55{
56 vector<const char*> args;
57 argv_to_vec(argc, argv, args);
11fdf7f2
TL
58 if (args.empty()) {
59 cerr << argv[0] << ": -h or --help for usage" << std::endl;
60 exit(1);
61 }
62 if (ceph_argparse_need_usage(args)) {
63 usage(argv[0]);
64 exit(0);
65 }
66
67 map<string,string> defaults = {
68 { "debug_rocksdb", "2" }
69 };
7c673cae
FG
70
71 auto cct = global_init(
11fdf7f2
TL
72 &defaults, args,
73 CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY,
74 CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
7c673cae
FG
75 common_init_finish(g_ceph_context);
76
11fdf7f2
TL
77 ceph_assert((int)args.size() < argc);
78 for(size_t i=0; i<args.size(); i++)
79 argv[i+1] = args[i];
80 argc = args.size() + 1;
7c673cae
FG
81
82 if (args.size() < 3) {
83 usage(argv[0]);
84 return 1;
85 }
86
87 string type(args[0]);
88 string path(args[1]);
89 string cmd(args[2]);
90
11fdf7f2
TL
91 if (type != "leveldb" &&
92 type != "rocksdb" &&
93 type != "bluestore-kv") {
94
95 std::cerr << "Unrecognized type: " << args[0] << std::endl;
96 usage(argv[0]);
97 return 1;
98 }
99
100 bool need_open_db = (cmd != "destructive-repair");
494da23a
TL
101 bool need_stats = (cmd == "stats");
102 StoreTool st(type, path, need_open_db, need_stats);
7c673cae 103
11fdf7f2
TL
104 if (cmd == "destructive-repair") {
105 int ret = st.destructive_repair();
106 if (!ret) {
107 std::cout << "destructive-repair completed without reporting an error"
108 << std::endl;
109 } else {
110 std::cout << "destructive-repair failed with " << cpp_strerror(ret)
111 << std::endl;
112 }
113 return ret;
114 } else if (cmd == "list" || cmd == "list-crc") {
7c673cae
FG
115 string prefix;
116 if (argc > 4)
117 prefix = url_unescape(argv[4]);
118
119 bool do_crc = (cmd == "list-crc");
11fdf7f2 120 st.list(prefix, do_crc, false);
7c673cae 121
11fdf7f2
TL
122 } else if (cmd == "dump") {
123 string prefix;
124 if (argc > 4)
125 prefix = url_unescape(argv[4]);
126 st.list(prefix, false, true);
7c673cae
FG
127
128 } else if (cmd == "exists") {
129 string key;
130 if (argc < 5) {
131 usage(argv[0]);
132 return 1;
133 }
134 string prefix(url_unescape(argv[4]));
135 if (argc > 5)
136 key = url_unescape(argv[5]);
137
138 bool ret = st.exists(prefix, key);
139 std::cout << "(" << url_escape(prefix) << ", " << url_escape(key) << ") "
140 << (ret ? "exists" : "does not exist")
141 << std::endl;
142 return (ret ? 0 : 1);
143
144 } else if (cmd == "get") {
145 if (argc < 6) {
146 usage(argv[0]);
147 return 1;
148 }
149 string prefix(url_unescape(argv[4]));
150 string key(url_unescape(argv[5]));
151
152 bool exists = false;
153 bufferlist bl = st.get(prefix, key, exists);
154 std::cout << "(" << url_escape(prefix) << ", " << url_escape(key) << ")";
155 if (!exists) {
156 std::cout << " does not exist" << std::endl;
157 return 1;
158 }
159 std::cout << std::endl;
160
161 if (argc >= 7) {
162 string subcmd(argv[6]);
163 if (subcmd != "out") {
164 std::cerr << "unrecognized subcmd '" << subcmd << "'"
165 << std::endl;
166 return 1;
167 }
168 if (argc < 8) {
169 std::cerr << "output path not specified" << std::endl;
170 return 1;
171 }
172 string out(argv[7]);
173
174 if (out.empty()) {
175 std::cerr << "unspecified out file" << std::endl;
176 return 1;
177 }
178
179 int err = bl.write_file(argv[7], 0644);
180 if (err < 0) {
181 std::cerr << "error writing value to '" << out << "': "
182 << cpp_strerror(err) << std::endl;
183 return 1;
184 }
185 } else {
186 ostringstream os;
187 bl.hexdump(os);
188 std::cout << os.str() << std::endl;
189 }
190
191 } else if (cmd == "crc") {
192 if (argc < 6) {
193 usage(argv[0]);
194 return 1;
195 }
196 string prefix(url_unescape(argv[4]));
197 string key(url_unescape(argv[5]));
198
199 bool exists = false;
200 bufferlist bl = st.get(prefix, key, exists);
201 std::cout << "(" << url_escape(prefix) << ", " << url_escape(key) << ") ";
202 if (!exists) {
203 std::cout << " does not exist" << std::endl;
204 return 1;
205 }
206 std::cout << " crc " << bl.crc32c(0) << std::endl;
207
208 } else if (cmd == "get-size") {
209 std::cout << "estimated store size: " << st.get_size() << std::endl;
210
211 if (argc < 5)
212 return 0;
213
214 if (argc < 6) {
215 usage(argv[0]);
216 return 1;
217 }
218 string prefix(url_unescape(argv[4]));
219 string key(url_unescape(argv[5]));
220
221 bool exists = false;
222 bufferlist bl = st.get(prefix, key, exists);
223 if (!exists) {
224 std::cerr << "(" << url_escape(prefix) << "," << url_escape(key)
225 << ") does not exist" << std::endl;
226 return 1;
227 }
228 std::cout << "(" << url_escape(prefix) << "," << url_escape(key)
11fdf7f2 229 << ") size " << byte_u_t(bl.length()) << std::endl;
7c673cae
FG
230
231 } else if (cmd == "set") {
232 if (argc < 8) {
233 usage(argv[0]);
234 return 1;
235 }
236 string prefix(url_unescape(argv[4]));
237 string key(url_unescape(argv[5]));
238 string subcmd(argv[6]);
239
240 bufferlist val;
241 string errstr;
242 if (subcmd == "ver") {
243 version_t v = (version_t) strict_strtoll(argv[7], 10, &errstr);
244 if (!errstr.empty()) {
245 std::cerr << "error reading version: " << errstr << std::endl;
246 return 1;
247 }
11fdf7f2 248 encode(v, val);
7c673cae
FG
249 } else if (subcmd == "in") {
250 int ret = val.read_file(argv[7], &errstr);
251 if (ret < 0 || !errstr.empty()) {
252 std::cerr << "error reading file: " << errstr << std::endl;
253 return 1;
254 }
255 } else {
256 std::cerr << "unrecognized subcommand '" << subcmd << "'" << std::endl;
257 usage(argv[0]);
258 return 1;
259 }
260
261 bool ret = st.set(prefix, key, val);
262 if (!ret) {
263 std::cerr << "error setting ("
264 << url_escape(prefix) << "," << url_escape(key) << ")" << std::endl;
265 return 1;
266 }
31f18b77
FG
267 } else if (cmd == "rm") {
268 if (argc < 6) {
269 usage(argv[0]);
270 return 1;
271 }
272 string prefix(url_unescape(argv[4]));
273 string key(url_unescape(argv[5]));
274
275 bool ret = st.rm(prefix, key);
276 if (!ret) {
277 std::cerr << "error removing ("
278 << url_escape(prefix) << "," << url_escape(key) << ")"
279 << std::endl;
280 return 1;
281 }
282 } else if (cmd == "rm-prefix") {
283 if (argc < 5) {
284 usage(argv[0]);
285 return 1;
286 }
287 string prefix(url_unescape(argv[4]));
288
289 bool ret = st.rm_prefix(prefix);
290 if (!ret) {
291 std::cerr << "error removing prefix ("
292 << url_escape(prefix) << ")"
293 << std::endl;
294 return 1;
295 }
7c673cae
FG
296 } else if (cmd == "store-copy") {
297 int num_keys_per_tx = 128; // magic number that just feels right.
298 if (argc < 5) {
299 usage(argv[0]);
300 return 1;
301 } else if (argc > 5) {
302 string err;
303 num_keys_per_tx = strict_strtol(argv[5], 10, &err);
304 if (!err.empty()) {
305 std::cerr << "invalid num_keys_per_tx: " << err << std::endl;
306 return 1;
307 }
308 }
11fdf7f2
TL
309 string other_store_type = argv[1];
310 if (argc > 6) {
311 other_store_type = argv[6];
312 }
7c673cae 313
11fdf7f2 314 int ret = st.copy_store_to(argv[1], argv[4], num_keys_per_tx, other_store_type);
7c673cae
FG
315 if (ret < 0) {
316 std::cerr << "error copying store to path '" << argv[4]
317 << "': " << cpp_strerror(ret) << std::endl;
318 return 1;
319 }
320
321 } else if (cmd == "store-crc") {
11fdf7f2
TL
322 if (argc < 4) {
323 usage(argv[0]);
324 return 1;
325 }
326 std::ofstream fs(argv[4]);
327 uint32_t crc = st.traverse(string(), true, false, &fs);
328 std::cout << "store at '" << argv[4] << "' crc " << crc << std::endl;
7c673cae
FG
329
330 } else if (cmd == "compact") {
331 st.compact();
332 } else if (cmd == "compact-prefix") {
333 if (argc < 5) {
334 usage(argv[0]);
335 return 1;
336 }
337 string prefix(url_unescape(argv[4]));
338 st.compact_prefix(prefix);
339 } else if (cmd == "compact-range") {
340 if (argc < 7) {
341 usage(argv[0]);
342 return 1;
343 }
344 string prefix(url_unescape(argv[4]));
345 string start(url_unescape(argv[5]));
346 string end(url_unescape(argv[6]));
347 st.compact_range(prefix, start, end);
494da23a
TL
348 } else if (cmd == "stats") {
349 st.print_stats();
7c673cae
FG
350 } else {
351 std::cerr << "Unrecognized command: " << cmd << std::endl;
352 return 1;
353 }
354
355 return 0;
356}