]>
Commit | Line | Data |
---|---|---|
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) 2004-2006 Sage Weil <sage@newdream.net> | |
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 | */ | |
14 | ||
15 | #include "include/types.h" | |
16 | ||
11fdf7f2 | 17 | #include "include/rados/buffer.h" |
7c673cae FG |
18 | #include "include/rados/librados.hpp" |
19 | #include "include/rados/rados_types.hpp" | |
11fdf7f2 TL |
20 | |
21 | #include "acconfig.h" | |
22 | #ifdef WITH_LIBRADOSSTRIPER | |
23 | #include "include/radosstriper/libradosstriper.hpp" | |
24 | using namespace libradosstriper; | |
25 | #endif | |
7c673cae FG |
26 | |
27 | #include "common/config.h" | |
28 | #include "common/ceph_argparse.h" | |
29 | #include "global/global_init.h" | |
30 | #include "common/Cond.h" | |
31 | #include "common/debug.h" | |
32 | #include "common/errno.h" | |
33 | #include "common/Formatter.h" | |
34 | #include "common/obj_bencher.h" | |
35 | #include "common/TextTable.h" | |
36 | #include "include/stringify.h" | |
37 | #include "mds/inode_backtrace.h" | |
11fdf7f2 | 38 | #include "include/random.h" |
7c673cae FG |
39 | #include <iostream> |
40 | #include <fstream> | |
41 | ||
42 | #include <stdlib.h> | |
43 | #include <time.h> | |
44 | #include <sstream> | |
45 | #include <errno.h> | |
46 | #include <dirent.h> | |
47 | #include <stdexcept> | |
48 | #include <climits> | |
49 | #include <locale> | |
50 | #include <memory> | |
f67539c2 | 51 | #include <optional> |
7c673cae FG |
52 | |
53 | #include "cls/lock/cls_lock_client.h" | |
54 | #include "include/compat.h" | |
55 | #include "include/util.h" | |
56 | #include "common/hobject.h" | |
57 | ||
58 | #include "PoolDump.h" | |
59 | #include "RadosImport.h" | |
60 | ||
94b18763 FG |
61 | #include "osd/ECUtil.h" |
62 | ||
20effc67 | 63 | using namespace std::chrono_literals; |
7c673cae | 64 | using namespace librados; |
11fdf7f2 | 65 | using ceph::util::generate_random_number; |
20effc67 TL |
66 | using std::cerr; |
67 | using std::cout; | |
68 | using std::dec; | |
69 | using std::hex; | |
70 | using std::less; | |
71 | using std::list; | |
72 | using std::map; | |
73 | using std::multiset; | |
74 | using std::ofstream; | |
75 | using std::ostream; | |
76 | using std::pair; | |
77 | using std::set; | |
78 | using std::string; | |
79 | using std::unique_ptr; | |
80 | using std::vector; | |
7c673cae FG |
81 | |
82 | // two steps seem to be necessary to do this right | |
83 | #define STR(x) _STR(x) | |
84 | #define _STR(x) #x | |
85 | ||
86 | void usage(ostream& out) | |
87 | { | |
88 | out << \ | |
89 | "usage: rados [options] [commands]\n" | |
90 | "POOL COMMANDS\n" | |
91 | " lspools list pools\n" | |
7c673cae | 92 | " cppool <pool-name> <dest-pool> copy content of a pool\n" |
7c673cae | 93 | " purge <pool-name> --yes-i-really-really-mean-it\n" |
aee94f69 | 94 | " remove all objects from pool <pool-name> without removing the pool itself\n" |
7c673cae FG |
95 | " df show per-pool and total usage\n" |
96 | " ls list objects in pool\n\n" | |
7c673cae FG |
97 | "\n" |
98 | "POOL SNAP COMMANDS\n" | |
99 | " lssnap list snaps\n" | |
100 | " mksnap <snap-name> create snap <snap-name>\n" | |
101 | " rmsnap <snap-name> remove snap <snap-name>\n" | |
102 | "\n" | |
103 | "OBJECT COMMANDS\n" | |
11fdf7f2 TL |
104 | " get <obj-name> <outfile> fetch object\n" |
105 | " put <obj-name> <infile> [--offset offset]\n" | |
31f18b77 | 106 | " write object with start offset (default:0)\n" |
11fdf7f2 | 107 | " append <obj-name> <infile> append object\n" |
7c673cae FG |
108 | " truncate <obj-name> length truncate object\n" |
109 | " create <obj-name> create object\n" | |
20effc67 | 110 | " rm <obj-name> ... [--force-full] remove object(s), --force-full forces remove when cluster is full\n" |
7c673cae | 111 | " cp <obj-name> [target-obj] copy object\n" |
20effc67 TL |
112 | " listxattr <obj-name> list attrs of this object\n" |
113 | " getxattr <obj-name> <attr> get the <attr> attribute of this object\n" | |
7c673cae FG |
114 | " setxattr <obj-name> attr val\n" |
115 | " rmxattr <obj-name> attr\n" | |
35e4c445 | 116 | " stat <obj-name> stat the named object\n" |
11fdf7f2 TL |
117 | " stat2 <obj-name> stat2 the named object (with high precision time)\n" |
118 | " touch <obj-name> [timestamp] change the named object modification time\n" | |
7c673cae FG |
119 | " mapext <obj-name>\n" |
120 | " rollback <obj-name> <snap-name> roll back object to snap <snap-name>\n" | |
121 | "\n" | |
122 | " listsnaps <obj-name> list the snapshots of this object\n" | |
11fdf7f2 | 123 | " bench <seconds> write|seq|rand [-t concurrent_operations] [--no-cleanup] [--run-name run_name] [--no-hints] [--reuse-bench]\n" |
7c673cae FG |
124 | " default is 16 concurrent IOs and 4 MB ops\n" |
125 | " default is to clean up after write benchmark\n" | |
126 | " default run-name is 'benchmark_last_metadata'\n" | |
127 | " cleanup [--run-name run_name] [--prefix prefix]\n" | |
128 | " clean up a previous benchmark operation\n" | |
129 | " default run-name is 'benchmark_last_metadata'\n" | |
130 | " load-gen [options] generate load on the cluster\n" | |
131 | " listomapkeys <obj-name> list the keys in the object map\n" | |
132 | " listomapvals <obj-name> list the keys and vals in the object map \n" | |
133 | " getomapval <obj-name> <key> [file] show the value for the specified key\n" | |
134 | " in the object's object map\n" | |
f67539c2 | 135 | " setomapval <obj-name> <key> <val | --input-file file>\n" |
20effc67 | 136 | " rmomapkey <obj-name> <key> Remove key from the object map of <obj-name>\n" |
11fdf7f2 | 137 | " clearomap <obj-name> [obj-name2 obj-name3...] clear all the omap keys for the specified objects\n" |
20effc67 TL |
138 | " getomapheader <obj-name> [file] Dump the hexadecimal value of the object map header of <obj-name>\n" |
139 | " setomapheader <obj-name> <val> Set the value of the object map header of <obj-name>\n" | |
7c673cae FG |
140 | " watch <obj-name> add watcher on this object\n" |
141 | " notify <obj-name> <message> notify watcher of this object with message\n" | |
142 | " listwatchers <obj-name> list the watchers of this object\n" | |
143 | " set-alloc-hint <obj-name> <expected-object-size> <expected-write-size>\n" | |
144 | " set allocation hint for an object\n" | |
11fdf7f2 TL |
145 | " set-redirect <object A> --target-pool <caspool> <target object A> [--with-reference]\n" |
146 | " set redirect target\n" | |
147 | " set-chunk <object A> <offset> <length> --target-pool <caspool> <target object A> <taget-offset> [--with-reference]\n" | |
148 | " convert an object to chunked object\n" | |
149 | " tier-promote <obj-name> promote the object to the base tier\n" | |
150 | " unset-manifest <obj-name> unset redirect or chunked object\n" | |
9f95a23c | 151 | " tier-flush <obj-name> flush the chunked object\n" |
f67539c2 | 152 | " tier-evict <obj-name> evict the chunked object\n" |
7c673cae FG |
153 | "\n" |
154 | "IMPORT AND EXPORT\n" | |
155 | " export [filename]\n" | |
156 | " Serialize pool contents to a file or standard out.\n" | |
157 | " import [--dry-run] [--no-overwrite] < filename | - >\n" | |
158 | " Load pool contents from a file or standard in\n" | |
159 | "\n" | |
160 | "ADVISORY LOCKS\n" | |
161 | " lock list <obj-name>\n" | |
162 | " List all advisory locks on an object\n" | |
9f95a23c | 163 | " lock get <obj-name> <lock-name> [--lock-cookie locker-cookie] [--lock-tag locker-tag] [--lock-description locker-desc] [--lock-duration locker-dur] [--lock-type locker-type]\n" |
7c673cae | 164 | " Try to acquire a lock\n" |
9f95a23c | 165 | " lock break <obj-name> <lock-name> <locker-name> [--lock-cookie locker-cookie]\n" |
7c673cae FG |
166 | " Try to break a lock acquired by another client\n" |
167 | " lock info <obj-name> <lock-name>\n" | |
168 | " Show lock information\n" | |
169 | " options:\n" | |
170 | " --lock-tag Lock tag, all locks operation should use\n" | |
171 | " the same tag\n" | |
172 | " --lock-cookie Locker cookie\n" | |
173 | " --lock-description Description of lock\n" | |
174 | " --lock-duration Lock duration (in seconds)\n" | |
175 | " --lock-type Lock type (shared, exclusive)\n" | |
176 | "\n" | |
177 | "SCRUB AND REPAIR:\n" | |
178 | " list-inconsistent-pg <pool> list inconsistent PGs in given pool\n" | |
eafe8130 TL |
179 | " list-inconsistent-obj <pgid> list inconsistent objects in given PG\n" |
180 | " list-inconsistent-snapset <pgid> list inconsistent snapsets in the given PG\n" | |
7c673cae FG |
181 | "\n" |
182 | "CACHE POOLS: (for testing/development only)\n" | |
183 | " cache-flush <obj-name> flush cache pool object (blocking)\n" | |
184 | " cache-try-flush <obj-name> flush cache pool object (non-blocking)\n" | |
185 | " cache-evict <obj-name> evict cache pool object\n" | |
186 | " cache-flush-evict-all flush+evict all objects\n" | |
187 | " cache-try-flush-evict-all try-flush+evict all objects\n" | |
188 | "\n" | |
189 | "GLOBAL OPTIONS:\n" | |
f67539c2 | 190 | " --object-locator object_locator\n" |
7c673cae FG |
191 | " set object_locator for operation\n" |
192 | " -p pool\n" | |
193 | " --pool=pool\n" | |
194 | " select given pool by name\n" | |
195 | " --target-pool=pool\n" | |
196 | " select target pool by name\n" | |
eafe8130 TL |
197 | " --pgid PG id\n" |
198 | " select given PG id\n" | |
11fdf7f2 TL |
199 | " -f [--format plain|json|json-pretty]\n" |
200 | " --format=[--format plain|json|json-pretty]\n" | |
7c673cae FG |
201 | " -b op_size\n" |
202 | " set the block size for put/get ops and for write benchmarking\n" | |
9f95a23c | 203 | " -O object_size\n" |
7c673cae FG |
204 | " set the object size for put/get ops and for write benchmarking\n" |
205 | " --max-objects\n" | |
206 | " set the max number of objects for write benchmarking\n" | |
f67539c2 TL |
207 | " --obj-name-file file\n" |
208 | " use the content of the specified file in place of <obj-name>\n" | |
7c673cae FG |
209 | " -s name\n" |
210 | " --snap name\n" | |
211 | " select given snap name for (read) IO\n" | |
f67539c2 TL |
212 | " --input-file file\n" |
213 | " use the content of the specified file in place of <val>\n" | |
7c673cae FG |
214 | " --create\n" |
215 | " create the pool or directory that was specified\n" | |
216 | " -N namespace\n" | |
217 | " --namespace=namespace\n" | |
218 | " specify the namespace to use for the object\n" | |
219 | " --all\n" | |
220 | " Use with ls to list objects in all namespaces\n" | |
221 | " Put in CEPH_ARGS environment variable to make this the default\n" | |
222 | " --default\n" | |
223 | " Use with ls to list objects in default namespace\n" | |
224 | " Takes precedence over --all in case --all is in environment\n" | |
225 | " --target-locator\n" | |
226 | " Use with cp to specify the locator of the new object\n" | |
227 | " --target-nspace\n" | |
228 | " Use with cp to specify the namespace of the new object\n" | |
11fdf7f2 | 229 | #ifdef WITH_LIBRADOSSTRIPER |
7c673cae FG |
230 | " --striper\n" |
231 | " Use radostriper interface rather than pure rados\n" | |
232 | " Available for stat, get, put, truncate, rm, ls and \n" | |
233 | " all xattr related operations\n" | |
11fdf7f2 | 234 | #endif |
7c673cae FG |
235 | "\n" |
236 | "BENCH OPTIONS:\n" | |
237 | " -t N\n" | |
238 | " --concurrent-ios=N\n" | |
239 | " Set number of concurrent I/O operations\n" | |
240 | " --show-time\n" | |
241 | " prefix output with date/time\n" | |
242 | " --no-verify\n" | |
243 | " do not verify contents of read objects\n" | |
244 | " --write-object\n" | |
245 | " write contents to the objects\n" | |
246 | " --write-omap\n" | |
247 | " write contents to the omap\n" | |
248 | " --write-xattr\n" | |
249 | " write contents to the extended attributes\n" | |
250 | "\n" | |
251 | "LOAD GEN OPTIONS:\n" | |
252 | " --num-objects total number of objects\n" | |
253 | " --min-object-size min object size\n" | |
254 | " --max-object-size max object size\n" | |
255 | " --min-op-len min io size of operations\n" | |
256 | " --max-op-len max io size of operations\n" | |
257 | " --max-ops max number of operations\n" | |
258 | " --max-backlog max backlog size\n" | |
259 | " --read-percent percent of operations that are read\n" | |
260 | " --target-throughput target throughput (in bytes)\n" | |
261 | " --run-length total time (in seconds)\n" | |
f67539c2 TL |
262 | " --offset-align at what boundary to align random op offsets\n" |
263 | "\n" | |
7c673cae FG |
264 | "CACHE POOLS OPTIONS:\n" |
265 | " --with-clones include clones when doing flush or evict\n" | |
f67539c2 | 266 | "\n" |
7c673cae | 267 | "OMAP OPTIONS:\n" |
f67539c2 TL |
268 | " --omap-key-file file read the omap key from a file\n" |
269 | "\n" | |
270 | "GENERIC OPTIONS:\n"; | |
271 | generic_client_usage(); | |
7c673cae FG |
272 | } |
273 | ||
11fdf7f2 TL |
274 | namespace detail { |
275 | ||
276 | #ifdef WITH_LIBRADOSSTRIPER | |
277 | RadosStriper& striper() | |
278 | { | |
279 | static RadosStriper s; | |
280 | return s; | |
281 | } | |
282 | #endif | |
283 | ||
284 | int read([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, buffer::list& out_data, const unsigned op_size, const uint64_t offset, [[maybe_unused]] const bool use_striper) | |
285 | { | |
286 | #ifdef WITH_LIBRADOSSTRIPER | |
287 | if (use_striper) | |
288 | return striper().read(oid, &out_data, op_size, offset); | |
289 | #endif | |
290 | ||
291 | return io_ctx.read(oid, out_data, op_size, offset); | |
292 | } | |
293 | ||
294 | int write([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, buffer::list& indata, const uint64_t count, const uint64_t offset, [[maybe_unused]] const bool use_striper) | |
295 | { | |
296 | #ifdef WITH_LIBRADOSSTRIPER | |
297 | if (use_striper) | |
298 | return striper().write(oid, indata, count, offset); | |
299 | #endif | |
300 | ||
301 | return io_ctx.write(oid, indata, count, offset); | |
302 | } | |
303 | ||
304 | int write_full([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, bufferlist& indata, [[maybe_unused]] const bool use_striper) | |
305 | { | |
306 | #ifdef WITH_LIBRADOSSTRIPER | |
307 | if (use_striper) | |
308 | return striper().write_full(oid, indata); | |
309 | #endif | |
310 | ||
311 | return io_ctx.write_full(oid, indata); | |
312 | } | |
313 | ||
314 | int trunc([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, const uint64_t offset, [[maybe_unused]] const bool use_striper) | |
315 | { | |
316 | #ifdef WITH_LIBRADOSSTRIPER | |
317 | if (use_striper) | |
318 | return striper().trunc(oid, offset); | |
319 | #endif | |
320 | ||
321 | return io_ctx.trunc(oid, offset); | |
322 | } | |
323 | ||
324 | int append([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, buffer::list& indata, const uint64_t count, [[maybe_unused]] const bool use_striper) | |
325 | { | |
326 | #ifdef WITH_LIBRADOSSTRIPER | |
327 | if (use_striper) | |
328 | return striper().append(oid, indata, count); | |
329 | #endif | |
330 | ||
331 | return io_ctx.append(oid, indata, count); | |
332 | } | |
333 | ||
334 | int setxattr([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, const std::string& attr_name, buffer::list& bl, [[maybe_unused]] const bool use_striper) | |
335 | { | |
336 | #ifdef WITH_LIBRADOSSTRIPER | |
337 | if (use_striper) | |
338 | return striper().setxattr(oid, attr_name.c_str(), bl); | |
339 | #endif | |
340 | ||
341 | return io_ctx.setxattr(oid, attr_name.c_str(), bl); | |
342 | } | |
343 | ||
344 | int getxattr([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, const std::string& attr_name, buffer::list& bl, [[maybe_unused]] const bool use_striper) | |
345 | { | |
346 | #ifdef WITH_LIBRADOSSTRIPER | |
347 | if (use_striper) | |
348 | return striper().getxattr(oid, attr_name.c_str(), bl); | |
349 | #endif | |
350 | ||
351 | return io_ctx.getxattr(oid, attr_name.c_str(), bl); | |
352 | } | |
353 | ||
354 | int rmxattr([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, const std::string& attr_name, [[maybe_unused]] const bool use_striper) | |
355 | { | |
356 | #ifdef WITH_LIBRADOSSTRIPER | |
357 | if (use_striper) | |
358 | return striper().rmxattr(oid, attr_name.c_str()); | |
359 | #endif | |
360 | ||
361 | return io_ctx.rmxattr(oid, attr_name.c_str()); | |
362 | } | |
363 | ||
364 | int getxattrs([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, std::map<std::string, buffer::list>& attrset, [[maybe_unused]] const bool use_striper) | |
365 | { | |
366 | #ifdef WITH_LIBRADOSSTRIPER | |
367 | if (use_striper) | |
368 | return striper().getxattrs(oid, attrset); | |
369 | #endif | |
370 | ||
371 | return io_ctx.getxattrs(oid, attrset); | |
372 | } | |
373 | ||
374 | int remove([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, const int flags, [[maybe_unused]] const bool use_striper) | |
375 | { | |
376 | #ifdef WITH_LIBRADOSSTRIPER | |
377 | if (use_striper) | |
378 | return striper().remove(oid, flags); | |
379 | #endif | |
380 | ||
381 | return io_ctx.remove(oid, flags); | |
382 | } | |
383 | ||
384 | int remove([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, [[maybe_unused]] const bool use_striper) | |
385 | { | |
386 | #ifdef WITH_LIBRADOSSTRIPER | |
387 | if (use_striper) | |
388 | return striper().remove(oid); | |
389 | #endif | |
390 | ||
391 | return io_ctx.remove(oid); | |
392 | } | |
393 | ||
394 | std::string get_oid(librados::NObjectIterator& i, [[maybe_unused]] const bool use_striper) | |
395 | { | |
396 | #ifdef WITH_LIBRADOSSTRIPER | |
397 | if (use_striper) | |
398 | return i->get_oid().substr(0, i->get_oid().length()-17); | |
399 | #endif | |
400 | ||
401 | return i->get_oid(); | |
402 | } | |
403 | ||
404 | int stat([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, uint64_t& size, time_t& mtime, [[maybe_unused]] const bool use_striper) | |
405 | { | |
406 | #ifdef WITH_LIBRADOSSTRIPER | |
407 | if (use_striper) | |
408 | return striper().stat(oid, &size, &mtime); | |
409 | #endif | |
410 | ||
411 | return io_ctx.stat(oid, &size, &mtime); | |
412 | } | |
413 | ||
414 | int stat2([[maybe_unused]] IoCtx& io_ctx, const std::string& oid, uint64_t& size, timespec& mtime, [[maybe_unused]] const bool use_striper) | |
415 | { | |
416 | #ifdef WITH_LIBRADOSSTRIPER | |
417 | if (use_striper) | |
418 | return striper().stat2(oid, &size, &mtime); | |
419 | #endif | |
420 | ||
421 | return io_ctx.stat2(oid, &size, &mtime); | |
422 | } | |
423 | ||
424 | void dump_name(Formatter *formatter, const librados::NObjectIterator& i, [[maybe_unused]] const bool use_striper) | |
425 | { | |
426 | #ifdef WITH_LIBRADOSSTRIPER | |
427 | if (use_striper) { | |
428 | formatter->dump_string("name", i->get_oid().substr(0, i->get_oid().length()-17)); | |
429 | return; | |
430 | } | |
431 | #endif | |
432 | ||
433 | formatter->dump_string("name", i->get_oid()); | |
434 | } | |
435 | ||
436 | } // namespace detail | |
437 | ||
7c673cae | 438 | unsigned default_op_size = 1 << 22; |
9f95a23c | 439 | static const unsigned MAX_OMAP_BYTES_PER_REQUEST = 1 << 10; |
7c673cae | 440 | |
11fdf7f2 | 441 | [[noreturn]] static void usage_exit() |
7c673cae FG |
442 | { |
443 | usage(cerr); | |
444 | exit(1); | |
445 | } | |
446 | ||
447 | ||
448 | template <typename I, typename T> | |
449 | static int rados_sistrtoll(I &i, T *val) { | |
450 | std::string err; | |
1adf2230 | 451 | *val = strict_iecstrtoll(i->second.c_str(), &err); |
7c673cae FG |
452 | if (err != "") { |
453 | cerr << "Invalid value for " << i->first << ": " << err << std::endl; | |
454 | return -EINVAL; | |
455 | } else { | |
456 | return 0; | |
457 | } | |
458 | } | |
459 | ||
460 | ||
461 | static int dump_data(std::string const &filename, bufferlist const &data) | |
462 | { | |
463 | int fd; | |
464 | if (filename == "-") { | |
465 | fd = STDOUT_FILENO; | |
466 | } else { | |
f67539c2 | 467 | fd = TEMP_FAILURE_RETRY(::open(filename.c_str(), O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)); |
7c673cae FG |
468 | if (fd < 0) { |
469 | int err = errno; | |
470 | cerr << "failed to open file: " << cpp_strerror(err) << std::endl; | |
471 | return -err; | |
472 | } | |
473 | } | |
474 | ||
475 | int r = data.write_fd(fd); | |
476 | ||
477 | if (fd != 1) { | |
478 | VOID_TEMP_FAILURE_RETRY(::close(fd)); | |
479 | } | |
480 | ||
481 | return r; | |
482 | } | |
483 | ||
484 | ||
f67539c2 | 485 | static int do_get(IoCtx& io_ctx, const std::string& oid, const char *outfile, unsigned op_size, [[maybe_unused]] const bool use_striper) |
7c673cae | 486 | { |
7c673cae FG |
487 | int fd; |
488 | if (strcmp(outfile, "-") == 0) { | |
489 | fd = STDOUT_FILENO; | |
490 | } else { | |
f67539c2 | 491 | fd = TEMP_FAILURE_RETRY(::open(outfile, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0644)); |
7c673cae FG |
492 | if (fd < 0) { |
493 | int err = errno; | |
494 | cerr << "failed to open file: " << cpp_strerror(err) << std::endl; | |
495 | return -err; | |
496 | } | |
497 | } | |
498 | ||
499 | uint64_t offset = 0; | |
500 | int ret; | |
501 | while (true) { | |
502 | bufferlist outdata; | |
11fdf7f2 TL |
503 | |
504 | ret = detail::read(io_ctx, oid, outdata, op_size, offset, use_striper); | |
7c673cae FG |
505 | if (ret <= 0) { |
506 | goto out; | |
507 | } | |
508 | ret = outdata.write_fd(fd); | |
509 | if (ret < 0) { | |
510 | cerr << "error writing to file: " << cpp_strerror(ret) << std::endl; | |
511 | goto out; | |
512 | } | |
513 | if (outdata.length() < op_size) | |
514 | break; | |
515 | offset += outdata.length(); | |
516 | } | |
517 | ret = 0; | |
518 | ||
519 | out: | |
520 | if (fd != 1) | |
521 | VOID_TEMP_FAILURE_RETRY(::close(fd)); | |
522 | return ret; | |
523 | } | |
524 | ||
525 | static int do_copy(IoCtx& io_ctx, const char *objname, | |
526 | IoCtx& target_ctx, const char *target_obj) | |
527 | { | |
9f95a23c TL |
528 | uint32_t src_fadvise_flags = LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL | LIBRADOS_OP_FLAG_FADVISE_NOCACHE; |
529 | uint32_t dest_fadvise_flags = LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL | LIBRADOS_OP_FLAG_FADVISE_DONTNEED; | |
7c673cae | 530 | ObjectWriteOperation op; |
11fdf7f2 | 531 | op.copy_from(objname, io_ctx, 0, src_fadvise_flags); |
7c673cae FG |
532 | op.set_op_flags2(dest_fadvise_flags); |
533 | ||
534 | return target_ctx.operate(target_obj, &op); | |
535 | } | |
536 | ||
537 | static int do_copy_pool(Rados& rados, const char *src_pool, const char *target_pool) | |
538 | { | |
539 | IoCtx src_ctx, target_ctx; | |
540 | int ret = rados.ioctx_create(src_pool, src_ctx); | |
541 | if (ret < 0) { | |
542 | cerr << "cannot open source pool: " << src_pool << std::endl; | |
543 | return ret; | |
544 | } | |
545 | ret = rados.ioctx_create(target_pool, target_ctx); | |
546 | if (ret < 0) { | |
547 | cerr << "cannot open target pool: " << target_pool << std::endl; | |
548 | return ret; | |
549 | } | |
550 | src_ctx.set_namespace(all_nspaces); | |
551 | librados::NObjectIterator i = src_ctx.nobjects_begin(); | |
552 | librados::NObjectIterator i_end = src_ctx.nobjects_end(); | |
553 | for (; i != i_end; ++i) { | |
554 | string nspace = i->get_nspace(); | |
555 | string oid = i->get_oid(); | |
556 | string locator = i->get_locator(); | |
557 | ||
558 | string target_name = (nspace.size() ? nspace + "/" : "") + oid; | |
559 | string src_name = target_name; | |
560 | if (locator.size()) | |
561 | src_name += "(@" + locator + ")"; | |
562 | cout << src_pool << ":" << src_name << " => " | |
563 | << target_pool << ":" << target_name << std::endl; | |
564 | ||
565 | src_ctx.locator_set_key(locator); | |
566 | src_ctx.set_namespace(nspace); | |
567 | target_ctx.set_namespace(nspace); | |
568 | ret = do_copy(src_ctx, oid.c_str(), target_ctx, oid.c_str()); | |
569 | if (ret < 0) { | |
570 | cerr << "error copying object: " << cpp_strerror(errno) << std::endl; | |
571 | return ret; | |
572 | } | |
573 | } | |
574 | ||
575 | return 0; | |
576 | } | |
577 | ||
11fdf7f2 | 578 | static int do_put(IoCtx& io_ctx, |
f67539c2 | 579 | const std::string& oid, const char *infile, int op_size, |
9f95a23c | 580 | uint64_t obj_offset, bool create_object, |
11fdf7f2 | 581 | const bool use_striper) |
7c673cae | 582 | { |
7c673cae FG |
583 | bool stdio = (strcmp(infile, "-") == 0); |
584 | int ret = 0; | |
585 | int fd = STDIN_FILENO; | |
586 | if (!stdio) | |
f67539c2 | 587 | fd = open(infile, O_RDONLY|O_BINARY); |
7c673cae FG |
588 | if (fd < 0) { |
589 | cerr << "error reading input file " << infile << ": " << cpp_strerror(errno) << std::endl; | |
590 | return 1; | |
591 | } | |
592 | int count = op_size; | |
593 | uint64_t offset = obj_offset; | |
594 | while (count != 0) { | |
595 | bufferlist indata; | |
596 | count = indata.read_fd(fd, op_size); | |
597 | if (count < 0) { | |
598 | ret = -errno; | |
599 | cerr << "error reading input file " << infile << ": " << cpp_strerror(ret) << std::endl; | |
600 | goto out; | |
601 | } | |
602 | ||
603 | if (count == 0) { | |
604 | if (offset == obj_offset) { // in case we have to create an empty object & if obj_offset > 0 do a hole | |
11fdf7f2 | 605 | ret = detail::write_full(io_ctx, oid, indata, use_striper); // indata is empty |
7c673cae | 606 | |
11fdf7f2 TL |
607 | if (ret < 0) { |
608 | goto out; | |
609 | } | |
610 | ||
611 | if (offset) { | |
612 | ret = detail::trunc(io_ctx, oid, offset, use_striper); // before truncate, object must be existed. | |
613 | ||
614 | if (ret < 0) { | |
615 | goto out; | |
616 | } | |
617 | } | |
7c673cae | 618 | } |
11fdf7f2 | 619 | continue; |
7c673cae FG |
620 | } |
621 | ||
9f95a23c | 622 | if (0 == offset && create_object) |
11fdf7f2 TL |
623 | ret = detail::write_full(io_ctx, oid, indata, use_striper); |
624 | else | |
625 | ret = detail::write(io_ctx, oid, indata, count, offset, use_striper); | |
626 | ||
7c673cae FG |
627 | if (ret < 0) { |
628 | goto out; | |
629 | } | |
630 | offset += count; | |
631 | } | |
632 | ret = 0; | |
633 | out: | |
634 | if (fd != STDOUT_FILENO) | |
635 | VOID_TEMP_FAILURE_RETRY(close(fd)); | |
636 | return ret; | |
637 | } | |
638 | ||
11fdf7f2 | 639 | static int do_append(IoCtx& io_ctx, |
f67539c2 | 640 | const std::string& oid, const char *infile, int op_size, |
11fdf7f2 | 641 | const bool use_striper) |
7c673cae | 642 | { |
7c673cae FG |
643 | bool stdio = (strcmp(infile, "-") == 0); |
644 | int ret = 0; | |
645 | int fd = STDIN_FILENO; | |
646 | if (!stdio) | |
f67539c2 | 647 | fd = open(infile, O_RDONLY|O_BINARY); |
7c673cae FG |
648 | if (fd < 0) { |
649 | cerr << "error reading input file " << infile << ": " << cpp_strerror(errno) << std::endl; | |
650 | return 1; | |
651 | } | |
652 | int count = op_size; | |
653 | while (count != 0) { | |
654 | bufferlist indata; | |
655 | count = indata.read_fd(fd, op_size); | |
656 | if (count < 0) { | |
657 | ret = -errno; | |
658 | cerr << "error reading input file " << infile << ": " << cpp_strerror(ret) << std::endl; | |
659 | goto out; | |
660 | } | |
11fdf7f2 | 661 | ret = detail::append(io_ctx, oid, indata, count, use_striper); |
7c673cae FG |
662 | |
663 | if (ret < 0) { | |
664 | goto out; | |
665 | } | |
666 | } | |
667 | ret = 0; | |
668 | out: | |
669 | if (fd != STDOUT_FILENO) | |
670 | VOID_TEMP_FAILURE_RETRY(close(fd)); | |
671 | return ret; | |
672 | } | |
673 | ||
674 | class RadosWatchCtx : public librados::WatchCtx2 { | |
675 | IoCtx& ioctx; | |
676 | string name; | |
677 | public: | |
678 | RadosWatchCtx(IoCtx& io, const char *imgname) : ioctx(io), name(imgname) {} | |
679 | ~RadosWatchCtx() override {} | |
680 | void handle_notify(uint64_t notify_id, | |
681 | uint64_t cookie, | |
682 | uint64_t notifier_id, | |
683 | bufferlist& bl) override { | |
684 | cout << "NOTIFY" | |
685 | << " cookie " << cookie | |
686 | << " notify_id " << notify_id | |
687 | << " from " << notifier_id | |
688 | << std::endl; | |
689 | bl.hexdump(cout); | |
690 | ioctx.notify_ack(name, notify_id, cookie, bl); | |
691 | } | |
692 | void handle_error(uint64_t cookie, int err) override { | |
693 | cout << "ERROR" | |
694 | << " cookie " << cookie | |
695 | << " err " << cpp_strerror(err) | |
696 | << std::endl; | |
697 | } | |
698 | }; | |
699 | ||
700 | static const char alphanum_table[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; | |
701 | ||
11fdf7f2 | 702 | void gen_rand_alphanumeric(char *dest, int size) /* size should be the required string size + 1 */ |
7c673cae | 703 | { |
11fdf7f2 | 704 | const int max = sizeof(alphanum_table) - 2; |
7c673cae FG |
705 | |
706 | int i; | |
707 | for (i=0; i<size - 1; i++) { | |
11fdf7f2 TL |
708 | int pos = generate_random_number(0, max); |
709 | dest[i] = alphanum_table[pos]; | |
7c673cae FG |
710 | } |
711 | dest[i] = '\0'; | |
7c673cae FG |
712 | } |
713 | ||
714 | struct obj_info { | |
715 | string name; | |
716 | size_t len; | |
717 | }; | |
718 | ||
719 | class LoadGen { | |
720 | size_t total_sent; | |
721 | size_t total_completed; | |
722 | ||
723 | IoCtx io_ctx; | |
724 | Rados *rados; | |
725 | ||
726 | map<int, obj_info> objs; | |
727 | ||
728 | utime_t start_time; | |
729 | ||
730 | bool going_down; | |
731 | ||
732 | public: | |
733 | int read_percent; | |
734 | int num_objs; | |
735 | size_t min_obj_len; | |
11fdf7f2 | 736 | size_t max_obj_len; |
7c673cae FG |
737 | size_t min_op_len; |
738 | size_t max_op_len; | |
739 | size_t max_ops; | |
740 | size_t max_backlog; | |
741 | size_t target_throughput; | |
11fdf7f2 | 742 | size_t offset_align = 0; |
7c673cae FG |
743 | int run_length; |
744 | ||
745 | enum { | |
746 | OP_READ, | |
747 | OP_WRITE, | |
748 | }; | |
749 | ||
750 | struct LoadGenOp { | |
751 | int id; | |
752 | int type; | |
753 | string oid; | |
754 | size_t off; | |
755 | size_t len; | |
756 | bufferlist bl; | |
757 | LoadGen *lg; | |
758 | librados::AioCompletion *completion; | |
759 | ||
760 | LoadGenOp() : id(0), type(0), off(0), len(0), lg(NULL), completion(NULL) {} | |
761 | explicit LoadGenOp(LoadGen *_lg) : id(0), type(0), off(0), len(0), lg(_lg), completion(NULL) {} | |
762 | }; | |
763 | ||
764 | int max_op; | |
765 | ||
766 | map<int, LoadGenOp *> pending_ops; | |
767 | ||
768 | void gen_op(LoadGenOp *op); | |
769 | uint64_t gen_next_op(); | |
770 | void run_op(LoadGenOp *op); | |
771 | ||
772 | uint64_t cur_sent_rate() { | |
773 | return total_sent / time_passed(); | |
774 | } | |
775 | ||
776 | uint64_t cur_completed_rate() { | |
777 | return total_completed / time_passed(); | |
778 | } | |
779 | ||
780 | uint64_t total_expected() { | |
781 | return target_throughput * time_passed(); | |
782 | } | |
783 | ||
784 | float time_passed() { | |
785 | utime_t now = ceph_clock_now(); | |
786 | now -= start_time; | |
787 | uint64_t ns = now.nsec(); | |
788 | float total = (float) ns / 1000000000.0; | |
789 | total += now.sec(); | |
790 | return total; | |
791 | } | |
792 | ||
9f95a23c TL |
793 | ceph::mutex lock = ceph::make_mutex("LoadGen"); |
794 | ceph::condition_variable cond; | |
7c673cae | 795 | |
9f95a23c | 796 | explicit LoadGen(Rados *_rados) : rados(_rados), going_down(false) { |
7c673cae FG |
797 | read_percent = 80; |
798 | min_obj_len = 1024; | |
799 | max_obj_len = 5ull * 1024ull * 1024ull * 1024ull; | |
800 | min_op_len = 1024; | |
801 | target_throughput = 5 * 1024 * 1024; // B/sec | |
802 | max_op_len = 2 * 1024 * 1024; | |
803 | max_ops = 16; | |
804 | max_backlog = target_throughput * 2; | |
805 | run_length = 60; | |
806 | ||
807 | total_sent = 0; | |
808 | total_completed = 0; | |
809 | num_objs = 200; | |
810 | max_op = 0; | |
811 | } | |
812 | int bootstrap(const char *pool); | |
813 | int run(); | |
814 | void cleanup(); | |
815 | ||
816 | void io_cb(completion_t c, LoadGenOp *op) { | |
9f95a23c | 817 | std::lock_guard l{lock}; |
7c673cae FG |
818 | |
819 | total_completed += op->len; | |
820 | ||
821 | double rate = (double)cur_completed_rate() / (1024 * 1024); | |
822 | std::streamsize original_precision = cout.precision(); | |
823 | cout.precision(3); | |
824 | cout << "op " << op->id << " completed, throughput=" << rate << "MB/sec" << std::endl; | |
825 | cout.precision(original_precision); | |
826 | ||
827 | map<int, LoadGenOp *>::iterator iter = pending_ops.find(op->id); | |
828 | if (iter != pending_ops.end()) | |
829 | pending_ops.erase(iter); | |
830 | ||
831 | if (!going_down) | |
832 | op->completion->release(); | |
833 | ||
834 | delete op; | |
835 | ||
9f95a23c | 836 | cond.notify_all(); |
7c673cae FG |
837 | } |
838 | }; | |
839 | ||
840 | static void _load_gen_cb(completion_t c, void *param) | |
841 | { | |
842 | LoadGen::LoadGenOp *op = (LoadGen::LoadGenOp *)param; | |
843 | op->lg->io_cb(c, op); | |
844 | } | |
845 | ||
846 | int LoadGen::bootstrap(const char *pool) | |
847 | { | |
848 | char buf[128]; | |
849 | int i; | |
850 | ||
851 | if (!pool) { | |
852 | cerr << "ERROR: pool name was not specified" << std::endl; | |
853 | return -EINVAL; | |
854 | } | |
855 | ||
856 | int ret = rados->ioctx_create(pool, io_ctx); | |
857 | if (ret < 0) { | |
858 | cerr << "error opening pool " << pool << ": " << cpp_strerror(ret) << std::endl; | |
859 | return ret; | |
860 | } | |
861 | ||
862 | int buf_len = 1; | |
863 | bufferptr p = buffer::create(buf_len); | |
864 | bufferlist bl; | |
865 | memset(p.c_str(), 0, buf_len); | |
866 | bl.push_back(p); | |
867 | ||
868 | list<librados::AioCompletion *> completions; | |
869 | for (i = 0; i < num_objs; i++) { | |
870 | obj_info info; | |
871 | gen_rand_alphanumeric(buf, 16); | |
872 | info.name = "obj-"; | |
873 | info.name.append(buf); | |
11fdf7f2 | 874 | info.len = generate_random_number(min_obj_len, max_obj_len); |
7c673cae FG |
875 | |
876 | // throttle... | |
877 | while (completions.size() > max_ops) { | |
878 | AioCompletion *c = completions.front(); | |
879 | c->wait_for_complete(); | |
880 | ret = c->get_return_value(); | |
881 | c->release(); | |
882 | completions.pop_front(); | |
883 | if (ret < 0) { | |
884 | cerr << "aio_write failed" << std::endl; | |
885 | return ret; | |
886 | } | |
887 | } | |
888 | ||
9f95a23c | 889 | librados::AioCompletion *c = rados->aio_create_completion(nullptr, nullptr); |
7c673cae FG |
890 | completions.push_back(c); |
891 | // generate object | |
892 | ret = io_ctx.aio_write(info.name, c, bl, buf_len, info.len - buf_len); | |
893 | if (ret < 0) { | |
894 | cerr << "couldn't write obj: " << info.name << " ret=" << ret << std::endl; | |
895 | return ret; | |
896 | } | |
897 | objs[i] = info; | |
898 | } | |
899 | ||
900 | list<librados::AioCompletion *>::iterator iter; | |
901 | for (iter = completions.begin(); iter != completions.end(); ++iter) { | |
902 | AioCompletion *c = *iter; | |
903 | c->wait_for_complete(); | |
904 | ret = c->get_return_value(); | |
905 | c->release(); | |
906 | if (ret < 0) { // yes, we leak. | |
907 | cerr << "aio_write failed" << std::endl; | |
908 | return ret; | |
909 | } | |
910 | } | |
911 | return 0; | |
912 | } | |
913 | ||
914 | void LoadGen::run_op(LoadGenOp *op) | |
915 | { | |
9f95a23c | 916 | op->completion = rados->aio_create_completion(op, _load_gen_cb); |
7c673cae FG |
917 | |
918 | switch (op->type) { | |
919 | case OP_READ: | |
920 | io_ctx.aio_read(op->oid, op->completion, &op->bl, op->len, op->off); | |
921 | break; | |
922 | case OP_WRITE: | |
923 | bufferptr p = buffer::create(op->len); | |
924 | memset(p.c_str(), 0, op->len); | |
925 | op->bl.push_back(p); | |
926 | ||
927 | io_ctx.aio_write(op->oid, op->completion, op->bl, op->len, op->off); | |
928 | break; | |
929 | } | |
930 | ||
931 | total_sent += op->len; | |
932 | } | |
933 | ||
934 | void LoadGen::gen_op(LoadGenOp *op) | |
935 | { | |
11fdf7f2 | 936 | int i = generate_random_number<int>(0, objs.size() - 1); |
7c673cae FG |
937 | obj_info& info = objs[i]; |
938 | op->oid = info.name; | |
939 | ||
11fdf7f2 | 940 | size_t len = generate_random_number(min_op_len, max_op_len); |
7c673cae FG |
941 | if (len > info.len) |
942 | len = info.len; | |
11fdf7f2 | 943 | size_t off = generate_random_number<size_t>(0, info.len); |
7c673cae FG |
944 | |
945 | if (off + len > info.len) | |
946 | off = info.len - len; | |
947 | ||
11fdf7f2 TL |
948 | if (offset_align) |
949 | off = p2align(off, offset_align); | |
950 | ||
7c673cae FG |
951 | op->off = off; |
952 | op->len = len; | |
953 | ||
11fdf7f2 | 954 | i = generate_random_number(1, 100); |
7c673cae FG |
955 | if (i > read_percent) |
956 | op->type = OP_WRITE; | |
957 | else | |
958 | op->type = OP_READ; | |
959 | ||
960 | cout << (op->type == OP_READ ? "READ" : "WRITE") << " : oid=" << op->oid << " off=" << op->off << " len=" << op->len << std::endl; | |
961 | } | |
962 | ||
963 | uint64_t LoadGen::gen_next_op() | |
964 | { | |
9f95a23c | 965 | lock.lock(); |
7c673cae FG |
966 | |
967 | LoadGenOp *op = new LoadGenOp(this); | |
968 | gen_op(op); | |
969 | op->id = max_op++; | |
970 | pending_ops[op->id] = op; | |
971 | ||
9f95a23c | 972 | lock.unlock(); |
7c673cae FG |
973 | |
974 | run_op(op); | |
975 | ||
976 | return op->len; | |
977 | } | |
978 | ||
979 | int LoadGen::run() | |
980 | { | |
981 | start_time = ceph_clock_now(); | |
982 | utime_t end_time = start_time; | |
983 | end_time += run_length; | |
984 | utime_t stamp_time = start_time; | |
985 | uint32_t total_sec = 0; | |
986 | ||
987 | while (1) { | |
9f95a23c TL |
988 | { |
989 | std::unique_lock l{lock}; | |
990 | cond.wait_for(l, 1s); | |
991 | } | |
7c673cae FG |
992 | utime_t now = ceph_clock_now(); |
993 | ||
994 | if (now > end_time) | |
995 | break; | |
996 | ||
997 | uint64_t expected = total_expected(); | |
9f95a23c | 998 | lock.lock(); |
7c673cae FG |
999 | uint64_t sent = total_sent; |
1000 | uint64_t completed = total_completed; | |
9f95a23c | 1001 | lock.unlock(); |
7c673cae FG |
1002 | |
1003 | if (now - stamp_time >= utime_t(1, 0)) { | |
1004 | double rate = (double)cur_completed_rate() / (1024 * 1024); | |
1005 | ++total_sec; | |
1006 | std::streamsize original_precision = cout.precision(); | |
1007 | cout.precision(3); | |
20effc67 | 1008 | cout << std::setw(5) << total_sec << ": throughput=" << rate << "MB/sec" << " pending data=" << sent - completed << std::endl; |
7c673cae FG |
1009 | cout.precision(original_precision); |
1010 | stamp_time = now; | |
1011 | } | |
1012 | ||
1013 | while (sent < expected && | |
1014 | sent - completed < max_backlog && | |
1015 | pending_ops.size() < max_ops) { | |
1016 | sent += gen_next_op(); | |
1017 | } | |
1018 | } | |
1019 | ||
1020 | // get a reference to all pending requests | |
1021 | vector<librados::AioCompletion *> completions; | |
9f95a23c | 1022 | lock.lock(); |
7c673cae FG |
1023 | going_down = true; |
1024 | map<int, LoadGenOp *>::iterator iter; | |
1025 | for (iter = pending_ops.begin(); iter != pending_ops.end(); ++iter) { | |
1026 | LoadGenOp *op = iter->second; | |
1027 | completions.push_back(op->completion); | |
1028 | } | |
9f95a23c | 1029 | lock.unlock(); |
7c673cae FG |
1030 | |
1031 | cout << "waiting for all operations to complete" << std::endl; | |
1032 | ||
1033 | // now wait on all the pending requests | |
1034 | for (vector<librados::AioCompletion *>::iterator citer = completions.begin(); citer != completions.end(); ++citer) { | |
1035 | librados::AioCompletion *c = *citer; | |
1036 | c->wait_for_complete(); | |
1037 | c->release(); | |
1038 | } | |
1039 | ||
1040 | return 0; | |
1041 | } | |
1042 | ||
1043 | void LoadGen::cleanup() | |
1044 | { | |
1045 | cout << "cleaning up objects" << std::endl; | |
1046 | map<int, obj_info>::iterator iter; | |
1047 | for (iter = objs.begin(); iter != objs.end(); ++iter) { | |
1048 | obj_info& info = iter->second; | |
1049 | int ret = io_ctx.remove(info.name); | |
1050 | if (ret < 0) | |
1051 | cerr << "couldn't remove obj: " << info.name << " ret=" << ret << std::endl; | |
1052 | } | |
1053 | } | |
1054 | ||
1055 | enum OpWriteDest { | |
1056 | OP_WRITE_DEST_OBJ = 2 << 0, | |
1057 | OP_WRITE_DEST_OMAP = 2 << 1, | |
1058 | OP_WRITE_DEST_XATTR = 2 << 2, | |
1059 | }; | |
1060 | ||
1061 | class RadosBencher : public ObjBencher { | |
1062 | librados::AioCompletion **completions; | |
1063 | librados::Rados& rados; | |
1064 | librados::IoCtx& io_ctx; | |
1065 | librados::NObjectIterator oi; | |
1066 | bool iterator_valid; | |
1067 | OpWriteDest write_destination; | |
1068 | ||
1069 | protected: | |
1070 | int completions_init(int concurrentios) override { | |
1071 | completions = new librados::AioCompletion *[concurrentios]; | |
1072 | return 0; | |
1073 | } | |
1074 | void completions_done() override { | |
1075 | delete[] completions; | |
1076 | completions = NULL; | |
1077 | } | |
1078 | int create_completion(int slot, void (*cb)(void *, void*), void *arg) override { | |
9f95a23c | 1079 | completions[slot] = rados.aio_create_completion((void *) arg, cb); |
7c673cae FG |
1080 | |
1081 | if (!completions[slot]) | |
1082 | return -EINVAL; | |
1083 | ||
1084 | return 0; | |
1085 | } | |
1086 | void release_completion(int slot) override { | |
1087 | completions[slot]->release(); | |
1088 | completions[slot] = 0; | |
1089 | } | |
1090 | ||
1091 | int aio_read(const std::string& oid, int slot, bufferlist *pbl, size_t len, | |
1092 | size_t offset) override { | |
11fdf7f2 | 1093 | return io_ctx.aio_read(oid, completions[slot], pbl, len, offset); |
7c673cae FG |
1094 | } |
1095 | ||
1096 | int aio_write(const std::string& oid, int slot, bufferlist& bl, size_t len, | |
1097 | size_t offset) override { | |
1098 | librados::ObjectWriteOperation op; | |
1099 | ||
1100 | if (write_destination & OP_WRITE_DEST_OBJ) { | |
1101 | if (data.hints) | |
1102 | op.set_alloc_hint2(data.object_size, data.op_size, | |
1103 | ALLOC_HINT_FLAG_SEQUENTIAL_WRITE | | |
1104 | ALLOC_HINT_FLAG_SEQUENTIAL_READ | | |
1105 | ALLOC_HINT_FLAG_APPEND_ONLY | | |
1106 | ALLOC_HINT_FLAG_IMMUTABLE); | |
1107 | op.write(offset, bl); | |
1108 | } | |
1109 | ||
1110 | if (write_destination & OP_WRITE_DEST_OMAP) { | |
1111 | std::map<std::string, librados::bufferlist> omap; | |
1112 | omap[string("bench-omap-key-") + stringify(offset)] = bl; | |
1113 | op.omap_set(omap); | |
1114 | } | |
1115 | ||
1116 | if (write_destination & OP_WRITE_DEST_XATTR) { | |
1117 | char key[80]; | |
1118 | snprintf(key, sizeof(key), "bench-xattr-key-%d", (int)offset); | |
1119 | op.setxattr(key, bl); | |
1120 | } | |
1121 | ||
1122 | return io_ctx.aio_operate(oid, completions[slot], &op); | |
1123 | } | |
1124 | ||
1125 | int aio_remove(const std::string& oid, int slot) override { | |
1126 | return io_ctx.aio_remove(oid, completions[slot]); | |
1127 | } | |
1128 | ||
1129 | int sync_read(const std::string& oid, bufferlist& bl, size_t len) override { | |
1130 | return io_ctx.read(oid, bl, len, 0); | |
1131 | } | |
1132 | int sync_write(const std::string& oid, bufferlist& bl, size_t len) override { | |
1133 | return io_ctx.write_full(oid, bl); | |
1134 | } | |
1135 | ||
1136 | int sync_remove(const std::string& oid) override { | |
1137 | return io_ctx.remove(oid); | |
1138 | } | |
1139 | ||
1140 | bool completion_is_done(int slot) override { | |
9f95a23c | 1141 | return completions[slot] && completions[slot]->is_complete(); |
7c673cae FG |
1142 | } |
1143 | ||
1144 | int completion_wait(int slot) override { | |
9f95a23c | 1145 | return completions[slot]->wait_for_complete_and_cb(); |
7c673cae FG |
1146 | } |
1147 | int completion_ret(int slot) override { | |
1148 | return completions[slot]->get_return_value(); | |
1149 | } | |
1150 | ||
1151 | bool get_objects(std::list<Object>* objects, int num) override { | |
1152 | int count = 0; | |
1153 | ||
1154 | if (!iterator_valid) { | |
1155 | oi = io_ctx.nobjects_begin(); | |
1156 | iterator_valid = true; | |
1157 | } | |
1158 | ||
1159 | librados::NObjectIterator ei = io_ctx.nobjects_end(); | |
1160 | ||
1161 | if (oi == ei) { | |
1162 | iterator_valid = false; | |
1163 | return false; | |
1164 | } | |
1165 | ||
1166 | objects->clear(); | |
1167 | for ( ; oi != ei && count < num; ++oi) { | |
1168 | Object obj(oi->get_oid(), oi->get_nspace()); | |
1169 | objects->push_back(obj); | |
1170 | ++count; | |
1171 | } | |
1172 | ||
1173 | return true; | |
1174 | } | |
1175 | ||
1176 | void set_namespace( const std::string& ns) override { | |
1177 | io_ctx.set_namespace(ns); | |
1178 | } | |
1179 | ||
1180 | public: | |
1181 | RadosBencher(CephContext *cct_, librados::Rados& _r, librados::IoCtx& _i) | |
1182 | : ObjBencher(cct_), completions(NULL), rados(_r), io_ctx(_i), iterator_valid(false), write_destination(OP_WRITE_DEST_OBJ) {} | |
1183 | ~RadosBencher() override { } | |
1184 | ||
1185 | void set_write_destination(OpWriteDest dest) { | |
1186 | write_destination = dest; | |
1187 | } | |
1188 | }; | |
1189 | ||
1190 | static int do_lock_cmd(std::vector<const char*> &nargs, | |
1191 | const std::map < std::string, std::string > &opts, | |
1192 | IoCtx *ioctx, | |
1193 | Formatter *formatter) | |
1194 | { | |
1195 | if (nargs.size() < 3) | |
1196 | usage_exit(); | |
1197 | ||
1198 | string cmd(nargs[1]); | |
1199 | string oid(nargs[2]); | |
1200 | ||
1201 | string lock_tag; | |
1202 | string lock_cookie; | |
1203 | string lock_description; | |
1204 | int lock_duration = 0; | |
f67539c2 | 1205 | ClsLockType lock_type = ClsLockType::EXCLUSIVE; |
7c673cae FG |
1206 | |
1207 | map<string, string>::const_iterator i; | |
1208 | i = opts.find("lock-tag"); | |
1209 | if (i != opts.end()) { | |
1210 | lock_tag = i->second; | |
1211 | } | |
1212 | i = opts.find("lock-cookie"); | |
1213 | if (i != opts.end()) { | |
1214 | lock_cookie = i->second; | |
1215 | } | |
1216 | i = opts.find("lock-description"); | |
1217 | if (i != opts.end()) { | |
1218 | lock_description = i->second; | |
1219 | } | |
1220 | i = opts.find("lock-duration"); | |
1221 | if (i != opts.end()) { | |
1222 | if (rados_sistrtoll(i, &lock_duration)) { | |
1223 | return -EINVAL; | |
1224 | } | |
1225 | } | |
1226 | i = opts.find("lock-type"); | |
1227 | if (i != opts.end()) { | |
1228 | const string& type_str = i->second; | |
1229 | if (type_str.compare("exclusive") == 0) { | |
f67539c2 | 1230 | lock_type = ClsLockType::EXCLUSIVE; |
7c673cae | 1231 | } else if (type_str.compare("shared") == 0) { |
f67539c2 | 1232 | lock_type = ClsLockType::SHARED; |
7c673cae FG |
1233 | } else { |
1234 | cerr << "unknown lock type was specified, aborting" << std::endl; | |
1235 | return -EINVAL; | |
1236 | } | |
1237 | } | |
1238 | ||
1239 | if (cmd.compare("list") == 0) { | |
1240 | list<string> locks; | |
1241 | int ret = rados::cls::lock::list_locks(ioctx, oid, &locks); | |
1242 | if (ret < 0) { | |
1243 | cerr << "ERROR: rados_list_locks(): " << cpp_strerror(ret) << std::endl; | |
1244 | return ret; | |
1245 | } | |
1246 | ||
1247 | formatter->open_object_section("object"); | |
1248 | formatter->dump_string("objname", oid); | |
1249 | formatter->open_array_section("locks"); | |
1250 | list<string>::iterator iter; | |
1251 | for (iter = locks.begin(); iter != locks.end(); ++iter) { | |
1252 | formatter->open_object_section("lock"); | |
1253 | formatter->dump_string("name", *iter); | |
1254 | formatter->close_section(); | |
1255 | } | |
1256 | formatter->close_section(); | |
1257 | formatter->close_section(); | |
1258 | formatter->flush(cout); | |
1259 | return 0; | |
1260 | } | |
1261 | ||
1262 | if (nargs.size() < 4) | |
1263 | usage_exit(); | |
1264 | ||
1265 | string lock_name(nargs[3]); | |
1266 | ||
1267 | if (cmd.compare("info") == 0) { | |
1268 | map<rados::cls::lock::locker_id_t, rados::cls::lock::locker_info_t> lockers; | |
f67539c2 | 1269 | ClsLockType type = ClsLockType::NONE; |
7c673cae FG |
1270 | string tag; |
1271 | int ret = rados::cls::lock::get_lock_info(ioctx, oid, lock_name, &lockers, &type, &tag); | |
1272 | if (ret < 0) { | |
1273 | cerr << "ERROR: rados_lock_get_lock_info(): " << cpp_strerror(ret) << std::endl; | |
1274 | return ret; | |
1275 | } | |
1276 | ||
1277 | formatter->open_object_section("lock"); | |
1278 | formatter->dump_string("name", lock_name); | |
1279 | formatter->dump_string("type", cls_lock_type_str(type)); | |
1280 | formatter->dump_string("tag", tag); | |
1281 | formatter->open_array_section("lockers"); | |
1282 | map<rados::cls::lock::locker_id_t, rados::cls::lock::locker_info_t>::iterator iter; | |
1283 | for (iter = lockers.begin(); iter != lockers.end(); ++iter) { | |
1284 | const rados::cls::lock::locker_id_t& id = iter->first; | |
1285 | const rados::cls::lock::locker_info_t& info = iter->second; | |
1286 | formatter->open_object_section("locker"); | |
1287 | formatter->dump_stream("name") << id.locker; | |
1288 | formatter->dump_string("cookie", id.cookie); | |
1289 | formatter->dump_string("description", info.description); | |
1290 | formatter->dump_stream("expiration") << info.expiration; | |
11fdf7f2 | 1291 | formatter->dump_stream("addr") << info.addr.get_legacy_str(); |
7c673cae FG |
1292 | formatter->close_section(); |
1293 | } | |
1294 | formatter->close_section(); | |
1295 | formatter->close_section(); | |
1296 | formatter->flush(cout); | |
1297 | ||
1298 | return ret; | |
1299 | } else if (cmd.compare("get") == 0) { | |
1300 | rados::cls::lock::Lock l(lock_name); | |
1301 | l.set_cookie(lock_cookie); | |
1302 | l.set_tag(lock_tag); | |
1303 | l.set_duration(utime_t(lock_duration, 0)); | |
1304 | l.set_description(lock_description); | |
1305 | int ret; | |
1306 | switch (lock_type) { | |
f67539c2 | 1307 | case ClsLockType::SHARED: |
7c673cae FG |
1308 | ret = l.lock_shared(ioctx, oid); |
1309 | break; | |
1310 | default: | |
1311 | ret = l.lock_exclusive(ioctx, oid); | |
1312 | } | |
1313 | if (ret < 0) { | |
1314 | cerr << "ERROR: failed locking: " << cpp_strerror(ret) << std::endl; | |
1315 | return ret; | |
1316 | } | |
1317 | ||
1318 | return ret; | |
1319 | } | |
1320 | ||
1321 | if (nargs.size() < 5) | |
1322 | usage_exit(); | |
1323 | ||
1324 | if (cmd.compare("break") == 0) { | |
20effc67 | 1325 | const char* locker = nargs[4]; |
7c673cae FG |
1326 | rados::cls::lock::Lock l(lock_name); |
1327 | l.set_cookie(lock_cookie); | |
1328 | l.set_tag(lock_tag); | |
1329 | entity_name_t name; | |
1330 | if (!name.parse(locker)) { | |
1331 | cerr << "ERROR: failed to parse locker name (" << locker << ")" << std::endl; | |
1332 | return -EINVAL; | |
1333 | } | |
1334 | int ret = l.break_lock(ioctx, oid, name); | |
1335 | if (ret < 0) { | |
1336 | cerr << "ERROR: failed breaking lock: " << cpp_strerror(ret) << std::endl; | |
1337 | return ret; | |
1338 | } | |
1339 | } else { | |
1340 | usage_exit(); | |
1341 | } | |
1342 | ||
1343 | return 0; | |
1344 | } | |
1345 | ||
1346 | static int do_cache_flush(IoCtx& io_ctx, string oid) | |
1347 | { | |
1348 | ObjectReadOperation op; | |
1349 | op.cache_flush(); | |
1350 | librados::AioCompletion *completion = | |
1351 | librados::Rados::aio_create_completion(); | |
1352 | io_ctx.aio_operate(oid.c_str(), completion, &op, | |
1353 | librados::OPERATION_IGNORE_CACHE | | |
1354 | librados::OPERATION_IGNORE_OVERLAY, | |
1355 | NULL); | |
9f95a23c | 1356 | completion->wait_for_complete(); |
7c673cae FG |
1357 | int r = completion->get_return_value(); |
1358 | completion->release(); | |
1359 | return r; | |
1360 | } | |
1361 | ||
1362 | static int do_cache_try_flush(IoCtx& io_ctx, string oid) | |
1363 | { | |
1364 | ObjectReadOperation op; | |
1365 | op.cache_try_flush(); | |
1366 | librados::AioCompletion *completion = | |
1367 | librados::Rados::aio_create_completion(); | |
1368 | io_ctx.aio_operate(oid.c_str(), completion, &op, | |
1369 | librados::OPERATION_IGNORE_CACHE | | |
1370 | librados::OPERATION_IGNORE_OVERLAY | | |
1371 | librados::OPERATION_SKIPRWLOCKS, | |
1372 | NULL); | |
9f95a23c | 1373 | completion->wait_for_complete(); |
7c673cae FG |
1374 | int r = completion->get_return_value(); |
1375 | completion->release(); | |
1376 | return r; | |
1377 | } | |
1378 | ||
1379 | static int do_cache_evict(IoCtx& io_ctx, string oid) | |
1380 | { | |
1381 | ObjectReadOperation op; | |
1382 | op.cache_evict(); | |
1383 | librados::AioCompletion *completion = | |
1384 | librados::Rados::aio_create_completion(); | |
1385 | io_ctx.aio_operate(oid.c_str(), completion, &op, | |
1386 | librados::OPERATION_IGNORE_CACHE | | |
1387 | librados::OPERATION_IGNORE_OVERLAY | | |
1388 | librados::OPERATION_SKIPRWLOCKS, | |
1389 | NULL); | |
9f95a23c | 1390 | completion->wait_for_complete(); |
7c673cae FG |
1391 | int r = completion->get_return_value(); |
1392 | completion->release(); | |
1393 | return r; | |
1394 | } | |
1395 | ||
1396 | static int do_cache_flush_evict_all(IoCtx& io_ctx, bool blocking) | |
1397 | { | |
1398 | int errors = 0; | |
1399 | io_ctx.set_namespace(all_nspaces); | |
1400 | try { | |
1401 | librados::NObjectIterator i = io_ctx.nobjects_begin(); | |
1402 | librados::NObjectIterator i_end = io_ctx.nobjects_end(); | |
1403 | for (; i != i_end; ++i) { | |
1404 | int r; | |
1405 | cout << i->get_nspace() << "\t" << i->get_oid() << "\t" << i->get_locator() << std::endl; | |
1406 | if (i->get_locator().size()) { | |
1407 | io_ctx.locator_set_key(i->get_locator()); | |
1408 | } else { | |
1409 | io_ctx.locator_set_key(string()); | |
1410 | } | |
1411 | io_ctx.set_namespace(i->get_nspace()); | |
1412 | snap_set_t ls; | |
1413 | io_ctx.snap_set_read(LIBRADOS_SNAP_DIR); | |
1414 | r = io_ctx.list_snaps(i->get_oid(), &ls); | |
1415 | if (r < 0) { | |
1416 | cerr << "error listing snap shots " << i->get_nspace() << "/" << i->get_oid() << ": " | |
1417 | << cpp_strerror(r) << std::endl; | |
1418 | ++errors; | |
1419 | continue; | |
1420 | } | |
1421 | std::vector<clone_info_t>::iterator ci = ls.clones.begin(); | |
1422 | // no snapshots | |
1423 | if (ci == ls.clones.end()) { | |
1424 | io_ctx.snap_set_read(CEPH_NOSNAP); | |
1425 | if (blocking) | |
1426 | r = do_cache_flush(io_ctx, i->get_oid()); | |
1427 | else | |
1428 | r = do_cache_try_flush(io_ctx, i->get_oid()); | |
1429 | if (r < 0) { | |
1430 | cerr << "failed to flush " << i->get_nspace() << "/" << i->get_oid() << ": " | |
1431 | << cpp_strerror(r) << std::endl; | |
1432 | ++errors; | |
1433 | continue; | |
1434 | } | |
1435 | r = do_cache_evict(io_ctx, i->get_oid()); | |
1436 | if (r < 0) { | |
1437 | cerr << "failed to evict " << i->get_nspace() << "/" << i->get_oid() << ": " | |
1438 | << cpp_strerror(r) << std::endl; | |
1439 | ++errors; | |
1440 | continue; | |
1441 | } | |
1442 | } else { | |
1443 | // has snapshots | |
1444 | for (std::vector<clone_info_t>::iterator ci = ls.clones.begin(); | |
1445 | ci != ls.clones.end(); ++ci) { | |
1446 | io_ctx.snap_set_read(ci->cloneid); | |
1447 | if (blocking) | |
1448 | r = do_cache_flush(io_ctx, i->get_oid()); | |
1449 | else | |
1450 | r = do_cache_try_flush(io_ctx, i->get_oid()); | |
1451 | if (r < 0) { | |
1452 | cerr << "failed to flush " << i->get_nspace() << "/" << i->get_oid() << ": " | |
1453 | << cpp_strerror(r) << std::endl; | |
1454 | ++errors; | |
1455 | break; | |
1456 | } | |
1457 | r = do_cache_evict(io_ctx, i->get_oid()); | |
1458 | if (r < 0) { | |
1459 | cerr << "failed to evict " << i->get_nspace() << "/" << i->get_oid() << ": " | |
1460 | << cpp_strerror(r) << std::endl; | |
1461 | ++errors; | |
1462 | break; | |
1463 | } | |
1464 | } | |
1465 | } | |
1466 | } | |
1467 | } | |
f64942e4 | 1468 | catch (const std::exception& e) { |
7c673cae FG |
1469 | cerr << e.what() << std::endl; |
1470 | return -1; | |
1471 | } | |
1472 | return errors ? -1 : 0; | |
1473 | } | |
1474 | ||
1475 | static int do_get_inconsistent_pg_cmd(const std::vector<const char*> &nargs, | |
1476 | Rados& rados, | |
1477 | Formatter& formatter) | |
1478 | { | |
1479 | if (nargs.size() < 2) { | |
1480 | usage_exit(); | |
1481 | } | |
1482 | int64_t pool_id = rados.pool_lookup(nargs[1]); | |
1483 | if (pool_id < 0) { | |
1484 | cerr << "pool \"" << nargs[1] << "\" not found" << std::endl; | |
1485 | return (int)pool_id; | |
1486 | } | |
1487 | std::vector<PlacementGroup> pgs; | |
1488 | int ret = rados.get_inconsistent_pgs(pool_id, &pgs); | |
1489 | if (ret) { | |
1490 | return ret; | |
1491 | } | |
1492 | formatter.open_array_section("pgs"); | |
1493 | for (auto& pg : pgs) { | |
1494 | formatter.dump_stream("pg") << pg; | |
1495 | } | |
1496 | formatter.close_section(); | |
1497 | formatter.flush(cout); | |
1498 | cout << std::endl; | |
1499 | return 0; | |
1500 | } | |
1501 | ||
1502 | static void dump_errors(const err_t &err, Formatter &f, const char *name) | |
1503 | { | |
1504 | f.open_array_section(name); | |
1505 | if (err.has_shard_missing()) | |
1506 | f.dump_string("error", "missing"); | |
1507 | if (err.has_stat_error()) | |
1508 | f.dump_string("error", "stat_error"); | |
1509 | if (err.has_read_error()) | |
1510 | f.dump_string("error", "read_error"); | |
94b18763 FG |
1511 | if (err.has_data_digest_mismatch_info()) |
1512 | f.dump_string("error", "data_digest_mismatch_info"); | |
1513 | if (err.has_omap_digest_mismatch_info()) | |
1514 | f.dump_string("error", "omap_digest_mismatch_info"); | |
1515 | if (err.has_size_mismatch_info()) | |
1516 | f.dump_string("error", "size_mismatch_info"); | |
7c673cae FG |
1517 | if (err.has_ec_hash_error()) |
1518 | f.dump_string("error", "ec_hash_error"); | |
1519 | if (err.has_ec_size_error()) | |
1520 | f.dump_string("error", "ec_size_error"); | |
94b18763 FG |
1521 | if (err.has_info_missing()) |
1522 | f.dump_string("error", "info_missing"); | |
1523 | if (err.has_info_corrupted()) | |
1524 | f.dump_string("error", "info_corrupted"); | |
1525 | if (err.has_obj_size_info_mismatch()) | |
1526 | f.dump_string("error", "obj_size_info_mismatch"); | |
1527 | if (err.has_snapset_missing()) | |
1528 | f.dump_string("error", "snapset_missing"); | |
1529 | if (err.has_snapset_corrupted()) | |
1530 | f.dump_string("error", "snapset_corrupted"); | |
1531 | if (err.has_hinfo_missing()) | |
1532 | f.dump_string("error", "hinfo_missing"); | |
1533 | if (err.has_hinfo_corrupted()) | |
1534 | f.dump_string("error", "hinfo_corrupted"); | |
7c673cae FG |
1535 | f.close_section(); |
1536 | } | |
1537 | ||
1538 | static void dump_shard(const shard_info_t& shard, | |
1539 | const inconsistent_obj_t& inc, | |
1540 | Formatter &f) | |
1541 | { | |
1542 | dump_errors(shard, f, "errors"); | |
1543 | ||
1544 | if (shard.has_shard_missing()) | |
1545 | return; | |
1546 | ||
1547 | if (!shard.has_stat_error()) | |
1548 | f.dump_unsigned("size", shard.size); | |
1549 | if (shard.omap_digest_present) { | |
1550 | f.dump_format("omap_digest", "0x%08x", shard.omap_digest); | |
1551 | } | |
1552 | if (shard.data_digest_present) { | |
1553 | f.dump_format("data_digest", "0x%08x", shard.data_digest); | |
1554 | } | |
1555 | ||
94b18763 FG |
1556 | if ((inc.union_shards.has_info_missing() |
1557 | || inc.union_shards.has_info_corrupted() | |
1558 | || inc.has_object_info_inconsistency() | |
1559 | || shard.has_obj_size_info_mismatch()) && | |
1560 | !shard.has_info_missing()) { | |
7c673cae | 1561 | map<std::string, ceph::bufferlist>::iterator k = (const_cast<shard_info_t&>(shard)).attrs.find(OI_ATTR); |
11fdf7f2 | 1562 | ceph_assert(k != shard.attrs.end()); // Can't be missing |
94b18763 FG |
1563 | if (!shard.has_info_corrupted()) { |
1564 | object_info_t oi; | |
1565 | bufferlist bl; | |
11fdf7f2 TL |
1566 | auto bliter = k->second.cbegin(); |
1567 | decode(oi, bliter); // Can't be corrupted | |
94b18763 FG |
1568 | f.open_object_section("object_info"); |
1569 | oi.dump(&f); | |
1570 | f.close_section(); | |
1571 | } else { | |
1572 | bool b64; | |
1573 | f.dump_string("object_info", cleanbin(k->second, b64)); | |
1574 | } | |
7c673cae | 1575 | } |
94b18763 FG |
1576 | if ((inc.union_shards.has_snapset_missing() |
1577 | || inc.union_shards.has_snapset_corrupted() | |
1578 | || inc.has_snapset_inconsistency()) && | |
1579 | !shard.has_snapset_missing()) { | |
3a9019d9 | 1580 | map<std::string, ceph::bufferlist>::iterator k = (const_cast<shard_info_t&>(shard)).attrs.find(SS_ATTR); |
11fdf7f2 | 1581 | ceph_assert(k != shard.attrs.end()); // Can't be missing |
94b18763 FG |
1582 | if (!shard.has_snapset_corrupted()) { |
1583 | SnapSet ss; | |
1584 | bufferlist bl; | |
11fdf7f2 | 1585 | auto bliter = k->second.cbegin(); |
94b18763 FG |
1586 | decode(ss, bliter); // Can't be corrupted |
1587 | f.open_object_section("snapset"); | |
1588 | ss.dump(&f); | |
1589 | f.close_section(); | |
1590 | } else { | |
1591 | bool b64; | |
1592 | f.dump_string("snapset", cleanbin(k->second, b64)); | |
1593 | } | |
1594 | } | |
1595 | if ((inc.union_shards.has_hinfo_missing() | |
1596 | || inc.union_shards.has_hinfo_corrupted() | |
1597 | || inc.has_hinfo_inconsistency()) && | |
1598 | !shard.has_hinfo_missing()) { | |
1599 | map<std::string, ceph::bufferlist>::iterator k = (const_cast<shard_info_t&>(shard)).attrs.find(ECUtil::get_hinfo_key()); | |
11fdf7f2 | 1600 | ceph_assert(k != shard.attrs.end()); // Can't be missing |
94b18763 FG |
1601 | if (!shard.has_hinfo_corrupted()) { |
1602 | ECUtil::HashInfo hi; | |
1603 | bufferlist bl; | |
11fdf7f2 | 1604 | auto bliter = k->second.cbegin(); |
94b18763 FG |
1605 | decode(hi, bliter); // Can't be corrupted |
1606 | f.open_object_section("hashinfo"); | |
1607 | hi.dump(&f); | |
1608 | f.close_section(); | |
1609 | } else { | |
1610 | bool b64; | |
1611 | f.dump_string("hashinfo", cleanbin(k->second, b64)); | |
1612 | } | |
3a9019d9 | 1613 | } |
94b18763 | 1614 | if (inc.has_attr_name_mismatch() || inc.has_attr_value_mismatch()) { |
7c673cae FG |
1615 | f.open_array_section("attrs"); |
1616 | for (auto kv : shard.attrs) { | |
94b18763 FG |
1617 | // System attribute handled above |
1618 | if (kv.first == OI_ATTR || kv.first[0] != '_') | |
1619 | continue; | |
7c673cae | 1620 | f.open_object_section("attr"); |
94b18763 FG |
1621 | // Skip leading underscore since only giving user attrs |
1622 | f.dump_string("name", kv.first.substr(1)); | |
7c673cae FG |
1623 | bool b64; |
1624 | f.dump_string("value", cleanbin(kv.second, b64)); | |
1625 | f.dump_bool("Base64", b64); | |
1626 | f.close_section(); | |
1627 | } | |
1628 | f.close_section(); | |
1629 | } | |
1630 | } | |
1631 | ||
1632 | static void dump_obj_errors(const obj_err_t &err, Formatter &f) | |
1633 | { | |
1634 | f.open_array_section("errors"); | |
1635 | if (err.has_object_info_inconsistency()) | |
1636 | f.dump_string("error", "object_info_inconsistency"); | |
1637 | if (err.has_data_digest_mismatch()) | |
1638 | f.dump_string("error", "data_digest_mismatch"); | |
1639 | if (err.has_omap_digest_mismatch()) | |
1640 | f.dump_string("error", "omap_digest_mismatch"); | |
1641 | if (err.has_size_mismatch()) | |
1642 | f.dump_string("error", "size_mismatch"); | |
1643 | if (err.has_attr_value_mismatch()) | |
1644 | f.dump_string("error", "attr_value_mismatch"); | |
1645 | if (err.has_attr_name_mismatch()) | |
1646 | f.dump_string("error", "attr_name_mismatch"); | |
3a9019d9 FG |
1647 | if (err.has_snapset_inconsistency()) |
1648 | f.dump_string("error", "snapset_inconsistency"); | |
94b18763 FG |
1649 | if (err.has_hinfo_inconsistency()) |
1650 | f.dump_string("error", "hinfo_inconsistency"); | |
eafe8130 TL |
1651 | if (err.has_size_too_large()) |
1652 | f.dump_string("error", "size_too_large"); | |
7c673cae FG |
1653 | f.close_section(); |
1654 | } | |
1655 | ||
1656 | static void dump_object_id(const object_id_t& object, | |
1657 | Formatter &f) | |
1658 | { | |
1659 | f.dump_string("name", object.name); | |
1660 | f.dump_string("nspace", object.nspace); | |
1661 | f.dump_string("locator", object.locator); | |
1662 | switch (object.snap) { | |
1663 | case CEPH_NOSNAP: | |
1664 | f.dump_string("snap", "head"); | |
1665 | break; | |
1666 | case CEPH_SNAPDIR: | |
1667 | f.dump_string("snap", "snapdir"); | |
1668 | break; | |
1669 | default: | |
1670 | f.dump_unsigned("snap", object.snap); | |
1671 | break; | |
1672 | } | |
1673 | } | |
1674 | ||
1675 | static void dump_inconsistent(const inconsistent_obj_t& inc, | |
1676 | Formatter &f) | |
1677 | { | |
1678 | f.open_object_section("object"); | |
1679 | dump_object_id(inc.object, f); | |
1680 | f.dump_unsigned("version", inc.version); | |
1681 | f.close_section(); | |
1682 | ||
1683 | dump_obj_errors(inc, f); | |
1684 | dump_errors(inc.union_shards, f, "union_shard_errors"); | |
1685 | for (const auto& shard_info : inc.shards) { | |
1686 | shard_info_t shard = const_cast<shard_info_t&>(shard_info.second); | |
1687 | if (shard.selected_oi) { | |
1688 | object_info_t oi; | |
1689 | bufferlist bl; | |
1690 | auto k = shard.attrs.find(OI_ATTR); | |
11fdf7f2 TL |
1691 | ceph_assert(k != shard.attrs.end()); // Can't be missing |
1692 | auto bliter = k->second.cbegin(); | |
1693 | decode(oi, bliter); // Can't be corrupted | |
94b18763 FG |
1694 | f.open_object_section("selected_object_info"); |
1695 | oi.dump(&f); | |
1696 | f.close_section(); | |
7c673cae FG |
1697 | break; |
1698 | } | |
1699 | } | |
1700 | f.open_array_section("shards"); | |
1701 | for (const auto& shard_info : inc.shards) { | |
1702 | f.open_object_section("shard"); | |
1703 | auto& osd_shard = shard_info.first; | |
1704 | f.dump_int("osd", osd_shard.osd); | |
b5b8bbf5 | 1705 | f.dump_bool("primary", shard_info.second.primary); |
7c673cae FG |
1706 | auto shard = osd_shard.shard; |
1707 | if (shard != shard_id_t::NO_SHARD) | |
1708 | f.dump_unsigned("shard", shard); | |
1709 | dump_shard(shard_info.second, inc, f); | |
1710 | f.close_section(); | |
1711 | } | |
1712 | f.close_section(); | |
1713 | } | |
1714 | ||
1715 | static void dump_inconsistent(const inconsistent_snapset_t& inc, | |
1716 | Formatter &f) | |
1717 | { | |
1718 | dump_object_id(inc.object, f); | |
1719 | ||
94b18763 FG |
1720 | if (inc.ss_bl.length()) { |
1721 | SnapSet ss; | |
1722 | bufferlist bl = inc.ss_bl; | |
11fdf7f2 | 1723 | auto bliter = bl.cbegin(); |
94b18763 FG |
1724 | decode(ss, bliter); // Can't be corrupted |
1725 | f.open_object_section("snapset"); | |
1726 | ss.dump(&f); | |
1727 | f.close_section(); | |
1728 | } | |
7c673cae | 1729 | f.open_array_section("errors"); |
94b18763 FG |
1730 | if (inc.snapset_missing()) |
1731 | f.dump_string("error", "snapset_missing"); | |
1732 | if (inc.snapset_corrupted()) | |
1733 | f.dump_string("error", "snapset_corrupted"); | |
1734 | if (inc.info_missing()) | |
1735 | f.dump_string("error", "info_missing"); | |
1736 | if (inc.info_corrupted()) | |
1737 | f.dump_string("error", "info_corrupted"); | |
1738 | if (inc.snapset_error()) | |
1739 | f.dump_string("error", "snapset_error"); | |
7c673cae FG |
1740 | if (inc.headless()) |
1741 | f.dump_string("error", "headless"); | |
1742 | if (inc.size_mismatch()) | |
1743 | f.dump_string("error", "size_mismatch"); | |
1744 | if (inc.extra_clones()) | |
1745 | f.dump_string("error", "extra_clones"); | |
1746 | if (inc.clone_missing()) | |
1747 | f.dump_string("error", "clone_missing"); | |
1748 | f.close_section(); | |
1749 | ||
1750 | if (inc.extra_clones()) { | |
1751 | f.open_array_section("extra clones"); | |
1752 | for (auto snap : inc.clones) { | |
1753 | f.dump_unsigned("snap", snap); | |
1754 | } | |
1755 | f.close_section(); | |
1756 | } | |
1757 | ||
1758 | if (inc.clone_missing()) { | |
1759 | f.open_array_section("missing"); | |
1760 | for (auto snap : inc.missing) { | |
1761 | f.dump_unsigned("snap", snap); | |
1762 | } | |
1763 | f.close_section(); | |
1764 | } | |
1765 | } | |
1766 | ||
1767 | // dispatch the call by type | |
1768 | static int do_get_inconsistent(Rados& rados, | |
1769 | const PlacementGroup& pg, | |
1770 | const librados::object_id_t &start, | |
1771 | unsigned max_return, | |
1772 | AioCompletion *c, | |
1773 | std::vector<inconsistent_obj_t>* objs, | |
1774 | uint32_t* interval) | |
1775 | { | |
1776 | return rados.get_inconsistent_objects(pg, start, max_return, c, | |
1777 | objs, interval); | |
1778 | } | |
1779 | ||
1780 | static int do_get_inconsistent(Rados& rados, | |
1781 | const PlacementGroup& pg, | |
1782 | const librados::object_id_t &start, | |
1783 | unsigned max_return, | |
1784 | AioCompletion *c, | |
1785 | std::vector<inconsistent_snapset_t>* snapsets, | |
1786 | uint32_t* interval) | |
1787 | { | |
1788 | return rados.get_inconsistent_snapsets(pg, start, max_return, c, | |
1789 | snapsets, interval); | |
1790 | } | |
1791 | ||
1792 | template <typename T> | |
1793 | static int do_get_inconsistent_cmd(const std::vector<const char*> &nargs, | |
1794 | Rados& rados, | |
1795 | Formatter& formatter) | |
1796 | { | |
1797 | if (nargs.size() < 2) { | |
1798 | usage_exit(); | |
1799 | } | |
1800 | PlacementGroup pg; | |
1801 | int ret = 0; | |
1802 | ret = pg.parse(nargs[1]); | |
1803 | if (!ret) { | |
1804 | cerr << "bad pg: " << nargs[1] << std::endl; | |
1805 | return ret; | |
1806 | } | |
1807 | uint32_t interval = 0, first_interval = 0; | |
1808 | const unsigned max_item_num = 32; | |
1809 | bool opened = false; | |
1810 | for (librados::object_id_t start;;) { | |
1811 | std::vector<T> items; | |
1812 | auto completion = librados::Rados::aio_create_completion(); | |
1813 | ret = do_get_inconsistent(rados, pg, start, max_item_num, completion, | |
1814 | &items, &interval); | |
9f95a23c | 1815 | completion->wait_for_complete(); |
7c673cae FG |
1816 | ret = completion->get_return_value(); |
1817 | completion->release(); | |
1818 | if (ret < 0) { | |
1819 | if (ret == -EAGAIN) | |
1820 | cerr << "interval#" << interval << " expired." << std::endl; | |
1821 | else if (ret == -ENOENT) | |
1822 | cerr << "No scrub information available for pg " << pg << std::endl; | |
7c673cae FG |
1823 | break; |
1824 | } | |
1825 | // It must be the same interval every time. EAGAIN would | |
1826 | // occur if interval changes. | |
11fdf7f2 | 1827 | ceph_assert(start.name.empty() || first_interval == interval); |
7c673cae FG |
1828 | if (start.name.empty()) { |
1829 | first_interval = interval; | |
1830 | formatter.open_object_section("info"); | |
1831 | formatter.dump_int("epoch", interval); | |
1832 | formatter.open_array_section("inconsistents"); | |
1833 | opened = true; | |
1834 | } | |
1835 | for (auto& inc : items) { | |
1836 | formatter.open_object_section("inconsistent"); | |
1837 | dump_inconsistent(inc, formatter); | |
1838 | formatter.close_section(); | |
1839 | } | |
1840 | if (items.size() < max_item_num) { | |
1841 | formatter.close_section(); | |
1842 | break; | |
1843 | } | |
1844 | if (!items.empty()) { | |
1845 | start = items.back().object; | |
1846 | } | |
1847 | items.clear(); | |
1848 | } | |
1849 | if (opened) { | |
1850 | formatter.close_section(); | |
1851 | formatter.flush(cout); | |
1852 | } | |
1853 | return ret; | |
1854 | } | |
1855 | ||
f67539c2 TL |
1856 | static std::string prettify(const std::string& s) |
1857 | { | |
1858 | if (std::find_if_not(s.begin(), s.end(), | |
1859 | (int (*)(int))isprint) != s.end()) { | |
1860 | return "(binary key)"; | |
1861 | } else { | |
1862 | return s; | |
1863 | } | |
1864 | } | |
1865 | ||
7c673cae FG |
1866 | /********************************************** |
1867 | ||
1868 | **********************************************/ | |
1869 | static int rados_tool_common(const std::map < std::string, std::string > &opts, | |
1870 | std::vector<const char*> &nargs) | |
1871 | { | |
1872 | int ret; | |
1873 | bool create_pool = false; | |
1874 | const char *pool_name = NULL; | |
1875 | const char *target_pool_name = NULL; | |
1876 | string oloc, target_oloc, nspace, target_nspace; | |
1877 | int concurrent_ios = 16; | |
1878 | unsigned op_size = default_op_size; | |
1879 | unsigned object_size = 0; | |
1880 | unsigned max_objects = 0; | |
1881 | uint64_t obj_offset = 0; | |
9f95a23c | 1882 | bool obj_offset_specified = false; |
7c673cae FG |
1883 | bool block_size_specified = false; |
1884 | int bench_write_dest = 0; | |
1885 | bool cleanup = true; | |
1886 | bool hints = true; // for rados bench | |
11fdf7f2 | 1887 | bool reuse_bench = false; |
7c673cae FG |
1888 | bool no_verify = false; |
1889 | bool use_striper = false; | |
1890 | bool with_clones = false; | |
1891 | const char *snapname = NULL; | |
1892 | snap_t snapid = CEPH_NOSNAP; | |
1893 | std::map<std::string, std::string>::const_iterator i; | |
1894 | ||
11fdf7f2 | 1895 | uint64_t offset_align = 0; |
7c673cae FG |
1896 | uint64_t min_obj_len = 0; |
1897 | uint64_t max_obj_len = 0; | |
1898 | uint64_t min_op_len = 0; | |
1899 | uint64_t max_op_len = 0; | |
1900 | uint64_t max_ops = 0; | |
1901 | uint64_t max_backlog = 0; | |
1902 | uint64_t target_throughput = 0; | |
1903 | int64_t read_percent = -1; | |
1904 | uint64_t num_objs = 0; | |
1905 | int run_length = 0; | |
1906 | ||
1907 | bool show_time = false; | |
1908 | bool wildcard = false; | |
1909 | ||
1910 | std::string run_name; | |
1911 | std::string prefix; | |
1912 | bool forcefull = false; | |
11fdf7f2 | 1913 | unique_ptr<Formatter> formatter = nullptr; |
7c673cae FG |
1914 | bool pretty_format = false; |
1915 | const char *output = NULL; | |
f67539c2 TL |
1916 | std::optional<std::string> omap_key; |
1917 | std::optional<std::string> obj_name; | |
1918 | std::string input_file; | |
11fdf7f2 | 1919 | bool with_reference = false; |
7c673cae FG |
1920 | |
1921 | Rados rados; | |
1922 | IoCtx io_ctx; | |
7c673cae FG |
1923 | |
1924 | i = opts.find("create"); | |
1925 | if (i != opts.end()) { | |
1926 | create_pool = true; | |
1927 | } | |
1928 | i = opts.find("pool"); | |
1929 | if (i != opts.end()) { | |
1930 | pool_name = i->second.c_str(); | |
1931 | } | |
1932 | i = opts.find("target_pool"); | |
1933 | if (i != opts.end()) { | |
1934 | target_pool_name = i->second.c_str(); | |
1935 | } | |
1936 | i = opts.find("object_locator"); | |
1937 | if (i != opts.end()) { | |
1938 | oloc = i->second; | |
1939 | } | |
1940 | i = opts.find("target_locator"); | |
1941 | if (i != opts.end()) { | |
1942 | target_oloc = i->second; | |
1943 | } | |
1944 | i = opts.find("target_nspace"); | |
1945 | if (i != opts.end()) { | |
1946 | target_nspace = i->second; | |
1947 | } | |
1948 | i = opts.find("concurrent-ios"); | |
1949 | if (i != opts.end()) { | |
1950 | if (rados_sistrtoll(i, &concurrent_ios)) { | |
1951 | return -EINVAL; | |
1952 | } | |
1953 | } | |
1954 | i = opts.find("run-name"); | |
1955 | if (i != opts.end()) { | |
1956 | run_name = i->second; | |
1957 | } | |
1958 | ||
1959 | i = opts.find("force-full"); | |
1960 | if (i != opts.end()) { | |
1961 | forcefull = true; | |
1962 | } | |
1963 | i = opts.find("prefix"); | |
1964 | if (i != opts.end()) { | |
1965 | prefix = i->second; | |
1966 | } | |
1967 | i = opts.find("block-size"); | |
1968 | if (i != opts.end()) { | |
1969 | if (rados_sistrtoll(i, &op_size)) { | |
1970 | return -EINVAL; | |
1971 | } | |
1972 | block_size_specified = true; | |
1973 | } | |
1974 | i = opts.find("object-size"); | |
1975 | if (i != opts.end()) { | |
1976 | if (rados_sistrtoll(i, &object_size)) { | |
1977 | return -EINVAL; | |
1978 | } | |
1979 | block_size_specified = true; | |
1980 | } | |
1981 | i = opts.find("max-objects"); | |
1982 | if (i != opts.end()) { | |
1983 | if (rados_sistrtoll(i, &max_objects)) { | |
1984 | return -EINVAL; | |
1985 | } | |
1986 | } | |
1987 | i = opts.find("offset"); | |
1988 | if (i != opts.end()) { | |
1989 | if (rados_sistrtoll(i, &obj_offset)) { | |
1990 | return -EINVAL; | |
1991 | } | |
9f95a23c | 1992 | obj_offset_specified = true; |
7c673cae FG |
1993 | } |
1994 | i = opts.find("snap"); | |
1995 | if (i != opts.end()) { | |
1996 | snapname = i->second.c_str(); | |
1997 | } | |
1998 | i = opts.find("snapid"); | |
1999 | if (i != opts.end()) { | |
2000 | if (rados_sistrtoll(i, &snapid)) { | |
2001 | return -EINVAL; | |
2002 | } | |
2003 | } | |
2004 | i = opts.find("min-object-size"); | |
2005 | if (i != opts.end()) { | |
2006 | if (rados_sistrtoll(i, &min_obj_len)) { | |
2007 | return -EINVAL; | |
2008 | } | |
2009 | } | |
2010 | i = opts.find("max-object-size"); | |
2011 | if (i != opts.end()) { | |
2012 | if (rados_sistrtoll(i, &max_obj_len)) { | |
2013 | return -EINVAL; | |
2014 | } | |
2015 | } | |
2016 | i = opts.find("min-op-len"); | |
2017 | if (i != opts.end()) { | |
2018 | if (rados_sistrtoll(i, &min_op_len)) { | |
2019 | return -EINVAL; | |
2020 | } | |
2021 | } | |
2022 | i = opts.find("max-op-len"); | |
2023 | if (i != opts.end()) { | |
2024 | if (rados_sistrtoll(i, &max_op_len)) { | |
2025 | return -EINVAL; | |
2026 | } | |
2027 | } | |
2028 | i = opts.find("max-ops"); | |
2029 | if (i != opts.end()) { | |
2030 | if (rados_sistrtoll(i, &max_ops)) { | |
2031 | return -EINVAL; | |
2032 | } | |
2033 | } | |
2034 | i = opts.find("max-backlog"); | |
2035 | if (i != opts.end()) { | |
2036 | if (rados_sistrtoll(i, &max_backlog)) { | |
2037 | return -EINVAL; | |
2038 | } | |
2039 | } | |
2040 | i = opts.find("target-throughput"); | |
2041 | if (i != opts.end()) { | |
2042 | if (rados_sistrtoll(i, &target_throughput)) { | |
2043 | return -EINVAL; | |
2044 | } | |
2045 | } | |
2046 | i = opts.find("read-percent"); | |
2047 | if (i != opts.end()) { | |
2048 | if (rados_sistrtoll(i, &read_percent)) { | |
2049 | return -EINVAL; | |
2050 | } | |
2051 | } | |
2052 | i = opts.find("num-objects"); | |
2053 | if (i != opts.end()) { | |
2054 | if (rados_sistrtoll(i, &num_objs)) { | |
2055 | return -EINVAL; | |
2056 | } | |
2057 | } | |
2058 | i = opts.find("run-length"); | |
2059 | if (i != opts.end()) { | |
2060 | if (rados_sistrtoll(i, &run_length)) { | |
2061 | return -EINVAL; | |
2062 | } | |
2063 | } | |
2064 | i = opts.find("show-time"); | |
2065 | if (i != opts.end()) { | |
2066 | show_time = true; | |
2067 | } | |
2068 | i = opts.find("no-cleanup"); | |
2069 | if (i != opts.end()) { | |
2070 | cleanup = false; | |
2071 | } | |
2072 | i = opts.find("no-hints"); | |
2073 | if (i != opts.end()) { | |
2074 | hints = false; | |
2075 | } | |
11fdf7f2 TL |
2076 | i = opts.find("reuse-bench"); |
2077 | if (i != opts.end()) { | |
2078 | reuse_bench = true; | |
2079 | } | |
7c673cae FG |
2080 | i = opts.find("pretty-format"); |
2081 | if (i != opts.end()) { | |
2082 | pretty_format = true; | |
2083 | } | |
2084 | i = opts.find("format"); | |
2085 | if (i != opts.end()) { | |
2086 | const char *format = i->second.c_str(); | |
11fdf7f2 | 2087 | formatter.reset(Formatter::create(format)); |
7c673cae FG |
2088 | if (!formatter) { |
2089 | cerr << "unrecognized format: " << format << std::endl; | |
2090 | return -EINVAL; | |
2091 | } | |
2092 | } | |
2093 | i = opts.find("namespace"); | |
2094 | if (i != opts.end()) { | |
2095 | nspace = i->second; | |
2096 | } | |
2097 | i = opts.find("no-verify"); | |
2098 | if (i != opts.end()) { | |
2099 | no_verify = true; | |
2100 | } | |
2101 | i = opts.find("output"); | |
2102 | if (i != opts.end()) { | |
2103 | output = i->second.c_str(); | |
2104 | } | |
2105 | i = opts.find("write-dest-obj"); | |
2106 | if (i != opts.end()) { | |
2107 | bench_write_dest |= static_cast<int>(OP_WRITE_DEST_OBJ); | |
2108 | } | |
2109 | i = opts.find("write-dest-omap"); | |
2110 | if (i != opts.end()) { | |
2111 | bench_write_dest |= static_cast<int>(OP_WRITE_DEST_OMAP); | |
2112 | } | |
2113 | i = opts.find("write-dest-xattr"); | |
2114 | if (i != opts.end()) { | |
2115 | bench_write_dest |= static_cast<int>(OP_WRITE_DEST_XATTR); | |
2116 | } | |
2117 | i = opts.find("with-clones"); | |
2118 | if (i != opts.end()) { | |
2119 | with_clones = true; | |
2120 | } | |
2121 | i = opts.find("omap-key-file"); | |
2122 | if (i != opts.end()) { | |
2123 | string err; | |
2124 | bufferlist indata; | |
2125 | ret = indata.read_file(i->second.c_str(), &err); | |
2126 | if (ret < 0) { | |
2127 | cerr << err << std::endl; | |
2128 | return 1; | |
2129 | } | |
7c673cae | 2130 | omap_key = std::string(indata.c_str(), indata.length()); |
f67539c2 TL |
2131 | } |
2132 | i = opts.find("obj-name-file"); | |
2133 | if (i != opts.end()) { | |
2134 | string err; | |
2135 | bufferlist indata; | |
2136 | ret = indata.read_file(i->second.c_str(), &err); | |
2137 | if (ret < 0) { | |
2138 | cerr << err << std::endl; | |
2139 | return 1; | |
7c673cae | 2140 | } |
f67539c2 | 2141 | obj_name = std::string(indata.c_str(), indata.length()); |
7c673cae | 2142 | } |
11fdf7f2 TL |
2143 | i = opts.find("offset_align"); |
2144 | if (i != opts.end()) { | |
2145 | if (rados_sistrtoll(i, &offset_align)) { | |
2146 | return -EINVAL; | |
2147 | } | |
2148 | } | |
2149 | i = opts.find("with-reference"); | |
2150 | if (i != opts.end()) { | |
2151 | with_reference = true; | |
2152 | } | |
f67539c2 TL |
2153 | i = opts.find("input_file"); |
2154 | if (i != opts.end()) { | |
2155 | input_file = i->second; | |
2156 | } | |
11fdf7f2 | 2157 | |
7c673cae FG |
2158 | // open rados |
2159 | ret = rados.init_with_context(g_ceph_context); | |
2160 | if (ret < 0) { | |
2161 | cerr << "couldn't initialize rados: " << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 2162 | return 1; |
7c673cae FG |
2163 | } |
2164 | ||
2165 | ret = rados.connect(); | |
2166 | if (ret) { | |
2167 | cerr << "couldn't connect to cluster: " << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 2168 | return 1; |
7c673cae FG |
2169 | } |
2170 | ||
2171 | if (create_pool && !pool_name) { | |
2172 | cerr << "--create-pool requested but pool_name was not specified!" << std::endl; | |
11fdf7f2 TL |
2173 | usage(cerr); |
2174 | return 1; | |
7c673cae FG |
2175 | } |
2176 | ||
2177 | if (create_pool) { | |
11fdf7f2 | 2178 | ret = rados.pool_create(pool_name); |
7c673cae FG |
2179 | if (ret < 0) { |
2180 | cerr << "error creating pool " << pool_name << ": " | |
2181 | << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 2182 | return 1; |
7c673cae FG |
2183 | } |
2184 | } | |
2185 | ||
eafe8130 TL |
2186 | i = opts.find("pgid"); |
2187 | boost::optional<pg_t> pgid(i != opts.end(), pg_t()); | |
2188 | if (pgid && (!pgid->parse(i->second.c_str()) || (pool_name && rados.pool_lookup(pool_name) != pgid->pool()))) { | |
2189 | cerr << "invalid pgid" << std::endl; | |
2190 | return 1; | |
2191 | } | |
2192 | ||
7c673cae | 2193 | // open io context. |
11fdf7f2 TL |
2194 | if (pool_name || pgid) { |
2195 | ret = pool_name ? rados.ioctx_create(pool_name, io_ctx) : rados.ioctx_create2(pgid->pool(), io_ctx); | |
7c673cae | 2196 | if (ret < 0) { |
11fdf7f2 TL |
2197 | cerr << "error opening pool " |
2198 | << (pool_name ? pool_name : std::string("with id ") + std::to_string(pgid->pool())) << ": " | |
7c673cae | 2199 | << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 2200 | return 1; |
7c673cae FG |
2201 | } |
2202 | ||
2203 | // align op_size | |
2204 | { | |
1e59de90 TL |
2205 | bool req; |
2206 | ret = io_ctx.pool_requires_alignment2(&req); | |
7c673cae FG |
2207 | if (ret < 0) { |
2208 | cerr << "error checking pool alignment requirement" | |
2209 | << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 2210 | return 1; |
7c673cae FG |
2211 | } |
2212 | ||
1e59de90 | 2213 | if (req) { |
7c673cae FG |
2214 | uint64_t align = 0; |
2215 | ret = io_ctx.pool_required_alignment2(&align); | |
2216 | if (ret < 0) { | |
2217 | cerr << "error getting pool alignment" | |
2218 | << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 2219 | return 1; |
7c673cae FG |
2220 | } |
2221 | ||
2222 | const uint64_t prev_op_size = op_size; | |
2223 | op_size = uint64_t((op_size + align - 1) / align) * align; | |
2224 | // Warn: if user specified and it was rounded | |
2225 | if (prev_op_size != default_op_size && prev_op_size != op_size) | |
2226 | cerr << "INFO: op_size has been rounded to " << op_size << std::endl; | |
2227 | } | |
2228 | } | |
2229 | ||
11fdf7f2 | 2230 | #ifdef WITH_LIBRADOSSTRIPER |
7c673cae FG |
2231 | // create striper interface |
2232 | if (opts.find("striper") != opts.end()) { | |
11fdf7f2 TL |
2233 | // Note that this call does a tricky thing by reaching into a "singleton". We count |
2234 | // on this happening only once: | |
2235 | ret = RadosStriper::striper_create(io_ctx, &detail::striper()); | |
7c673cae | 2236 | if (0 != ret) { |
11fdf7f2 TL |
2237 | cerr << "error opening pool " << pool_name << " with striper interface: " |
2238 | << cpp_strerror(ret) << std::endl; | |
2239 | return 1; | |
7c673cae FG |
2240 | } |
2241 | use_striper = true; | |
2242 | } | |
11fdf7f2 | 2243 | #endif // USE_LIBRADOSSTRIPER |
7c673cae FG |
2244 | } |
2245 | ||
2246 | // snapname? | |
2247 | if (snapname) { | |
2248 | if (!pool_name) { | |
2249 | cerr << "pool name must be specified with --snap" << std::endl; | |
11fdf7f2 | 2250 | return 1; |
7c673cae FG |
2251 | } |
2252 | ret = io_ctx.snap_lookup(snapname, &snapid); | |
2253 | if (ret < 0) { | |
2254 | cerr << "error looking up snap '" << snapname << "': " << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 2255 | return 1; |
7c673cae FG |
2256 | } |
2257 | } | |
2258 | if (oloc.size()) { | |
2259 | if (!pool_name) { | |
f67539c2 | 2260 | cerr << "pool name must be specified with --object-locator" << std::endl; |
11fdf7f2 | 2261 | return 1; |
7c673cae FG |
2262 | } |
2263 | io_ctx.locator_set_key(oloc); | |
2264 | } | |
2265 | // Use namespace from command line if specified | |
2266 | if (opts.find("namespace") != opts.end()) { | |
2267 | if (!pool_name) { | |
2268 | cerr << "pool name must be specified with --namespace" << std::endl; | |
11fdf7f2 | 2269 | return 1; |
7c673cae FG |
2270 | } |
2271 | io_ctx.set_namespace(nspace); | |
2272 | // Use wildcard if --all specified and --default NOT specified | |
2273 | } else if (opts.find("all") != opts.end() && opts.find("default") == opts.end()) { | |
2274 | // Only the ls should ever set namespace to special value | |
2275 | wildcard = true; | |
2276 | } | |
2277 | if (snapid != CEPH_NOSNAP) { | |
2278 | if (!pool_name) { | |
2279 | cerr << "pool name must be specified with --snapid" << std::endl; | |
11fdf7f2 | 2280 | return 1; |
7c673cae FG |
2281 | } |
2282 | string name; | |
2283 | ret = io_ctx.snap_get_name(snapid, &name); | |
2284 | if (ret < 0) { | |
2285 | cerr << "snapid " << snapid << " doesn't exist in pool " | |
2286 | << io_ctx.get_pool_name() << std::endl; | |
11fdf7f2 | 2287 | return 1; |
7c673cae FG |
2288 | } |
2289 | io_ctx.snap_set_read(snapid); | |
2290 | cout << "selected snap " << snapid << " '" << name << "'" << std::endl; | |
2291 | } | |
2292 | ||
11fdf7f2 | 2293 | ceph_assert(!nargs.empty()); |
7c673cae FG |
2294 | |
2295 | // list pools? | |
2296 | if (strcmp(nargs[0], "lspools") == 0) { | |
2297 | list<string> vec; | |
2298 | ret = rados.pool_list(vec); | |
2299 | if (ret < 0) { | |
2300 | cerr << "error listing pools: " << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 2301 | return 1; |
7c673cae FG |
2302 | } |
2303 | for (list<string>::iterator i = vec.begin(); i != vec.end(); ++i) | |
2304 | cout << *i << std::endl; | |
2305 | } | |
2306 | else if (strcmp(nargs[0], "df") == 0) { | |
2307 | // pools | |
2308 | list<string> vec; | |
2309 | ||
2310 | if (!pool_name) { | |
2311 | ret = rados.pool_list(vec); | |
2312 | if (ret < 0) { | |
2313 | cerr << "error listing pools: " << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 2314 | return 1; |
7c673cae FG |
2315 | } |
2316 | } else { | |
2317 | vec.push_back(pool_name); | |
2318 | } | |
2319 | ||
2320 | map<string,librados::pool_stat_t> stats; | |
2321 | ret = rados.get_pool_stats(vec, stats); | |
2322 | if (ret < 0) { | |
2323 | cerr << "error fetching pool stats: " << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 2324 | return 1; |
7c673cae FG |
2325 | } |
2326 | ||
2327 | TextTable tab; | |
2328 | ||
2329 | if (!formatter) { | |
2330 | tab.define_column("POOL_NAME", TextTable::LEFT, TextTable::LEFT); | |
11fdf7f2 TL |
2331 | tab.define_column("USED", TextTable::RIGHT, TextTable::RIGHT); |
2332 | tab.define_column("OBJECTS", TextTable::RIGHT, TextTable::RIGHT); | |
2333 | tab.define_column("CLONES", TextTable::RIGHT, TextTable::RIGHT); | |
2334 | tab.define_column("COPIES", TextTable::RIGHT, TextTable::RIGHT); | |
2335 | tab.define_column("MISSING_ON_PRIMARY", TextTable::RIGHT, TextTable::RIGHT); | |
2336 | tab.define_column("UNFOUND", TextTable::RIGHT, TextTable::RIGHT); | |
2337 | tab.define_column("DEGRADED", TextTable::RIGHT, TextTable::RIGHT); | |
2338 | tab.define_column("RD_OPS", TextTable::RIGHT, TextTable::RIGHT); | |
2339 | tab.define_column("RD", TextTable::RIGHT, TextTable::RIGHT); | |
2340 | tab.define_column("WR_OPS", TextTable::RIGHT, TextTable::RIGHT); | |
2341 | tab.define_column("WR", TextTable::RIGHT, TextTable::RIGHT); | |
2342 | tab.define_column("USED COMPR", TextTable::RIGHT, TextTable::RIGHT); | |
2343 | tab.define_column("UNDER COMPR", TextTable::RIGHT, TextTable::RIGHT); | |
7c673cae FG |
2344 | } else { |
2345 | formatter->open_object_section("stats"); | |
2346 | formatter->open_array_section("pools"); | |
2347 | } | |
2348 | for (map<string,librados::pool_stat_t>::iterator i = stats.begin(); | |
2349 | i != stats.end(); | |
2350 | ++i) { | |
2351 | const char *pool_name = i->first.c_str(); | |
2352 | librados::pool_stat_t& s = i->second; | |
2353 | if (!formatter) { | |
2354 | tab << pool_name | |
1adf2230 | 2355 | << byte_u_t(s.num_bytes) |
7c673cae FG |
2356 | << s.num_objects |
2357 | << s.num_object_clones | |
2358 | << s.num_object_copies | |
2359 | << s.num_objects_missing_on_primary | |
2360 | << s.num_objects_unfound | |
2361 | << s.num_objects_degraded | |
2362 | << s.num_rd | |
1adf2230 | 2363 | << byte_u_t(s.num_rd_kb << 10) |
7c673cae | 2364 | << s.num_wr |
1adf2230 | 2365 | << byte_u_t(s.num_wr_kb << 10) |
11fdf7f2 TL |
2366 | << byte_u_t(s.compressed_bytes_alloc) |
2367 | << byte_u_t(s.compressed_bytes_orig) | |
7c673cae FG |
2368 | << TextTable::endrow; |
2369 | } else { | |
2370 | formatter->open_object_section("pool"); | |
2371 | int64_t pool_id = rados.pool_lookup(pool_name); | |
2372 | formatter->dump_string("name", pool_name); | |
2373 | if (pool_id >= 0) | |
2374 | formatter->dump_int("id", pool_id); | |
2375 | else | |
2376 | cerr << "ERROR: lookup_pg_pool_name for name=" << pool_name | |
2377 | << " returned " << pool_id << std::endl; | |
2378 | formatter->dump_int("size_bytes",s.num_bytes); | |
2379 | formatter->dump_int("size_kb", s.num_kb); | |
2380 | formatter->dump_int("num_objects", s.num_objects); | |
2381 | formatter->dump_int("num_object_clones", s.num_object_clones); | |
2382 | formatter->dump_int("num_object_copies", s.num_object_copies); | |
2383 | formatter->dump_int("num_objects_missing_on_primary", s.num_objects_missing_on_primary); | |
2384 | formatter->dump_int("num_objects_unfound", s.num_objects_unfound); | |
2385 | formatter->dump_int("num_objects_degraded", s.num_objects_degraded); | |
2386 | formatter->dump_int("read_ops", s.num_rd); | |
2387 | formatter->dump_int("read_bytes", s.num_rd_kb * 1024ull); | |
2388 | formatter->dump_int("write_ops", s.num_wr); | |
2389 | formatter->dump_int("write_bytes", s.num_wr_kb * 1024ull); | |
11fdf7f2 TL |
2390 | formatter->dump_int("compress_bytes_used", s.compressed_bytes_alloc); |
2391 | formatter->dump_int("compress_under_bytes", s.compressed_bytes_orig); | |
7c673cae FG |
2392 | formatter->close_section(); |
2393 | } | |
2394 | } | |
2395 | ||
2396 | if (!formatter) { | |
2397 | cout << tab; | |
2398 | } | |
2399 | ||
2400 | // total | |
2401 | cluster_stat_t tstats; | |
2402 | ret = rados.cluster_stat(tstats); | |
2403 | if (ret < 0) { | |
2404 | cerr << "error getting total cluster usage: " << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 2405 | return 1; |
7c673cae FG |
2406 | } |
2407 | if (!formatter) { | |
2408 | cout << std::endl; | |
2409 | cout << "total_objects " << tstats.num_objects | |
2410 | << std::endl; | |
1adf2230 | 2411 | cout << "total_used " << byte_u_t(tstats.kb_used << 10) |
7c673cae | 2412 | << std::endl; |
1adf2230 | 2413 | cout << "total_avail " << byte_u_t(tstats.kb_avail << 10) |
7c673cae | 2414 | << std::endl; |
1adf2230 | 2415 | cout << "total_space " << byte_u_t(tstats.kb << 10) |
7c673cae FG |
2416 | << std::endl; |
2417 | } else { | |
2418 | formatter->close_section(); | |
2419 | formatter->dump_int("total_objects", tstats.num_objects); | |
2420 | formatter->dump_int("total_used", tstats.kb_used); | |
2421 | formatter->dump_int("total_avail", tstats.kb_avail); | |
2422 | formatter->dump_int("total_space", tstats.kb); | |
2423 | formatter->close_section(); | |
2424 | formatter->flush(cout); | |
2425 | } | |
2426 | } | |
2427 | ||
2428 | else if (strcmp(nargs[0], "ls") == 0) { | |
11fdf7f2 TL |
2429 | if (!pool_name && !pgid) { |
2430 | cerr << "either pool name or pg id needs to be specified" << std::endl; | |
2431 | return 1; | |
7c673cae FG |
2432 | } |
2433 | ||
f91f0fd5 | 2434 | if (wildcard) { |
7c673cae | 2435 | io_ctx.set_namespace(all_nspaces); |
f91f0fd5 | 2436 | } |
11fdf7f2 TL |
2437 | bool use_stdout = (!output && (nargs.size() < 2 || (strcmp(nargs[1], "-") == 0))); |
2438 | if (!use_stdout && !output) { | |
2439 | cerr << "Please use --output to specify the output file name" << std::endl; | |
2440 | return 1; | |
2441 | } | |
f91f0fd5 | 2442 | |
7c673cae | 2443 | ostream *outstream; |
f91f0fd5 | 2444 | if (use_stdout) { |
7c673cae | 2445 | outstream = &cout; |
f91f0fd5 | 2446 | } else { |
11fdf7f2 | 2447 | outstream = new ofstream(output); |
f91f0fd5 | 2448 | } |
7c673cae FG |
2449 | |
2450 | { | |
f91f0fd5 | 2451 | if (formatter) { |
7c673cae | 2452 | formatter->open_array_section("objects"); |
f91f0fd5 | 2453 | } |
7c673cae | 2454 | try { |
11fdf7f2 | 2455 | librados::NObjectIterator i = pgid ? io_ctx.nobjects_begin(pgid->ps()) : io_ctx.nobjects_begin(); |
f91f0fd5 | 2456 | const librados::NObjectIterator i_end = io_ctx.nobjects_end(); |
7c673cae | 2457 | for (; i != i_end; ++i) { |
11fdf7f2 | 2458 | #ifdef WITH_LIBRADOSSTRIPER |
7c673cae FG |
2459 | if (use_striper) { |
2460 | // in case of --striper option, we only list striped | |
2461 | // objects, so we only display the first object of | |
2462 | // each, without its suffix '.000...000' | |
2463 | size_t l = i->get_oid().length(); | |
2464 | if (l <= 17 || | |
f91f0fd5 TL |
2465 | (0 != i->get_oid().compare(l-17, 17,".0000000000000000"))) { |
2466 | continue; | |
2467 | } | |
7c673cae | 2468 | } |
11fdf7f2 TL |
2469 | #endif // WITH_LIBRADOSSTRIPER |
2470 | if (pgid) { | |
2471 | uint32_t ps; | |
f91f0fd5 | 2472 | if (io_ctx.get_object_pg_hash_position2(i->get_oid(), &ps) || pgid->ps() != ps) { |
11fdf7f2 | 2473 | break; |
f91f0fd5 | 2474 | } |
11fdf7f2 | 2475 | } |
7c673cae FG |
2476 | if (!formatter) { |
2477 | // Only include namespace in output when wildcard specified | |
f91f0fd5 | 2478 | if (wildcard) { |
7c673cae | 2479 | *outstream << i->get_nspace() << "\t"; |
f91f0fd5 TL |
2480 | } |
2481 | *outstream << detail::get_oid(i, use_striper); | |
2482 | if (i->get_locator().size()) { | |
7c673cae | 2483 | *outstream << "\t" << i->get_locator(); |
f91f0fd5 | 2484 | } |
7c673cae FG |
2485 | *outstream << std::endl; |
2486 | } else { | |
2487 | formatter->open_object_section("object"); | |
2488 | formatter->dump_string("namespace", i->get_nspace()); | |
11fdf7f2 | 2489 | |
f91f0fd5 | 2490 | detail::dump_name(formatter.get(), i, use_striper); |
11fdf7f2 | 2491 | |
f91f0fd5 | 2492 | if (i->get_locator().size()) { |
7c673cae | 2493 | formatter->dump_string("locator", i->get_locator()); |
f91f0fd5 | 2494 | } |
7c673cae | 2495 | formatter->close_section(); //object |
f91f0fd5 TL |
2496 | |
2497 | constexpr int TARGET_BYTES_PER_FLUSH = 4096; | |
2498 | if (formatter->get_len() >= TARGET_BYTES_PER_FLUSH) { | |
2499 | formatter->flush(*outstream); | |
2500 | } | |
7c673cae FG |
2501 | } |
2502 | } | |
2503 | } | |
f64942e4 | 2504 | catch (const std::exception& e) { |
7c673cae | 2505 | cerr << e.what() << std::endl; |
11fdf7f2 | 2506 | return 1; |
7c673cae FG |
2507 | } |
2508 | } | |
2509 | if (formatter) { | |
2510 | formatter->close_section(); //objects | |
2511 | formatter->flush(*outstream); | |
f91f0fd5 | 2512 | if (pretty_format) { |
7c673cae | 2513 | *outstream << std::endl; |
f91f0fd5 | 2514 | } |
7c673cae FG |
2515 | formatter->flush(*outstream); |
2516 | } | |
f91f0fd5 | 2517 | if (!stdout) { |
7c673cae | 2518 | delete outstream; |
f91f0fd5 | 2519 | } |
7c673cae | 2520 | } |
7c673cae | 2521 | else if (strcmp(nargs[0], "mapext") == 0) { |
f67539c2 | 2522 | if (!pool_name || (nargs.size() < 2 && !obj_name)) { |
11fdf7f2 TL |
2523 | usage(cerr); |
2524 | return 1; | |
2525 | } | |
f67539c2 TL |
2526 | if (!obj_name) { |
2527 | obj_name = nargs[1]; | |
2528 | } | |
7c673cae | 2529 | std::map<uint64_t,uint64_t> m; |
f67539c2 | 2530 | ret = io_ctx.mapext(*obj_name, 0, -1, m); |
7c673cae | 2531 | if (ret < 0) { |
f67539c2 | 2532 | cerr << "mapext error on " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 2533 | return 1; |
7c673cae FG |
2534 | } |
2535 | std::map<uint64_t,uint64_t>::iterator iter; | |
2536 | for (iter = m.begin(); iter != m.end(); ++iter) { | |
2537 | cout << hex << iter->first << "\t" << iter->second << dec << std::endl; | |
2538 | } | |
2539 | } | |
2540 | else if (strcmp(nargs[0], "stat") == 0) { | |
f67539c2 | 2541 | if (!pool_name || (nargs.size() < 2 && !obj_name)) { |
11fdf7f2 TL |
2542 | usage(cerr); |
2543 | return 1; | |
2544 | } | |
f67539c2 TL |
2545 | if (!obj_name) { |
2546 | obj_name = nargs[1]; | |
2547 | } | |
7c673cae FG |
2548 | uint64_t size; |
2549 | time_t mtime; | |
11fdf7f2 | 2550 | |
f67539c2 | 2551 | ret = detail::stat(io_ctx, *obj_name, size, mtime, use_striper); |
11fdf7f2 | 2552 | |
7c673cae | 2553 | if (ret < 0) { |
f67539c2 | 2554 | cerr << " error stat-ing " << pool_name << "/" << prettify(*obj_name) << ": " |
7c673cae | 2555 | << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 2556 | return 1; |
7c673cae FG |
2557 | } else { |
2558 | utime_t t(mtime, 0); | |
f67539c2 | 2559 | cout << pool_name << "/" << prettify(*obj_name) |
7c673cae FG |
2560 | << " mtime " << t << ", size " << size << std::endl; |
2561 | } | |
2562 | } | |
11fdf7f2 | 2563 | else if (strcmp(nargs[0], "stat2") == 0) { |
f67539c2 | 2564 | if (!pool_name || (nargs.size() < 2 && !obj_name)) { |
11fdf7f2 TL |
2565 | usage(cerr); |
2566 | return 1; | |
2567 | } | |
f67539c2 TL |
2568 | if (!obj_name) { |
2569 | obj_name = nargs[1]; | |
2570 | } | |
11fdf7f2 TL |
2571 | uint64_t size; |
2572 | struct timespec mtime; | |
2573 | ||
f67539c2 | 2574 | ret = detail::stat2(io_ctx, *obj_name, size, mtime, use_striper); |
11fdf7f2 TL |
2575 | |
2576 | if (ret < 0) { | |
f67539c2 | 2577 | cerr << " error stat-ing " << pool_name << "/" << prettify(*obj_name) << ": " |
11fdf7f2 TL |
2578 | << cpp_strerror(ret) << std::endl; |
2579 | return 1; | |
2580 | } else { | |
2581 | utime_t t(mtime); | |
f67539c2 | 2582 | cout << pool_name << "/" << prettify(*obj_name) |
11fdf7f2 TL |
2583 | << " mtime " << t << ", size " << size << std::endl; |
2584 | } | |
2585 | } | |
2586 | else if (strcmp(nargs[0], "touch") == 0) { | |
f67539c2 | 2587 | if (!pool_name || (nargs.size() < 2 && !obj_name)) { |
11fdf7f2 TL |
2588 | usage(cerr); |
2589 | return 1; | |
2590 | } | |
11fdf7f2 | 2591 | time_t timestamp = time(NULL); |
f67539c2 | 2592 | if (nargs.size() > (obj_name ? 1 : 2)) { |
11fdf7f2 | 2593 | char* endptr = NULL; |
f67539c2 | 2594 | timestamp = static_cast<time_t>(strtoll(nargs[obj_name ? 1 : 2], &endptr, 10)); |
11fdf7f2 | 2595 | if (*endptr) { |
f67539c2 | 2596 | cerr << "Invalid value for timestamp: '" << nargs[obj_name ? 1 : 2] << "'" << std::endl; |
11fdf7f2 TL |
2597 | ret = -EINVAL; |
2598 | return 1; | |
2599 | } | |
2600 | } | |
f67539c2 TL |
2601 | if (!obj_name) { |
2602 | obj_name = nargs[1]; | |
2603 | } | |
11fdf7f2 TL |
2604 | ObjectWriteOperation op; |
2605 | op.create(false); | |
2606 | op.mtime(×tamp); | |
f67539c2 | 2607 | ret = io_ctx.operate(*obj_name, &op); |
11fdf7f2 | 2608 | if (ret < 0) { |
f67539c2 | 2609 | cerr << " error touch-ing " << pool_name << "/" << prettify(*obj_name) << ": " |
11fdf7f2 TL |
2610 | << cpp_strerror(ret) << std::endl; |
2611 | return 1; | |
2612 | } | |
2613 | } | |
7c673cae | 2614 | else if (strcmp(nargs[0], "get") == 0) { |
f67539c2 | 2615 | if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) { |
11fdf7f2 TL |
2616 | usage(cerr); |
2617 | return 1; | |
2618 | } | |
f67539c2 TL |
2619 | const char* out_filename; |
2620 | if (obj_name) { | |
2621 | out_filename = nargs[1]; | |
2622 | } else { | |
2623 | obj_name = nargs[1]; | |
2624 | out_filename = nargs[2]; | |
2625 | } | |
2626 | ret = do_get(io_ctx, *obj_name, out_filename, op_size, use_striper); | |
7c673cae | 2627 | if (ret < 0) { |
f67539c2 | 2628 | cerr << "error getting " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 2629 | return 1; |
7c673cae FG |
2630 | } |
2631 | } | |
2632 | else if (strcmp(nargs[0], "put") == 0) { | |
f67539c2 | 2633 | if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) { |
11fdf7f2 TL |
2634 | usage(cerr); |
2635 | return 1; | |
2636 | } | |
f67539c2 TL |
2637 | const char* in_filename; |
2638 | if (obj_name) { | |
2639 | in_filename = nargs[1]; | |
2640 | } else { | |
2641 | obj_name = nargs[1]; | |
2642 | in_filename = nargs[2]; | |
2643 | } | |
9f95a23c | 2644 | bool create_object = !obj_offset_specified; |
f67539c2 | 2645 | ret = do_put(io_ctx, *obj_name, in_filename, op_size, obj_offset, create_object, use_striper); |
7c673cae | 2646 | if (ret < 0) { |
f67539c2 | 2647 | cerr << "error putting " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 2648 | return 1; |
7c673cae FG |
2649 | } |
2650 | } | |
2651 | else if (strcmp(nargs[0], "append") == 0) { | |
f67539c2 | 2652 | if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) { |
11fdf7f2 TL |
2653 | usage(cerr); |
2654 | return 1; | |
2655 | } | |
f67539c2 TL |
2656 | const char* in_filename; |
2657 | if (obj_name) { | |
2658 | in_filename = nargs[1]; | |
2659 | } else { | |
2660 | obj_name = nargs[1]; | |
2661 | in_filename = nargs[2]; | |
2662 | } | |
2663 | ret = do_append(io_ctx, *obj_name, in_filename, op_size, use_striper); | |
7c673cae | 2664 | if (ret < 0) { |
f67539c2 | 2665 | cerr << "error appending " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 2666 | return 1; |
7c673cae FG |
2667 | } |
2668 | } | |
2669 | else if (strcmp(nargs[0], "truncate") == 0) { | |
f67539c2 | 2670 | if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) { |
11fdf7f2 TL |
2671 | usage(cerr); |
2672 | return 1; | |
2673 | } | |
7c673cae | 2674 | |
7c673cae | 2675 | char* endptr = NULL; |
f67539c2 TL |
2676 | long size; |
2677 | if (!obj_name) { | |
2678 | obj_name = nargs[1]; | |
2679 | size = strtoll(nargs[2], &endptr, 10); | |
2680 | } else { | |
2681 | size = strtoll(nargs[1], &endptr, 10); | |
2682 | } | |
7c673cae FG |
2683 | if (*endptr) { |
2684 | cerr << "Invalid value for size: '" << nargs[2] << "'" << std::endl; | |
2685 | ret = -EINVAL; | |
11fdf7f2 | 2686 | return 1; |
7c673cae FG |
2687 | } |
2688 | if (size < 0) { | |
2689 | cerr << "error, cannot truncate to negative value" << std::endl; | |
11fdf7f2 TL |
2690 | usage(cerr); |
2691 | return 1; | |
7c673cae | 2692 | } |
11fdf7f2 | 2693 | |
f67539c2 | 2694 | ret = detail::trunc(io_ctx, *obj_name, size, use_striper); |
11fdf7f2 | 2695 | |
7c673cae FG |
2696 | if (ret < 0) { |
2697 | cerr << "error truncating oid " | |
f67539c2 | 2698 | << prettify(*obj_name) << " to " << size << ": " |
7c673cae FG |
2699 | << cpp_strerror(ret) << std::endl; |
2700 | } else { | |
2701 | ret = 0; | |
2702 | } | |
2703 | } | |
2704 | else if (strcmp(nargs[0], "setxattr") == 0) { | |
f67539c2 TL |
2705 | if (!pool_name || nargs.size() < (obj_name ? 2 : 3) || |
2706 | nargs.size() > (obj_name ? 3 : 4)) { | |
11fdf7f2 TL |
2707 | usage(cerr); |
2708 | return 1; | |
2709 | } | |
f67539c2 | 2710 | string attr_name(nargs[obj_name ? 1 : 2]); |
7c673cae | 2711 | bufferlist bl; |
f67539c2 TL |
2712 | if (nargs.size() == (obj_name ? 3 : 4)) { |
2713 | string attr_val(nargs[obj_name ? 2 : 3]); | |
7c673cae FG |
2714 | bl.append(attr_val.c_str(), attr_val.length()); |
2715 | } else { | |
2716 | do { | |
2717 | ret = bl.read_fd(STDIN_FILENO, 1024); // from stdin | |
2718 | if (ret < 0) | |
11fdf7f2 | 2719 | return 1; |
7c673cae FG |
2720 | } while (ret > 0); |
2721 | } | |
f67539c2 TL |
2722 | if (!obj_name) { |
2723 | obj_name = nargs[1]; | |
2724 | } | |
7c673cae | 2725 | |
f67539c2 | 2726 | ret = detail::setxattr(io_ctx, *obj_name, attr_name, bl, use_striper); |
11fdf7f2 | 2727 | |
7c673cae | 2728 | if (ret < 0) { |
f67539c2 | 2729 | cerr << "error setting xattr " << pool_name << "/" << prettify(*obj_name) << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 2730 | return 1; |
7c673cae FG |
2731 | } |
2732 | else | |
2733 | ret = 0; | |
2734 | } | |
2735 | else if (strcmp(nargs[0], "getxattr") == 0) { | |
f67539c2 | 2736 | if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) { |
11fdf7f2 TL |
2737 | usage(cerr); |
2738 | return 1; | |
2739 | } | |
f67539c2 TL |
2740 | string attr_name(nargs[obj_name ? 1 : 2]); |
2741 | if (!obj_name) { | |
2742 | obj_name = nargs[1]; | |
2743 | } | |
7c673cae | 2744 | bufferlist bl; |
f67539c2 | 2745 | ret = detail::getxattr(io_ctx, *obj_name, attr_name, bl, use_striper); |
11fdf7f2 | 2746 | |
7c673cae | 2747 | if (ret < 0) { |
f67539c2 | 2748 | cerr << "error getting xattr " << pool_name << "/" << prettify(*obj_name) << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 2749 | return 1; |
7c673cae FG |
2750 | } |
2751 | else | |
2752 | ret = 0; | |
2753 | string s(bl.c_str(), bl.length()); | |
2754 | cout << s; | |
2755 | } else if (strcmp(nargs[0], "rmxattr") == 0) { | |
f67539c2 | 2756 | if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) { |
11fdf7f2 TL |
2757 | usage(cerr); |
2758 | return 1; | |
2759 | } | |
7c673cae | 2760 | |
f67539c2 TL |
2761 | string attr_name(nargs[obj_name ? 1 : 2]); |
2762 | if (!obj_name) { | |
2763 | obj_name = nargs[1]; | |
2764 | } | |
2765 | ret = detail::rmxattr(io_ctx, *obj_name, attr_name, use_striper); | |
11fdf7f2 | 2766 | |
7c673cae | 2767 | if (ret < 0) { |
f67539c2 | 2768 | cerr << "error removing xattr " << pool_name << "/" << prettify(*obj_name) << "/" << attr_name << ": " << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 2769 | return 1; |
7c673cae FG |
2770 | } |
2771 | } else if (strcmp(nargs[0], "listxattr") == 0) { | |
f67539c2 | 2772 | if (!pool_name || (nargs.size() < 2 && !obj_name)) { |
11fdf7f2 TL |
2773 | usage(cerr); |
2774 | return 1; | |
2775 | } | |
f67539c2 TL |
2776 | if (!obj_name) { |
2777 | obj_name = nargs[1]; | |
2778 | } | |
7c673cae | 2779 | bufferlist bl; |
11fdf7f2 TL |
2780 | map<std::string, bufferlist> attrset; |
2781 | ||
f67539c2 | 2782 | ret = detail::getxattrs(io_ctx, *obj_name, attrset, use_striper); |
11fdf7f2 | 2783 | |
7c673cae | 2784 | if (ret < 0) { |
f67539c2 | 2785 | cerr << "error getting xattr set " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 2786 | return 1; |
7c673cae FG |
2787 | } |
2788 | ||
2789 | for (map<std::string, bufferlist>::iterator iter = attrset.begin(); | |
2790 | iter != attrset.end(); ++iter) { | |
2791 | cout << iter->first << std::endl; | |
2792 | } | |
2793 | } else if (strcmp(nargs[0], "getomapheader") == 0) { | |
f67539c2 | 2794 | if (!pool_name || (nargs.size() < 2 && !obj_name)) { |
11fdf7f2 TL |
2795 | usage(cerr); |
2796 | return 1; | |
2797 | } | |
7c673cae | 2798 | string outfile; |
f67539c2 TL |
2799 | if (nargs.size() >= (obj_name ? 2 : 3)) { |
2800 | outfile = nargs[obj_name ? 1 : 2]; | |
2801 | } | |
2802 | if (!obj_name) { | |
2803 | obj_name = nargs[1]; | |
7c673cae | 2804 | } |
7c673cae | 2805 | bufferlist header; |
f67539c2 | 2806 | ret = io_ctx.omap_get_header(*obj_name, &header); |
7c673cae | 2807 | if (ret < 0) { |
f67539c2 | 2808 | cerr << "error getting omap header " << pool_name << "/" << prettify(*obj_name) |
7c673cae | 2809 | << ": " << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 2810 | return 1; |
7c673cae FG |
2811 | } else { |
2812 | if (!outfile.empty()) { | |
2813 | cerr << "Writing to " << outfile << std::endl; | |
2814 | dump_data(outfile, header); | |
2815 | } else { | |
2816 | cout << "header (" << header.length() << " bytes) :\n"; | |
2817 | header.hexdump(cout); | |
2818 | cout << std::endl; | |
2819 | } | |
2820 | ret = 0; | |
2821 | } | |
2822 | } else if (strcmp(nargs[0], "setomapheader") == 0) { | |
f67539c2 | 2823 | if (!pool_name || nargs.size() < (obj_name ? 2 : 3)) { |
11fdf7f2 TL |
2824 | usage(cerr); |
2825 | return 1; | |
2826 | } | |
7c673cae | 2827 | |
7c673cae | 2828 | bufferlist bl; |
f67539c2 TL |
2829 | if (!obj_name) { |
2830 | obj_name = nargs[1]; | |
2831 | bl.append(nargs[2]); // val | |
2832 | } else { | |
2833 | bl.append(nargs[1]); // val | |
2834 | } | |
2835 | ret = io_ctx.omap_set_header(*obj_name, bl); | |
7c673cae | 2836 | if (ret < 0) { |
f67539c2 | 2837 | cerr << "error setting omap value " << pool_name << "/" << prettify(*obj_name) |
7c673cae | 2838 | << ": " << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 2839 | return 1; |
7c673cae FG |
2840 | } else { |
2841 | ret = 0; | |
2842 | } | |
2843 | } else if (strcmp(nargs[0], "setomapval") == 0) { | |
f67539c2 | 2844 | uint32_t min_args = (omap_key ? 2 : 3); |
7c673cae | 2845 | if (!pool_name || nargs.size() < min_args || nargs.size() > min_args + 1) { |
11fdf7f2 TL |
2846 | usage(cerr); |
2847 | return 1; | |
7c673cae FG |
2848 | } |
2849 | ||
2850 | string oid(nargs[1]); | |
f67539c2 | 2851 | if (!omap_key) { |
7c673cae | 2852 | omap_key = nargs[2]; |
7c673cae FG |
2853 | } |
2854 | ||
2855 | bufferlist bl; | |
f67539c2 TL |
2856 | if (!input_file.empty()) { |
2857 | string err; | |
2858 | ret = bl.read_file(input_file.c_str(), &err); | |
2859 | if (ret < 0) { | |
2860 | cerr << "error reading file " << input_file.c_str() << ": " << err << std::endl; | |
2861 | return 1; | |
2862 | } | |
2863 | } else if (nargs.size() > min_args) { | |
7c673cae FG |
2864 | string val(nargs[min_args]); |
2865 | bl.append(val); | |
2866 | } else { | |
2867 | do { | |
2868 | ret = bl.read_fd(STDIN_FILENO, 1024); // from stdin | |
2869 | if (ret < 0) { | |
11fdf7f2 | 2870 | return 1; |
7c673cae FG |
2871 | } |
2872 | } while (ret > 0); | |
2873 | } | |
2874 | ||
2875 | map<string, bufferlist> values; | |
f67539c2 | 2876 | values[*omap_key] = bl; |
7c673cae FG |
2877 | |
2878 | ret = io_ctx.omap_set(oid, values); | |
2879 | if (ret < 0) { | |
2880 | cerr << "error setting omap value " << pool_name << "/" << oid << "/" | |
f67539c2 | 2881 | << prettify(*omap_key) << ": " << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 2882 | return 1; |
7c673cae FG |
2883 | } else { |
2884 | ret = 0; | |
2885 | } | |
2886 | } else if (strcmp(nargs[0], "getomapval") == 0) { | |
f67539c2 TL |
2887 | uint32_t min_args = (omap_key ? (obj_name ? 1 : 2) |
2888 | : (obj_name ? 2 : 3)); | |
7c673cae | 2889 | if (!pool_name || nargs.size() < min_args || nargs.size() > min_args + 1) { |
11fdf7f2 TL |
2890 | usage(cerr); |
2891 | return 1; | |
7c673cae FG |
2892 | } |
2893 | ||
f67539c2 TL |
2894 | if (!omap_key) { |
2895 | omap_key = nargs[obj_name ? 1 : 2]; | |
7c673cae FG |
2896 | } |
2897 | ||
2898 | set<string> keys; | |
f67539c2 | 2899 | keys.insert(*omap_key); |
7c673cae FG |
2900 | |
2901 | std::string outfile; | |
2902 | if (nargs.size() > min_args) { | |
2903 | outfile = nargs[min_args]; | |
2904 | } | |
f67539c2 TL |
2905 | if (!obj_name) { |
2906 | obj_name = nargs[1]; | |
2907 | } | |
7c673cae FG |
2908 | |
2909 | map<string, bufferlist> values; | |
f67539c2 | 2910 | ret = io_ctx.omap_get_vals_by_keys(*obj_name, keys, &values); |
7c673cae | 2911 | if (ret < 0) { |
f67539c2 TL |
2912 | cerr << "error getting omap value " << pool_name << "/" << prettify(*obj_name) << "/" |
2913 | << prettify(*omap_key) << ": " << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 2914 | return 1; |
7c673cae FG |
2915 | } else { |
2916 | ret = 0; | |
2917 | } | |
2918 | ||
f67539c2 | 2919 | if (values.size() && values.begin()->first == *omap_key) { |
7c673cae FG |
2920 | if (!outfile.empty()) { |
2921 | cerr << "Writing to " << outfile << std::endl; | |
2922 | dump_data(outfile, values.begin()->second); | |
2923 | } else { | |
2924 | cout << "value (" << values.begin()->second.length() << " bytes) :\n"; | |
2925 | values.begin()->second.hexdump(cout); | |
2926 | cout << std::endl; | |
2927 | } | |
2928 | ret = 0; | |
2929 | } else { | |
f67539c2 TL |
2930 | cout << "No such key: " << pool_name << "/" << prettify(*obj_name) << "/" |
2931 | << prettify(*omap_key) << std::endl; | |
11fdf7f2 | 2932 | return 1; |
7c673cae FG |
2933 | } |
2934 | } else if (strcmp(nargs[0], "rmomapkey") == 0) { | |
f67539c2 TL |
2935 | uint32_t num_args = (omap_key ? (obj_name ? 1 : 2) |
2936 | : (obj_name ? 2 : 3)); | |
7c673cae | 2937 | if (!pool_name || nargs.size() != num_args) { |
11fdf7f2 TL |
2938 | usage(cerr); |
2939 | return 1; | |
7c673cae FG |
2940 | } |
2941 | ||
f67539c2 TL |
2942 | if (!omap_key) { |
2943 | omap_key = nargs[obj_name ? 1 : 2]; | |
2944 | } | |
2945 | if (!obj_name) { | |
2946 | obj_name = nargs[1]; | |
7c673cae FG |
2947 | } |
2948 | set<string> keys; | |
f67539c2 | 2949 | keys.insert(*omap_key); |
7c673cae | 2950 | |
f67539c2 | 2951 | ret = io_ctx.omap_rm_keys(*obj_name, keys); |
7c673cae | 2952 | if (ret < 0) { |
f67539c2 TL |
2953 | cerr << "error removing omap key " << pool_name << "/" << prettify(*obj_name) << "/" |
2954 | << prettify(*omap_key) << ": " << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 2955 | return 1; |
7c673cae FG |
2956 | } else { |
2957 | ret = 0; | |
2958 | } | |
11fdf7f2 | 2959 | } else if (strcmp(nargs[0], "clearomap") == 0) { |
f67539c2 | 2960 | if (!pool_name || (nargs.size() < 2 && !obj_name)) { |
11fdf7f2 TL |
2961 | usage(cerr); |
2962 | return 1; | |
2963 | } | |
f67539c2 TL |
2964 | // strip nargs[0] which is "clearomap" |
2965 | std::vector<std::string> oids(std::next(std::begin(nargs)), | |
2966 | std::end(nargs)); | |
2967 | if (obj_name) { | |
2968 | oids.push_back(*obj_name); | |
2969 | } | |
11fdf7f2 | 2970 | |
f67539c2 | 2971 | for (const auto& oid : oids) { |
11fdf7f2 TL |
2972 | ret = io_ctx.omap_clear(oid); |
2973 | if (ret < 0) { | |
f67539c2 | 2974 | cerr << "error clearing omap keys " << pool_name << "/" << prettify(*obj_name) << "/" |
11fdf7f2 TL |
2975 | << cpp_strerror(ret) << std::endl; |
2976 | return 1; | |
2977 | } | |
2978 | } | |
2979 | ret = 0; | |
7c673cae | 2980 | } else if (strcmp(nargs[0], "listomapvals") == 0) { |
f67539c2 | 2981 | if (!pool_name || (nargs.size() < 2 && !obj_name)) { |
11fdf7f2 TL |
2982 | usage(cerr); |
2983 | return 1; | |
2984 | } | |
f67539c2 TL |
2985 | if (!obj_name) { |
2986 | obj_name = nargs[1]; | |
2987 | } | |
7c673cae | 2988 | string last_read = ""; |
7c673cae FG |
2989 | do { |
2990 | map<string, bufferlist> values; | |
f67539c2 | 2991 | ret = io_ctx.omap_get_vals(*obj_name, last_read, MAX_OMAP_BYTES_PER_REQUEST, &values); |
7c673cae | 2992 | if (ret < 0) { |
f67539c2 | 2993 | cerr << "error getting omap keys " << pool_name << "/" << prettify(*obj_name) << ": " |
7c673cae FG |
2994 | << cpp_strerror(ret) << std::endl; |
2995 | return 1; | |
2996 | } | |
2997 | ret = values.size(); | |
2998 | for (map<string, bufferlist>::const_iterator it = values.begin(); | |
2999 | it != values.end(); ++it) { | |
3000 | last_read = it->first; | |
3001 | // dump key in hex if it contains nonprintable characters | |
3002 | if (std::count_if(it->first.begin(), it->first.end(), | |
3003 | (int (*)(int))isprint) < (int)it->first.length()) { | |
3004 | cout << "key (" << it->first.length() << " bytes):\n"; | |
3005 | bufferlist keybl; | |
3006 | keybl.append(it->first); | |
3007 | keybl.hexdump(cout); | |
3008 | } else { | |
3009 | cout << it->first; | |
3010 | } | |
3011 | cout << std::endl; | |
3012 | cout << "value (" << it->second.length() << " bytes) :\n"; | |
3013 | it->second.hexdump(cout); | |
3014 | cout << std::endl; | |
3015 | } | |
9f95a23c | 3016 | } while (ret == MAX_OMAP_BYTES_PER_REQUEST); |
7c673cae FG |
3017 | ret = 0; |
3018 | } | |
3019 | else if (strcmp(nargs[0], "cp") == 0) { | |
f67539c2 | 3020 | // XXX: binary names aren't supported for this operation |
11fdf7f2 TL |
3021 | if (!pool_name) { |
3022 | usage(cerr); | |
3023 | return 1; | |
3024 | } | |
7c673cae | 3025 | |
11fdf7f2 TL |
3026 | if (nargs.size() < 2 || nargs.size() > 3) { |
3027 | usage(cerr); | |
3028 | return 1; | |
3029 | } | |
7c673cae FG |
3030 | |
3031 | const char *target = target_pool_name; | |
3032 | if (!target) | |
3033 | target = pool_name; | |
3034 | ||
3035 | const char *target_obj; | |
3036 | if (nargs.size() < 3) { | |
3037 | if (strcmp(target, pool_name) == 0) { | |
3038 | cerr << "cannot copy object into itself" << std::endl; | |
11fdf7f2 | 3039 | return 1; |
7c673cae FG |
3040 | } |
3041 | target_obj = nargs[1]; | |
3042 | } else { | |
3043 | target_obj = nargs[2]; | |
3044 | } | |
3045 | ||
3046 | // open io context. | |
3047 | IoCtx target_ctx; | |
3048 | ret = rados.ioctx_create(target, target_ctx); | |
3049 | if (ret < 0) { | |
3050 | cerr << "error opening target pool " << target << ": " | |
3051 | << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 3052 | return 1; |
7c673cae FG |
3053 | } |
3054 | if (target_oloc.size()) { | |
3055 | target_ctx.locator_set_key(target_oloc); | |
3056 | } | |
3057 | if (target_nspace.size()) { | |
3058 | target_ctx.set_namespace(target_nspace); | |
3059 | } | |
3060 | ||
3061 | ret = do_copy(io_ctx, nargs[1], target_ctx, target_obj); | |
3062 | if (ret < 0) { | |
3063 | cerr << "error copying " << pool_name << "/" << nargs[1] << " => " << target << "/" << target_obj << ": " << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 3064 | return 1; |
7c673cae FG |
3065 | } |
3066 | } else if (strcmp(nargs[0], "rm") == 0) { | |
f67539c2 | 3067 | if (!pool_name || (nargs.size() < 2 && !obj_name)) { |
11fdf7f2 TL |
3068 | usage(cerr); |
3069 | return 1; | |
3070 | } | |
f67539c2 TL |
3071 | // strip nargs[0] which is "rm" |
3072 | std::vector<std::string> oids(std::next(std::begin(nargs)), | |
3073 | std::end(nargs)); | |
3074 | if (obj_name) { | |
3075 | oids.push_back(*obj_name); | |
11fdf7f2 | 3076 | } |
f67539c2 TL |
3077 | for (const auto& oid : oids) { |
3078 | if (forcefull) { | |
3079 | ret = detail::remove(io_ctx, oid, (CEPH_OSD_FLAG_FULL_FORCE | | |
3080 | CEPH_OSD_FLAG_FULL_TRY), use_striper); | |
3081 | } else { | |
3082 | ret = detail::remove(io_ctx, oid, use_striper); | |
3083 | } | |
11fdf7f2 | 3084 | |
f67539c2 TL |
3085 | if (ret < 0) { |
3086 | string name = (nspace.size() ? nspace + "/" : "" ) + prettify(oid); | |
3087 | cerr << "error removing " << pool_name << ">" << name << ": " << cpp_strerror(ret) << std::endl; | |
3088 | return 1; | |
7c673cae FG |
3089 | } |
3090 | } | |
3091 | } | |
3092 | else if (strcmp(nargs[0], "create") == 0) { | |
f67539c2 | 3093 | if (!pool_name || (nargs.size() < 2 && !obj_name)) { |
11fdf7f2 TL |
3094 | usage(cerr); |
3095 | return 1; | |
3096 | } | |
f67539c2 TL |
3097 | if (!obj_name) { |
3098 | obj_name = nargs[1]; | |
3099 | } | |
3100 | ret = io_ctx.create(*obj_name, true); | |
7c673cae | 3101 | if (ret < 0) { |
f67539c2 | 3102 | cerr << "error creating " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 3103 | return 1; |
7c673cae | 3104 | } |
7c673cae FG |
3105 | } |
3106 | else if (strcmp(nargs[0], "cppool") == 0) { | |
3107 | bool force = nargs.size() == 4 && !strcmp(nargs[3], "--yes-i-really-mean-it"); | |
11fdf7f2 TL |
3108 | if (nargs.size() != 3 && !(nargs.size() == 4 && force)) { |
3109 | usage(cerr); | |
3110 | return 1; | |
3111 | } | |
7c673cae FG |
3112 | const char *src_pool = nargs[1]; |
3113 | const char *target_pool = nargs[2]; | |
3114 | ||
3115 | if (strcmp(src_pool, target_pool) == 0) { | |
3116 | cerr << "cannot copy pool into itself" << std::endl; | |
11fdf7f2 | 3117 | return 1; |
7c673cae FG |
3118 | } |
3119 | ||
3120 | cerr << "WARNING: pool copy does not preserve user_version, which some " | |
1e59de90 | 3121 | << "apps may rely on." << std::endl; |
7c673cae FG |
3122 | |
3123 | if (rados.get_pool_is_selfmanaged_snaps_mode(src_pool)) { | |
3124 | cerr << "WARNING: pool " << src_pool << " has selfmanaged snaps, which are not preserved\n" | |
3125 | << " by the cppool operation. This will break any snapshot user." | |
3126 | << std::endl; | |
3127 | if (!force) { | |
3128 | cerr << " If you insist on making a broken copy, you can pass\n" | |
3129 | << " --yes-i-really-mean-it to proceed anyway." | |
3130 | << std::endl; | |
3131 | exit(1); | |
3132 | } | |
3133 | } | |
3134 | ||
3135 | ret = do_copy_pool(rados, src_pool, target_pool); | |
3136 | if (ret < 0) { | |
3137 | cerr << "error copying pool " << src_pool << " => " << target_pool << ": " | |
3138 | << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 3139 | return 1; |
7c673cae FG |
3140 | } |
3141 | cout << "successfully copied pool " << nargs[1] << std::endl; | |
3142 | } | |
7c673cae | 3143 | else if (strcmp(nargs[0], "purge") == 0) { |
11fdf7f2 TL |
3144 | if (nargs.size() < 2) { |
3145 | usage(cerr); | |
3146 | return 1; | |
3147 | } | |
7c673cae FG |
3148 | if (nargs.size() < 3 || |
3149 | strcmp(nargs[2], "--yes-i-really-really-mean-it") != 0) { | |
3150 | cerr << "WARNING:\n" | |
3151 | << " This will PERMANENTLY DESTROY all objects from a pool with no way back.\n" | |
3152 | << " To confirm, follow pool with --yes-i-really-really-mean-it" << std::endl; | |
11fdf7f2 | 3153 | return 1; |
7c673cae FG |
3154 | } |
3155 | ret = rados.ioctx_create(nargs[1], io_ctx); | |
3156 | if (ret < 0) { | |
3157 | cerr << "error pool " << nargs[1] << ": " | |
3158 | << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 3159 | return 1; |
7c673cae FG |
3160 | } |
3161 | io_ctx.set_namespace(all_nspaces); | |
9f95a23c | 3162 | io_ctx.set_pool_full_try(); |
7c673cae FG |
3163 | RadosBencher bencher(g_ceph_context, rados, io_ctx); |
3164 | ret = bencher.clean_up_slow("", concurrent_ios); | |
3165 | if (ret >= 0) { | |
3166 | cout << "successfully purged pool " << nargs[1] << std::endl; | |
3167 | } else { //error | |
3168 | cerr << "pool " << nargs[1] << " could not be purged" << std::endl; | |
3169 | cerr << "Check your monitor configuration - `mon allow pool delete` is set to false by default," | |
3170 | << " change it to true to allow deletion of pools" << std::endl; | |
3171 | } | |
3172 | } | |
3173 | else if (strcmp(nargs[0], "lssnap") == 0) { | |
11fdf7f2 TL |
3174 | if (!pool_name || nargs.size() != 1) { |
3175 | usage(cerr); | |
3176 | return 1; | |
3177 | } | |
7c673cae FG |
3178 | |
3179 | vector<snap_t> snaps; | |
3180 | io_ctx.snap_list(&snaps); | |
3181 | for (vector<snap_t>::iterator i = snaps.begin(); | |
3182 | i != snaps.end(); | |
3183 | ++i) { | |
3184 | string s; | |
3185 | time_t t; | |
3186 | if (io_ctx.snap_get_name(*i, &s) < 0) | |
3187 | continue; | |
3188 | if (io_ctx.snap_get_stamp(*i, &t) < 0) | |
3189 | continue; | |
3190 | struct tm bdt; | |
3191 | localtime_r(&t, &bdt); | |
3192 | cout << *i << "\t" << s << "\t"; | |
3193 | ||
3194 | std::ios_base::fmtflags original_flags = cout.flags(); | |
3195 | cout.setf(std::ios::right); | |
3196 | cout.fill('0'); | |
3197 | cout << std::setw(4) << (bdt.tm_year+1900) | |
3198 | << '.' << std::setw(2) << (bdt.tm_mon+1) | |
3199 | << '.' << std::setw(2) << bdt.tm_mday | |
3200 | << ' ' | |
3201 | << std::setw(2) << bdt.tm_hour | |
3202 | << ':' << std::setw(2) << bdt.tm_min | |
3203 | << ':' << std::setw(2) << bdt.tm_sec | |
3204 | << std::endl; | |
3205 | cout.flags(original_flags); | |
3206 | } | |
3207 | cout << snaps.size() << " snaps" << std::endl; | |
3208 | } | |
3209 | ||
3210 | else if (strcmp(nargs[0], "mksnap") == 0) { | |
11fdf7f2 TL |
3211 | if (!pool_name || nargs.size() < 2) { |
3212 | usage(cerr); | |
3213 | return 1; | |
3214 | } | |
3215 | ||
3216 | if (rados.get_pool_is_selfmanaged_snaps_mode(pool_name)) { | |
3217 | cerr << "can't create snapshot: pool " << pool_name | |
3218 | << " is in selfmanaged snaps mode" << std::endl; | |
3219 | return 1; | |
3220 | } | |
7c673cae FG |
3221 | |
3222 | ret = io_ctx.snap_create(nargs[1]); | |
3223 | if (ret < 0) { | |
3224 | cerr << "error creating pool " << pool_name << " snapshot " << nargs[1] | |
3225 | << ": " << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 3226 | return 1; |
7c673cae FG |
3227 | } |
3228 | cout << "created pool " << pool_name << " snap " << nargs[1] << std::endl; | |
3229 | } | |
3230 | ||
3231 | else if (strcmp(nargs[0], "rmsnap") == 0) { | |
11fdf7f2 TL |
3232 | if (!pool_name || nargs.size() < 2) { |
3233 | usage(cerr); | |
3234 | return 1; | |
3235 | } | |
7c673cae FG |
3236 | |
3237 | ret = io_ctx.snap_remove(nargs[1]); | |
3238 | if (ret < 0) { | |
3239 | cerr << "error removing pool " << pool_name << " snapshot " << nargs[1] | |
3240 | << ": " << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 3241 | return 1; |
7c673cae FG |
3242 | } |
3243 | cout << "removed pool " << pool_name << " snap " << nargs[1] << std::endl; | |
3244 | } | |
3245 | ||
3246 | else if (strcmp(nargs[0], "rollback") == 0) { | |
11fdf7f2 TL |
3247 | if (!pool_name || nargs.size() < 3) { |
3248 | usage(cerr); | |
3249 | return 1; | |
3250 | } | |
7c673cae FG |
3251 | |
3252 | ret = io_ctx.snap_rollback(nargs[1], nargs[2]); | |
3253 | if (ret < 0) { | |
3254 | cerr << "error rolling back pool " << pool_name << " to snapshot " << nargs[1] | |
3255 | << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 3256 | return 1; |
7c673cae FG |
3257 | } |
3258 | cout << "rolled back pool " << pool_name | |
3259 | << " to snapshot " << nargs[2] << std::endl; | |
3260 | } | |
3261 | else if (strcmp(nargs[0], "bench") == 0) { | |
11fdf7f2 TL |
3262 | if (!pool_name || nargs.size() < 3) { |
3263 | usage(cerr); | |
3264 | return 1; | |
3265 | } | |
7c673cae FG |
3266 | char* endptr = NULL; |
3267 | int seconds = strtol(nargs[1], &endptr, 10); | |
3268 | if (*endptr) { | |
3269 | cerr << "Invalid value for seconds: '" << nargs[1] << "'" << std::endl; | |
11fdf7f2 | 3270 | return 1; |
7c673cae FG |
3271 | } |
3272 | int operation = 0; | |
3273 | if (strcmp(nargs[2], "write") == 0) | |
3274 | operation = OP_WRITE; | |
3275 | else if (strcmp(nargs[2], "seq") == 0) | |
3276 | operation = OP_SEQ_READ; | |
3277 | else if (strcmp(nargs[2], "rand") == 0) | |
3278 | operation = OP_RAND_READ; | |
11fdf7f2 TL |
3279 | else { |
3280 | usage(cerr); | |
3281 | return 1; | |
3282 | } | |
7c673cae FG |
3283 | if (operation != OP_WRITE) { |
3284 | if (block_size_specified) { | |
224ce89b | 3285 | cerr << "-b|--block_size option can be used only with 'write' bench test" |
7c673cae | 3286 | << std::endl; |
11fdf7f2 | 3287 | return 1; |
7c673cae FG |
3288 | } |
3289 | if (bench_write_dest != 0) { | |
3290 | cerr << "--write-object, --write-omap and --write-xattr options can " | |
3291 | "only be used with the 'write' bench test" | |
3292 | << std::endl; | |
11fdf7f2 | 3293 | return 1; |
7c673cae FG |
3294 | } |
3295 | } | |
3296 | else if (bench_write_dest == 0) { | |
3297 | bench_write_dest = OP_WRITE_DEST_OBJ; | |
3298 | } | |
3299 | ||
3300 | if (!formatter && output) { | |
224ce89b | 3301 | cerr << "-o|--output option can only be used with '--format' option" |
7c673cae | 3302 | << std::endl; |
11fdf7f2 | 3303 | return 1; |
7c673cae FG |
3304 | } |
3305 | RadosBencher bencher(g_ceph_context, rados, io_ctx); | |
3306 | bencher.set_show_time(show_time); | |
3307 | bencher.set_write_destination(static_cast<OpWriteDest>(bench_write_dest)); | |
3308 | ||
3309 | ostream *outstream = NULL; | |
3310 | if (formatter) { | |
11fdf7f2 | 3311 | bencher.set_formatter(formatter.get()); |
7c673cae FG |
3312 | if (output) |
3313 | outstream = new ofstream(output); | |
3314 | else | |
3315 | outstream = &cout; | |
3316 | bencher.set_outstream(*outstream); | |
3317 | } | |
3318 | if (!object_size) | |
3319 | object_size = op_size; | |
3320 | else if (object_size < op_size) | |
3321 | op_size = object_size; | |
3322 | cout << "hints = " << (int)hints << std::endl; | |
3323 | ret = bencher.aio_bench(operation, seconds, | |
3324 | concurrent_ios, op_size, object_size, | |
11fdf7f2 | 3325 | max_objects, cleanup, hints, run_name, reuse_bench, no_verify); |
7c673cae | 3326 | if (ret != 0) |
224ce89b | 3327 | cerr << "error during benchmark: " << cpp_strerror(ret) << std::endl; |
7c673cae FG |
3328 | if (formatter && output) |
3329 | delete outstream; | |
3330 | } | |
3331 | else if (strcmp(nargs[0], "cleanup") == 0) { | |
11fdf7f2 TL |
3332 | if (!pool_name) { |
3333 | usage(cerr); | |
3334 | return 1; | |
3335 | } | |
7c673cae FG |
3336 | if (wildcard) |
3337 | io_ctx.set_namespace(all_nspaces); | |
3338 | RadosBencher bencher(g_ceph_context, rados, io_ctx); | |
3339 | ret = bencher.clean_up(prefix, concurrent_ios, run_name); | |
3340 | if (ret != 0) | |
224ce89b | 3341 | cerr << "error during cleanup: " << cpp_strerror(ret) << std::endl; |
7c673cae FG |
3342 | } |
3343 | else if (strcmp(nargs[0], "watch") == 0) { | |
11fdf7f2 TL |
3344 | if (!pool_name || nargs.size() < 2) { |
3345 | usage(cerr); | |
3346 | return 1; | |
3347 | } | |
7c673cae FG |
3348 | string oid(nargs[1]); |
3349 | RadosWatchCtx ctx(io_ctx, oid.c_str()); | |
3350 | uint64_t cookie; | |
3351 | ret = io_ctx.watch2(oid, &cookie, &ctx); | |
3352 | if (ret != 0) | |
224ce89b | 3353 | cerr << "error calling watch: " << cpp_strerror(ret) << std::endl; |
7c673cae FG |
3354 | else { |
3355 | cout << "press enter to exit..." << std::endl; | |
3356 | getchar(); | |
3357 | io_ctx.unwatch2(cookie); | |
3358 | rados.watch_flush(); | |
3359 | } | |
3360 | } | |
3361 | else if (strcmp(nargs[0], "notify") == 0) { | |
11fdf7f2 TL |
3362 | if (!pool_name || nargs.size() < 3) { |
3363 | usage(cerr); | |
3364 | return 1; | |
3365 | } | |
7c673cae FG |
3366 | string oid(nargs[1]); |
3367 | string msg(nargs[2]); | |
3368 | bufferlist bl, replybl; | |
11fdf7f2 | 3369 | encode(msg, bl); |
7c673cae FG |
3370 | ret = io_ctx.notify2(oid, bl, 10000, &replybl); |
3371 | if (ret != 0) | |
224ce89b | 3372 | cerr << "error calling notify: " << cpp_strerror(ret) << std::endl; |
7c673cae FG |
3373 | if (replybl.length()) { |
3374 | map<pair<uint64_t,uint64_t>,bufferlist> rm; | |
3375 | set<pair<uint64_t,uint64_t> > missed; | |
11fdf7f2 TL |
3376 | auto p = replybl.cbegin(); |
3377 | decode(rm, p); | |
3378 | decode(missed, p); | |
7c673cae FG |
3379 | for (map<pair<uint64_t,uint64_t>,bufferlist>::iterator p = rm.begin(); |
3380 | p != rm.end(); | |
3381 | ++p) { | |
3382 | cout << "reply client." << p->first.first | |
3383 | << " cookie " << p->first.second | |
3384 | << " : " << p->second.length() << " bytes" << std::endl; | |
3385 | if (p->second.length()) | |
3386 | p->second.hexdump(cout); | |
3387 | } | |
3388 | for (multiset<pair<uint64_t,uint64_t> >::iterator p = missed.begin(); | |
3389 | p != missed.end(); ++p) { | |
3390 | cout << "timeout client." << p->first | |
3391 | << " cookie " << p->second << std::endl; | |
3392 | } | |
3393 | } | |
3394 | } else if (strcmp(nargs[0], "set-alloc-hint") == 0) { | |
f67539c2 TL |
3395 | // cmd, [oid, ] obj_size, write_size |
3396 | if (!pool_name || nargs.size() < (obj_name ? 3 : 4)) { | |
11fdf7f2 TL |
3397 | usage(cerr); |
3398 | return 1; | |
3399 | } | |
7c673cae | 3400 | string err; |
f67539c2 | 3401 | uint64_t expected_object_size = strict_strtoll(nargs[obj_name ? 1 : 2], 10, &err); |
7c673cae FG |
3402 | if (!err.empty()) { |
3403 | cerr << "couldn't parse expected_object_size: " << err << std::endl; | |
11fdf7f2 TL |
3404 | usage(cerr); |
3405 | return 1; | |
7c673cae | 3406 | } |
f67539c2 | 3407 | uint64_t expected_write_size = strict_strtoll(nargs[obj_name ? 2 : 3], 10, &err); |
7c673cae FG |
3408 | if (!err.empty()) { |
3409 | cerr << "couldn't parse expected_write_size: " << err << std::endl; | |
11fdf7f2 TL |
3410 | usage(cerr); |
3411 | return 1; | |
7c673cae | 3412 | } |
f67539c2 TL |
3413 | if (!obj_name) { |
3414 | obj_name = nargs[1]; | |
3415 | } | |
3416 | ret = io_ctx.set_alloc_hint(*obj_name, expected_object_size, expected_write_size); | |
7c673cae | 3417 | if (ret < 0) { |
f67539c2 | 3418 | cerr << "error setting alloc-hint " << pool_name << "/" << prettify(*obj_name) << ": " |
7c673cae | 3419 | << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 3420 | return 1; |
7c673cae FG |
3421 | } |
3422 | } else if (strcmp(nargs[0], "load-gen") == 0) { | |
3423 | if (!pool_name) { | |
3424 | cerr << "error: must specify pool" << std::endl; | |
11fdf7f2 TL |
3425 | usage(cerr); |
3426 | return 1; | |
7c673cae FG |
3427 | } |
3428 | LoadGen lg(&rados); | |
3429 | if (min_obj_len) | |
3430 | lg.min_obj_len = min_obj_len; | |
3431 | if (max_obj_len) | |
3432 | lg.max_obj_len = max_obj_len; | |
3433 | if (min_op_len) | |
3434 | lg.min_op_len = min_op_len; | |
3435 | if (max_op_len) | |
3436 | lg.max_op_len = max_op_len; | |
3437 | if (max_ops) | |
3438 | lg.max_ops = max_ops; | |
3439 | if (max_backlog) | |
3440 | lg.max_backlog = max_backlog; | |
3441 | if (target_throughput) | |
11fdf7f2 | 3442 | lg.target_throughput = target_throughput; |
7c673cae FG |
3443 | if (read_percent >= 0) |
3444 | lg.read_percent = read_percent; | |
3445 | if (num_objs) | |
3446 | lg.num_objs = num_objs; | |
3447 | if (run_length) | |
3448 | lg.run_length = run_length; | |
11fdf7f2 TL |
3449 | if (offset_align) |
3450 | lg.offset_align = offset_align; | |
7c673cae FG |
3451 | |
3452 | cout << "run length " << run_length << " seconds" << std::endl; | |
3453 | cout << "preparing " << lg.num_objs << " objects" << std::endl; | |
3454 | ret = lg.bootstrap(pool_name); | |
3455 | if (ret < 0) { | |
3456 | cerr << "load-gen bootstrap failed" << std::endl; | |
11fdf7f2 | 3457 | return 1; |
7c673cae FG |
3458 | } |
3459 | cout << "load-gen will run " << lg.run_length << " seconds" << std::endl; | |
3460 | lg.run(); | |
3461 | lg.cleanup(); | |
3462 | } else if (strcmp(nargs[0], "listomapkeys") == 0) { | |
f67539c2 | 3463 | if (!pool_name || (nargs.size() < 2 && !obj_name)) { |
11fdf7f2 TL |
3464 | usage(cerr); |
3465 | return 1; | |
3466 | } | |
f67539c2 TL |
3467 | if (!obj_name) { |
3468 | obj_name = nargs[1]; | |
3469 | } | |
9f95a23c TL |
3470 | string last_read; |
3471 | bool more = true; | |
3472 | do { | |
3473 | set<string> out_keys; | |
f67539c2 | 3474 | ret = io_ctx.omap_get_keys2(*obj_name, last_read, MAX_OMAP_BYTES_PER_REQUEST, &out_keys, &more); |
9f95a23c TL |
3475 | if (ret < 0) { |
3476 | cerr << "error getting omap key set " << pool_name << "/" | |
f67539c2 | 3477 | << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl; |
9f95a23c TL |
3478 | return 1; |
3479 | } | |
7c673cae | 3480 | |
9f95a23c TL |
3481 | for (auto &key : out_keys) { |
3482 | cout << key << std::endl; | |
3483 | last_read = std::move(key); | |
3484 | } | |
3485 | } while (more); | |
7c673cae | 3486 | } else if (strcmp(nargs[0], "lock") == 0) { |
11fdf7f2 TL |
3487 | if (!pool_name) { |
3488 | usage(cerr); | |
3489 | return 1; | |
3490 | } | |
7c673cae FG |
3491 | |
3492 | if (!formatter) { | |
11fdf7f2 | 3493 | formatter = std::make_unique<JSONFormatter>(pretty_format); |
7c673cae | 3494 | } |
11fdf7f2 | 3495 | ret = do_lock_cmd(nargs, opts, &io_ctx, formatter.get()); |
7c673cae | 3496 | } else if (strcmp(nargs[0], "listwatchers") == 0) { |
11fdf7f2 TL |
3497 | if (!pool_name || nargs.size() < 2) { |
3498 | usage(cerr); | |
3499 | return 1; | |
3500 | } | |
7c673cae FG |
3501 | |
3502 | string oid(nargs[1]); | |
3503 | std::list<obj_watch_t> lw; | |
3504 | ||
3505 | ret = io_ctx.list_watchers(oid, &lw); | |
3506 | if (ret < 0) { | |
3507 | cerr << "error listing watchers " << pool_name << "/" << oid << ": " << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 3508 | return 1; |
7c673cae FG |
3509 | } |
3510 | else | |
3511 | ret = 0; | |
3512 | ||
3513 | for (std::list<obj_watch_t>::iterator i = lw.begin(); i != lw.end(); ++i) { | |
3514 | cout << "watcher=" << i->addr << " client." << i->watcher_id << " cookie=" << i->cookie << std::endl; | |
3515 | } | |
3516 | } else if (strcmp(nargs[0], "listsnaps") == 0) { | |
f67539c2 | 3517 | if (!pool_name || (nargs.size() < 2 && !obj_name)) { |
11fdf7f2 TL |
3518 | usage(cerr); |
3519 | return 1; | |
3520 | } | |
f67539c2 TL |
3521 | if (!obj_name) { |
3522 | obj_name = nargs[1]; | |
3523 | } | |
7c673cae | 3524 | |
7c673cae | 3525 | snap_set_t ls; |
7c673cae | 3526 | io_ctx.snap_set_read(LIBRADOS_SNAP_DIR); |
f67539c2 | 3527 | ret = io_ctx.list_snaps(*obj_name, &ls); |
7c673cae | 3528 | if (ret < 0) { |
f67539c2 | 3529 | cerr << "error listing snap shots " << pool_name << "/" << prettify(*obj_name) << ": " << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 3530 | return 1; |
7c673cae FG |
3531 | } |
3532 | else | |
3533 | ret = 0; | |
3534 | ||
3535 | map<snap_t,string> snamemap; | |
3536 | if (formatter || pretty_format) { | |
3537 | vector<snap_t> snaps; | |
3538 | io_ctx.snap_list(&snaps); | |
3539 | for (vector<snap_t>::iterator i = snaps.begin(); | |
3540 | i != snaps.end(); ++i) { | |
3541 | string s; | |
3542 | if (io_ctx.snap_get_name(*i, &s) < 0) | |
3543 | continue; | |
3544 | snamemap.insert(pair<snap_t,string>(*i, s)); | |
3545 | } | |
3546 | } | |
3547 | ||
3548 | if (formatter) { | |
3549 | formatter->open_object_section("object"); | |
f67539c2 | 3550 | formatter->dump_string("name", *obj_name); |
7c673cae FG |
3551 | formatter->open_array_section("clones"); |
3552 | } else { | |
f67539c2 | 3553 | cout << prettify(*obj_name) << ":" << std::endl; |
7c673cae FG |
3554 | cout << "cloneid snaps size overlap" << std::endl; |
3555 | } | |
3556 | ||
3557 | for (std::vector<clone_info_t>::iterator ci = ls.clones.begin(); | |
3558 | ci != ls.clones.end(); ++ci) { | |
3559 | ||
3560 | if (formatter) formatter->open_object_section("clone"); | |
3561 | ||
3562 | if (ci->cloneid == librados::SNAP_HEAD) { | |
3563 | if (formatter) | |
3564 | formatter->dump_string("id", "head"); | |
3565 | else | |
3566 | cout << "head"; | |
3567 | } else { | |
3568 | if (formatter) | |
3569 | formatter->dump_unsigned("id", ci->cloneid); | |
3570 | else | |
3571 | cout << ci->cloneid; | |
3572 | } | |
3573 | ||
3574 | if (formatter) | |
3575 | formatter->open_array_section("snapshots"); | |
3576 | else | |
3577 | cout << "\t"; | |
3578 | ||
3579 | if (!formatter && ci->snaps.empty()) { | |
3580 | cout << "-"; | |
3581 | } | |
3582 | for (std::vector<snap_t>::const_iterator snapindex = ci->snaps.begin(); | |
3583 | snapindex != ci->snaps.end(); ++snapindex) { | |
3584 | ||
3585 | map<snap_t,string>::iterator si; | |
3586 | ||
3587 | if (formatter || pretty_format) si = snamemap.find(*snapindex); | |
3588 | ||
3589 | if (formatter) { | |
3590 | formatter->open_object_section("snapshot"); | |
3591 | formatter->dump_unsigned("id", *snapindex); | |
3592 | if (si != snamemap.end()) | |
3593 | formatter->dump_string("name", si->second); | |
3594 | formatter->close_section(); //snapshot | |
3595 | } else { | |
3596 | if (snapindex != ci->snaps.begin()) cout << ","; | |
3597 | if (!pretty_format || (si == snamemap.end())) | |
3598 | cout << *snapindex; | |
3599 | else | |
3600 | cout << si->second << "(" << *snapindex << ")"; | |
3601 | } | |
3602 | } | |
3603 | ||
3604 | if (formatter) { | |
3605 | formatter->close_section(); //Snapshots | |
3606 | formatter->dump_unsigned("size", ci->size); | |
3607 | } else { | |
3608 | cout << "\t" << ci->size; | |
3609 | } | |
3610 | ||
3611 | if (ci->cloneid != librados::SNAP_HEAD) { | |
3612 | if (formatter) | |
3613 | formatter->open_array_section("overlaps"); | |
3614 | else | |
3615 | cout << "\t["; | |
3616 | ||
3617 | for (std::vector< std::pair<uint64_t,uint64_t> >::iterator ovi = ci->overlap.begin(); | |
3618 | ovi != ci->overlap.end(); ++ovi) { | |
3619 | if (formatter) { | |
3620 | formatter->open_object_section("section"); | |
3621 | formatter->dump_unsigned("start", ovi->first); | |
3622 | formatter->dump_unsigned("length", ovi->second); | |
3623 | formatter->close_section(); //section | |
3624 | } else { | |
3625 | if (ovi != ci->overlap.begin()) cout << ","; | |
3626 | cout << ovi->first << "~" << ovi->second; | |
3627 | } | |
3628 | } | |
3629 | if (formatter) | |
3630 | formatter->close_section(); //overlaps | |
3631 | else | |
3632 | cout << "]" << std::endl; | |
3633 | } | |
3634 | if (formatter) formatter->close_section(); //clone | |
3635 | } | |
3636 | if (formatter) { | |
3637 | formatter->close_section(); //clones | |
3638 | formatter->close_section(); //object | |
3639 | formatter->flush(cout); | |
3640 | } else { | |
3641 | cout << std::endl; | |
3642 | } | |
3643 | } else if (strcmp(nargs[0], "list-inconsistent-pg") == 0) { | |
3644 | if (!formatter) { | |
11fdf7f2 | 3645 | formatter = std::make_unique<JSONFormatter>(pretty_format); |
7c673cae FG |
3646 | } |
3647 | ret = do_get_inconsistent_pg_cmd(nargs, rados, *formatter); | |
3648 | } else if (strcmp(nargs[0], "list-inconsistent-obj") == 0) { | |
3649 | if (!formatter) { | |
11fdf7f2 | 3650 | formatter = std::make_unique<JSONFormatter>(pretty_format); |
7c673cae FG |
3651 | } |
3652 | ret = do_get_inconsistent_cmd<inconsistent_obj_t>(nargs, rados, *formatter); | |
3653 | } else if (strcmp(nargs[0], "list-inconsistent-snapset") == 0) { | |
3654 | if (!formatter) { | |
11fdf7f2 | 3655 | formatter = std::make_unique<JSONFormatter>(pretty_format); |
7c673cae FG |
3656 | } |
3657 | ret = do_get_inconsistent_cmd<inconsistent_snapset_t>(nargs, rados, *formatter); | |
3658 | } else if (strcmp(nargs[0], "cache-flush") == 0) { | |
f67539c2 | 3659 | if (!pool_name || (nargs.size() < 2 && !obj_name)) { |
11fdf7f2 TL |
3660 | usage(cerr); |
3661 | return 1; | |
3662 | } | |
f67539c2 TL |
3663 | if (!obj_name) { |
3664 | obj_name = nargs[1]; | |
3665 | } | |
7c673cae FG |
3666 | if (with_clones) { |
3667 | snap_set_t ls; | |
3668 | io_ctx.snap_set_read(LIBRADOS_SNAP_DIR); | |
f67539c2 | 3669 | ret = io_ctx.list_snaps(*obj_name, &ls); |
7c673cae | 3670 | if (ret < 0) { |
f67539c2 | 3671 | cerr << "error listing snapshots " << pool_name << "/" << prettify(*obj_name) << ": " |
7c673cae | 3672 | << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 3673 | return 1; |
7c673cae FG |
3674 | } |
3675 | for (std::vector<clone_info_t>::iterator ci = ls.clones.begin(); | |
3676 | ci != ls.clones.end(); ++ci) { | |
3677 | if (snapid != CEPH_NOSNAP && ci->cloneid > snapid) | |
3678 | break; | |
3679 | io_ctx.snap_set_read(ci->cloneid); | |
f67539c2 | 3680 | ret = do_cache_flush(io_ctx, *obj_name); |
7c673cae | 3681 | if (ret < 0) { |
f67539c2 | 3682 | cerr << "error from cache-flush " << prettify(*obj_name) << ": " |
7c673cae | 3683 | << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 3684 | return 1; |
7c673cae FG |
3685 | } |
3686 | } | |
3687 | } else { | |
f67539c2 | 3688 | ret = do_cache_flush(io_ctx, *obj_name); |
7c673cae | 3689 | if (ret < 0) { |
f67539c2 | 3690 | cerr << "error from cache-flush " << prettify(*obj_name) << ": " |
7c673cae | 3691 | << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 3692 | return 1; |
7c673cae FG |
3693 | } |
3694 | } | |
3695 | } else if (strcmp(nargs[0], "cache-try-flush") == 0) { | |
f67539c2 | 3696 | if (!pool_name || (nargs.size() < 2 && !obj_name)) { |
11fdf7f2 TL |
3697 | usage(cerr); |
3698 | return 1; | |
3699 | } | |
f67539c2 TL |
3700 | if (!obj_name) { |
3701 | obj_name = nargs[1]; | |
3702 | } | |
7c673cae FG |
3703 | if (with_clones) { |
3704 | snap_set_t ls; | |
3705 | io_ctx.snap_set_read(LIBRADOS_SNAP_DIR); | |
f67539c2 | 3706 | ret = io_ctx.list_snaps(*obj_name, &ls); |
7c673cae | 3707 | if (ret < 0) { |
f67539c2 | 3708 | cerr << "error listing snapshots " << pool_name << "/" << prettify(*obj_name) << ": " |
7c673cae | 3709 | << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 3710 | return 1; |
7c673cae FG |
3711 | } |
3712 | for (std::vector<clone_info_t>::iterator ci = ls.clones.begin(); | |
3713 | ci != ls.clones.end(); ++ci) { | |
3714 | if (snapid != CEPH_NOSNAP && ci->cloneid > snapid) | |
3715 | break; | |
3716 | io_ctx.snap_set_read(ci->cloneid); | |
f67539c2 | 3717 | ret = do_cache_try_flush(io_ctx, *obj_name); |
7c673cae | 3718 | if (ret < 0) { |
f67539c2 | 3719 | cerr << "error from cache-flush " << prettify(*obj_name) << ": " |
7c673cae | 3720 | << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 3721 | return 1; |
7c673cae FG |
3722 | } |
3723 | } | |
3724 | } else { | |
f67539c2 | 3725 | ret = do_cache_try_flush(io_ctx, *obj_name); |
7c673cae | 3726 | if (ret < 0) { |
f67539c2 | 3727 | cerr << "error from cache-flush " << prettify(*obj_name) << ": " |
7c673cae | 3728 | << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 3729 | return 1; |
7c673cae FG |
3730 | } |
3731 | } | |
3732 | } else if (strcmp(nargs[0], "cache-evict") == 0) { | |
f67539c2 | 3733 | if (!pool_name || (nargs.size() < 2 && !obj_name)) { |
11fdf7f2 TL |
3734 | usage(cerr); |
3735 | return 1; | |
3736 | } | |
f67539c2 TL |
3737 | if (!obj_name) { |
3738 | obj_name = nargs[1]; | |
3739 | } | |
7c673cae FG |
3740 | if (with_clones) { |
3741 | snap_set_t ls; | |
3742 | io_ctx.snap_set_read(LIBRADOS_SNAP_DIR); | |
f67539c2 | 3743 | ret = io_ctx.list_snaps(*obj_name, &ls); |
7c673cae | 3744 | if (ret < 0) { |
f67539c2 | 3745 | cerr << "error listing snapshots " << pool_name << "/" << prettify(*obj_name) << ": " |
7c673cae | 3746 | << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 3747 | return 1; |
7c673cae FG |
3748 | } |
3749 | for (std::vector<clone_info_t>::iterator ci = ls.clones.begin(); | |
3750 | ci != ls.clones.end(); ++ci) { | |
3751 | if (snapid != CEPH_NOSNAP && ci->cloneid > snapid) | |
3752 | break; | |
3753 | io_ctx.snap_set_read(ci->cloneid); | |
f67539c2 | 3754 | ret = do_cache_evict(io_ctx, *obj_name); |
7c673cae | 3755 | if (ret < 0) { |
f67539c2 | 3756 | cerr << "error from cache-flush " << prettify(*obj_name) << ": " |
7c673cae | 3757 | << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 3758 | return 1; |
7c673cae FG |
3759 | } |
3760 | } | |
3761 | } else { | |
f67539c2 | 3762 | ret = do_cache_evict(io_ctx, *obj_name); |
7c673cae | 3763 | if (ret < 0) { |
f67539c2 | 3764 | cerr << "error from cache-flush " << prettify(*obj_name) << ": " |
7c673cae | 3765 | << cpp_strerror(ret) << std::endl; |
11fdf7f2 | 3766 | return 1; |
7c673cae FG |
3767 | } |
3768 | } | |
3769 | } else if (strcmp(nargs[0], "cache-flush-evict-all") == 0) { | |
11fdf7f2 TL |
3770 | if (!pool_name) { |
3771 | usage(cerr); | |
3772 | return 1; | |
3773 | } | |
7c673cae FG |
3774 | ret = do_cache_flush_evict_all(io_ctx, true); |
3775 | if (ret < 0) { | |
11fdf7f2 TL |
3776 | cerr << "cache-flush-evict-all finished with errors" << std::endl; |
3777 | return 1; | |
7c673cae FG |
3778 | } |
3779 | } else if (strcmp(nargs[0], "cache-try-flush-evict-all") == 0) { | |
11fdf7f2 TL |
3780 | if (!pool_name) { |
3781 | usage(cerr); | |
3782 | return 1; | |
3783 | } | |
7c673cae FG |
3784 | ret = do_cache_flush_evict_all(io_ctx, false); |
3785 | if (ret < 0) { | |
11fdf7f2 TL |
3786 | cerr << "cache-try-flush-evict-all finished with errors" << std::endl; |
3787 | return 1; | |
7c673cae | 3788 | } |
31f18b77 | 3789 | } else if (strcmp(nargs[0], "set-redirect") == 0) { |
11fdf7f2 TL |
3790 | if (!pool_name) { |
3791 | usage(cerr); | |
3792 | return 1; | |
3793 | } | |
31f18b77 FG |
3794 | |
3795 | const char *target = target_pool_name; | |
3796 | if (!target) | |
3797 | target = pool_name; | |
3798 | ||
3799 | const char *target_obj; | |
3800 | if (nargs.size() < 3) { | |
3801 | if (strcmp(target, pool_name) == 0) { | |
3802 | cerr << "cannot copy object into itself" << std::endl; | |
11fdf7f2 | 3803 | return 1; |
31f18b77 FG |
3804 | } |
3805 | target_obj = nargs[1]; | |
3806 | } else { | |
3807 | target_obj = nargs[2]; | |
3808 | } | |
3809 | ||
3810 | IoCtx target_ctx; | |
3811 | ret = rados.ioctx_create(target, target_ctx); | |
3812 | if (target_oloc.size()) { | |
3813 | target_ctx.locator_set_key(target_oloc); | |
3814 | } | |
3815 | if (target_nspace.size()) { | |
3816 | target_ctx.set_namespace(target_nspace); | |
3817 | } | |
3818 | ||
3819 | ObjectWriteOperation op; | |
11fdf7f2 TL |
3820 | if (with_reference) { |
3821 | op.set_redirect(target_obj, target_ctx, 0, CEPH_OSD_OP_FLAG_WITH_REFERENCE); | |
3822 | } else { | |
3823 | op.set_redirect(target_obj, target_ctx, 0); | |
3824 | } | |
31f18b77 FG |
3825 | ret = io_ctx.operate(nargs[1], &op); |
3826 | if (ret < 0) { | |
3827 | cerr << "error set-redirect " << pool_name << "/" << nargs[1] << " => " << target << "/" << target_obj << ": " << cpp_strerror(ret) << std::endl; | |
11fdf7f2 TL |
3828 | return 1; |
3829 | } | |
3830 | } else if (strcmp(nargs[0], "set-chunk") == 0) { | |
3831 | if (!pool_name) { | |
3832 | usage(cerr); | |
3833 | return 1; | |
3834 | } | |
3835 | ||
3836 | const char *target = target_pool_name; | |
3837 | if (!target) | |
3838 | target = pool_name; | |
3839 | ||
3840 | uint64_t offset; | |
3841 | uint64_t length; | |
3842 | uint64_t tgt_offset; | |
3843 | string tgt_oid; | |
3844 | if (nargs.size() < 6) { | |
3845 | usage(cerr); | |
3846 | return 1; | |
3847 | } else { | |
3848 | char* endptr = NULL; | |
3849 | offset = strtoull(nargs[2], &endptr, 10); | |
3850 | if (*endptr) { | |
3851 | cerr << "Invalid value for size: '" << nargs[2] << "'" << std::endl; | |
3852 | return 1; | |
3853 | } | |
3854 | length = strtoull(nargs[3], &endptr, 10); | |
3855 | if (*endptr) { | |
3856 | cerr << "Invalid value for size: '" << nargs[2] << "'" << std::endl; | |
3857 | return 1; | |
3858 | } | |
3859 | tgt_oid = string(nargs[4]); | |
3860 | tgt_offset = strtoull(nargs[5], &endptr, 10); | |
3861 | if (*endptr) { | |
3862 | cerr << "Invalid value for size: '" << nargs[2] << "'" << std::endl; | |
3863 | return 1; | |
3864 | } | |
3865 | } | |
3866 | ||
3867 | IoCtx target_ctx; | |
3868 | ret = rados.ioctx_create(target, target_ctx); | |
f67539c2 TL |
3869 | ObjectReadOperation op; |
3870 | op.set_chunk(offset, length, target_ctx, tgt_oid, tgt_offset, CEPH_OSD_OP_FLAG_WITH_REFERENCE); | |
3871 | ret = io_ctx.operate(nargs[1], &op, NULL); | |
11fdf7f2 TL |
3872 | if (ret < 0) { |
3873 | cerr << "error set-chunk " << pool_name << "/" << nargs[1] << " " << " offset " << offset | |
3874 | << " length " << length << " target_pool " << target | |
3875 | << "tgt_offset: " << tgt_offset << " : " << cpp_strerror(ret) << std::endl; | |
3876 | return 1; | |
3877 | } | |
3878 | } else if (strcmp(nargs[0], "tier-promote") == 0) { | |
f67539c2 | 3879 | if (!pool_name || (nargs.size() < 2 && !obj_name)) { |
11fdf7f2 TL |
3880 | usage(cerr); |
3881 | return 1; | |
3882 | } | |
f67539c2 TL |
3883 | if (!obj_name) { |
3884 | obj_name = nargs[1]; | |
3885 | } | |
11fdf7f2 TL |
3886 | ObjectWriteOperation op; |
3887 | op.tier_promote(); | |
f67539c2 | 3888 | ret = io_ctx.operate(*obj_name, &op); |
11fdf7f2 | 3889 | if (ret < 0) { |
f67539c2 | 3890 | cerr << "error tier-promote " << pool_name << "/" << prettify(*obj_name) << " : " |
11fdf7f2 TL |
3891 | << cpp_strerror(ret) << std::endl; |
3892 | return 1; | |
3893 | } | |
3894 | } else if (strcmp(nargs[0], "unset-manifest") == 0) { | |
f67539c2 | 3895 | if (!pool_name || (nargs.size() < 2 && !obj_name)) { |
11fdf7f2 TL |
3896 | usage(cerr); |
3897 | return 1; | |
3898 | } | |
f67539c2 TL |
3899 | if (!obj_name) { |
3900 | obj_name = nargs[1]; | |
3901 | } | |
11fdf7f2 TL |
3902 | ObjectWriteOperation op; |
3903 | op.unset_manifest(); | |
f67539c2 | 3904 | ret = io_ctx.operate(*obj_name, &op); |
11fdf7f2 | 3905 | if (ret < 0) { |
f67539c2 | 3906 | cerr << "error unset-manifest " << pool_name << "/" << prettify(*obj_name) << " : " |
11fdf7f2 TL |
3907 | << cpp_strerror(ret) << std::endl; |
3908 | return 1; | |
31f18b77 | 3909 | } |
9f95a23c | 3910 | } else if (strcmp(nargs[0], "tier-flush") == 0) { |
f67539c2 | 3911 | if (!pool_name || (nargs.size() < 2 && !obj_name)) { |
9f95a23c TL |
3912 | usage(cerr); |
3913 | return 1; | |
3914 | } | |
f67539c2 TL |
3915 | if (!obj_name) { |
3916 | obj_name = nargs[1]; | |
3917 | } | |
3918 | ObjectReadOperation op; | |
9f95a23c | 3919 | op.tier_flush(); |
f67539c2 TL |
3920 | librados::AioCompletion *completion = |
3921 | librados::Rados::aio_create_completion(); | |
3922 | io_ctx.aio_operate(*obj_name, completion, &op, | |
3923 | librados::OPERATION_IGNORE_CACHE | | |
3924 | librados::OPERATION_IGNORE_OVERLAY, | |
3925 | NULL); | |
3926 | completion->wait_for_complete(); | |
3927 | ret = completion->get_return_value(); | |
3928 | completion->release(); | |
3929 | if (ret < 0) { | |
3930 | cerr << "error tier-flush " << pool_name << "/" << prettify(*obj_name) << " : " | |
3931 | << cpp_strerror(ret) << std::endl; | |
3932 | return 1; | |
3933 | } | |
3934 | } else if (strcmp(nargs[0], "tier-evict") == 0) { | |
3935 | if (!pool_name || (nargs.size() < 2 && !obj_name)) { | |
3936 | usage(cerr); | |
3937 | return 1; | |
3938 | } | |
3939 | if (!obj_name) { | |
3940 | obj_name = nargs[1]; | |
3941 | } | |
3942 | ObjectReadOperation op; | |
3943 | op.tier_evict(); | |
3944 | librados::AioCompletion *completion = | |
3945 | librados::Rados::aio_create_completion(); | |
3946 | io_ctx.aio_operate(*obj_name, completion, &op, | |
3947 | librados::OPERATION_IGNORE_CACHE | | |
3948 | librados::OPERATION_IGNORE_OVERLAY, | |
3949 | NULL); | |
3950 | completion->wait_for_complete(); | |
3951 | ret = completion->get_return_value(); | |
3952 | completion->release(); | |
9f95a23c | 3953 | if (ret < 0) { |
f67539c2 | 3954 | cerr << "error tier-evict " << pool_name << "/" << prettify(*obj_name) << " : " |
9f95a23c TL |
3955 | << cpp_strerror(ret) << std::endl; |
3956 | return 1; | |
3957 | } | |
7c673cae FG |
3958 | } else if (strcmp(nargs[0], "export") == 0) { |
3959 | // export [filename] | |
3960 | if (!pool_name || nargs.size() > 2) { | |
11fdf7f2 TL |
3961 | usage(cerr); |
3962 | return 1; | |
7c673cae FG |
3963 | } |
3964 | ||
3965 | int file_fd; | |
3966 | if (nargs.size() < 2 || std::string(nargs[1]) == "-") { | |
3967 | file_fd = STDOUT_FILENO; | |
3968 | } else { | |
f67539c2 | 3969 | file_fd = open(nargs[1], O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666); |
7c673cae FG |
3970 | if (file_fd < 0) { |
3971 | cerr << "Error opening '" << nargs[1] << "': " | |
3972 | << cpp_strerror(file_fd) << std::endl; | |
11fdf7f2 | 3973 | return 1; |
7c673cae FG |
3974 | } |
3975 | } | |
3976 | ||
3977 | ret = PoolDump(file_fd).dump(&io_ctx); | |
3978 | ||
3979 | if (file_fd != STDIN_FILENO) { | |
3980 | VOID_TEMP_FAILURE_RETRY(::close(file_fd)); | |
3981 | } | |
3982 | ||
3983 | if (ret < 0) { | |
3984 | cerr << "error from export: " | |
3985 | << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 3986 | return 1; |
7c673cae FG |
3987 | } |
3988 | } else if (strcmp(nargs[0], "import") == 0) { | |
3989 | // import [--no-overwrite] [--dry-run] <filename | - > | |
3990 | if (!pool_name || nargs.size() > 4 || nargs.size() < 2) { | |
11fdf7f2 TL |
3991 | usage(cerr); |
3992 | return 1; | |
7c673cae FG |
3993 | } |
3994 | ||
3995 | // Last arg is the filename | |
3996 | std::string const filename = nargs[nargs.size() - 1]; | |
3997 | ||
3998 | // All other args may be flags | |
3999 | bool dry_run = false; | |
4000 | bool no_overwrite = false; | |
4001 | for (unsigned i = 1; i < nargs.size() - 1; ++i) { | |
4002 | std::string arg(nargs[i]); | |
4003 | ||
4004 | if (arg == std::string("--no-overwrite")) { | |
4005 | no_overwrite = true; | |
4006 | } else if (arg == std::string("--dry-run")) { | |
4007 | dry_run = true; | |
4008 | } else { | |
4009 | std::cerr << "Invalid argument '" << arg << "'" << std::endl; | |
11fdf7f2 | 4010 | return 1; |
7c673cae FG |
4011 | } |
4012 | } | |
4013 | ||
4014 | int file_fd; | |
4015 | if (filename == "-") { | |
4016 | file_fd = STDIN_FILENO; | |
4017 | } else { | |
f67539c2 | 4018 | file_fd = open(filename.c_str(), O_RDONLY|O_BINARY); |
7c673cae FG |
4019 | if (file_fd < 0) { |
4020 | cerr << "Error opening '" << filename << "': " | |
4021 | << cpp_strerror(file_fd) << std::endl; | |
11fdf7f2 | 4022 | return 1; |
7c673cae FG |
4023 | } |
4024 | } | |
4025 | ||
4026 | ret = RadosImport(file_fd, 0, dry_run).import(io_ctx, no_overwrite); | |
4027 | ||
4028 | if (file_fd != STDIN_FILENO) { | |
4029 | VOID_TEMP_FAILURE_RETRY(::close(file_fd)); | |
4030 | } | |
4031 | ||
4032 | if (ret < 0) { | |
4033 | cerr << "error from import: " | |
4034 | << cpp_strerror(ret) << std::endl; | |
11fdf7f2 | 4035 | return 1; |
7c673cae FG |
4036 | } |
4037 | } else { | |
4038 | cerr << "unrecognized command " << nargs[0] << "; -h or --help for usage" << std::endl; | |
4039 | ret = -EINVAL; | |
7c673cae FG |
4040 | } |
4041 | ||
4042 | if (ret < 0) | |
4043 | cerr << "error " << (-ret) << ": " << cpp_strerror(ret) << std::endl; | |
4044 | ||
7c673cae FG |
4045 | return (ret < 0) ? 1 : 0; |
4046 | } | |
4047 | ||
4048 | int main(int argc, const char **argv) | |
4049 | { | |
20effc67 | 4050 | auto args = argv_to_vec(argc, argv); |
11fdf7f2 TL |
4051 | if (args.empty()) { |
4052 | cerr << argv[0] << ": -h or --help for usage" << std::endl; | |
4053 | exit(1); | |
4054 | } | |
4055 | if (ceph_argparse_need_usage(args)) { | |
4056 | usage(cout); | |
4057 | exit(0); | |
4058 | } | |
7c673cae FG |
4059 | |
4060 | std::map < std::string, std::string > opts; | |
4061 | std::string val; | |
4062 | ||
4063 | // Necessary to support usage of -f for formatting, | |
4064 | // since global_init will remove the -f using ceph | |
4065 | // argparse procedures. | |
4066 | for (auto j = args.begin(); j != args.end(); ++j) { | |
4067 | if (strcmp(*j, "--") == 0) { | |
4068 | break; | |
4069 | } else if ((j+1) == args.end()) { | |
4070 | // This can't be a formatting call (no format arg) | |
4071 | break; | |
4072 | } else if (strcmp(*j, "-f") == 0) { | |
4073 | val = *(j+1); | |
4074 | unique_ptr<Formatter> formatter(Formatter::create(val.c_str())); | |
4075 | ||
4076 | if (formatter) { | |
4077 | j = args.erase(j); | |
4078 | opts["format"] = val; | |
4079 | ||
4080 | j = args.erase(j); | |
4081 | break; | |
4082 | } | |
4083 | } | |
4084 | } | |
4085 | ||
4086 | auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, | |
4087 | CODE_ENVIRONMENT_UTILITY, 0); | |
4088 | common_init_finish(g_ceph_context); | |
4089 | ||
4090 | std::vector<const char*>::iterator i; | |
4091 | for (i = args.begin(); i != args.end(); ) { | |
4092 | if (ceph_argparse_double_dash(args, i)) { | |
4093 | break; | |
7c673cae FG |
4094 | } else if (ceph_argparse_flag(args, i, "--force-full", (char*)NULL)) { |
4095 | opts["force-full"] = "true"; | |
4096 | } else if (ceph_argparse_flag(args, i, "-d", "--delete-after", (char*)NULL)) { | |
4097 | opts["delete-after"] = "true"; | |
4098 | } else if (ceph_argparse_flag(args, i, "-C", "--create", "--create-pool", | |
4099 | (char*)NULL)) { | |
4100 | opts["create"] = "true"; | |
4101 | } else if (ceph_argparse_flag(args, i, "--pretty-format", (char*)NULL)) { | |
4102 | opts["pretty-format"] = "true"; | |
4103 | } else if (ceph_argparse_flag(args, i, "--show-time", (char*)NULL)) { | |
4104 | opts["show-time"] = "true"; | |
4105 | } else if (ceph_argparse_flag(args, i, "--no-cleanup", (char*)NULL)) { | |
4106 | opts["no-cleanup"] = "true"; | |
4107 | } else if (ceph_argparse_flag(args, i, "--no-hints", (char*)NULL)) { | |
4108 | opts["no-hints"] = "true"; | |
11fdf7f2 TL |
4109 | } else if (ceph_argparse_flag(args, i, "--reuse-bench", (char*)NULL)) { |
4110 | opts["reuse-bench"] = "true"; | |
7c673cae FG |
4111 | } else if (ceph_argparse_flag(args, i, "--no-verify", (char*)NULL)) { |
4112 | opts["no-verify"] = "true"; | |
4113 | } else if (ceph_argparse_witharg(args, i, &val, "--run-name", (char*)NULL)) { | |
4114 | opts["run-name"] = val; | |
4115 | } else if (ceph_argparse_witharg(args, i, &val, "--prefix", (char*)NULL)) { | |
4116 | opts["prefix"] = val; | |
4117 | } else if (ceph_argparse_witharg(args, i, &val, "-p", "--pool", (char*)NULL)) { | |
4118 | opts["pool"] = val; | |
4119 | } else if (ceph_argparse_witharg(args, i, &val, "--target-pool", (char*)NULL)) { | |
4120 | opts["target_pool"] = val; | |
4121 | } else if (ceph_argparse_witharg(args, i, &val, "--object-locator" , (char *)NULL)) { | |
4122 | opts["object_locator"] = val; | |
4123 | } else if (ceph_argparse_witharg(args, i, &val, "--target-locator" , (char *)NULL)) { | |
4124 | opts["target_locator"] = val; | |
4125 | } else if (ceph_argparse_witharg(args, i, &val, "--target-nspace" , (char *)NULL)) { | |
4126 | opts["target_nspace"] = val; | |
11fdf7f2 | 4127 | #ifdef WITH_LIBRADOSSTRIPER |
7c673cae FG |
4128 | } else if (ceph_argparse_flag(args, i, "--striper" , (char *)NULL)) { |
4129 | opts["striper"] = "true"; | |
11fdf7f2 | 4130 | #endif |
7c673cae FG |
4131 | } else if (ceph_argparse_witharg(args, i, &val, "-t", "--concurrent-ios", (char*)NULL)) { |
4132 | opts["concurrent-ios"] = val; | |
4133 | } else if (ceph_argparse_witharg(args, i, &val, "--block-size", (char*)NULL)) { | |
4134 | opts["block-size"] = val; | |
4135 | } else if (ceph_argparse_witharg(args, i, &val, "-b", (char*)NULL)) { | |
4136 | opts["block-size"] = val; | |
4137 | } else if (ceph_argparse_witharg(args, i, &val, "--object-size", (char*)NULL)) { | |
4138 | opts["object-size"] = val; | |
4139 | } else if (ceph_argparse_witharg(args, i, &val, "--max-objects", (char*)NULL)) { | |
4140 | opts["max-objects"] = val; | |
4141 | } else if (ceph_argparse_witharg(args, i, &val, "--offset", (char*)NULL)) { | |
4142 | opts["offset"] = val; | |
9f95a23c | 4143 | } else if (ceph_argparse_witharg(args, i, &val, "-O", (char*)NULL)) { |
7c673cae FG |
4144 | opts["object-size"] = val; |
4145 | } else if (ceph_argparse_witharg(args, i, &val, "-s", "--snap", (char*)NULL)) { | |
4146 | opts["snap"] = val; | |
4147 | } else if (ceph_argparse_witharg(args, i, &val, "-S", "--snapid", (char*)NULL)) { | |
4148 | opts["snapid"] = val; | |
4149 | } else if (ceph_argparse_witharg(args, i, &val, "--min-object-size", (char*)NULL)) { | |
4150 | opts["min-object-size"] = val; | |
4151 | } else if (ceph_argparse_witharg(args, i, &val, "--max-object-size", (char*)NULL)) { | |
4152 | opts["max-object-size"] = val; | |
4153 | } else if (ceph_argparse_witharg(args, i, &val, "--min-op-len", (char*)NULL)) { | |
4154 | opts["min-op-len"] = val; | |
4155 | } else if (ceph_argparse_witharg(args, i, &val, "--max-op-len", (char*)NULL)) { | |
4156 | opts["max-op-len"] = val; | |
4157 | } else if (ceph_argparse_witharg(args, i, &val, "--max-ops", (char*)NULL)) { | |
4158 | opts["max-ops"] = val; | |
4159 | } else if (ceph_argparse_witharg(args, i, &val, "--max-backlog", (char*)NULL)) { | |
4160 | opts["max-backlog"] = val; | |
4161 | } else if (ceph_argparse_witharg(args, i, &val, "--target-throughput", (char*)NULL)) { | |
4162 | opts["target-throughput"] = val; | |
11fdf7f2 TL |
4163 | } else if (ceph_argparse_witharg(args, i, &val, "--offset-align", (char*)NULL)) { |
4164 | opts["offset_align"] = val; | |
7c673cae FG |
4165 | } else if (ceph_argparse_witharg(args, i, &val, "--read-percent", (char*)NULL)) { |
4166 | opts["read-percent"] = val; | |
4167 | } else if (ceph_argparse_witharg(args, i, &val, "--num-objects", (char*)NULL)) { | |
4168 | opts["num-objects"] = val; | |
4169 | } else if (ceph_argparse_witharg(args, i, &val, "--run-length", (char*)NULL)) { | |
4170 | opts["run-length"] = val; | |
4171 | } else if (ceph_argparse_witharg(args, i, &val, "--workers", (char*)NULL)) { | |
4172 | opts["workers"] = val; | |
11fdf7f2 | 4173 | } else if (ceph_argparse_witharg(args, i, &val, "-f", "--format", (char*)NULL)) { |
7c673cae FG |
4174 | opts["format"] = val; |
4175 | } else if (ceph_argparse_witharg(args, i, &val, "--lock-tag", (char*)NULL)) { | |
4176 | opts["lock-tag"] = val; | |
4177 | } else if (ceph_argparse_witharg(args, i, &val, "--lock-cookie", (char*)NULL)) { | |
4178 | opts["lock-cookie"] = val; | |
4179 | } else if (ceph_argparse_witharg(args, i, &val, "--lock-description", (char*)NULL)) { | |
4180 | opts["lock-description"] = val; | |
4181 | } else if (ceph_argparse_witharg(args, i, &val, "--lock-duration", (char*)NULL)) { | |
4182 | opts["lock-duration"] = val; | |
4183 | } else if (ceph_argparse_witharg(args, i, &val, "--lock-type", (char*)NULL)) { | |
4184 | opts["lock-type"] = val; | |
4185 | } else if (ceph_argparse_witharg(args, i, &val, "-N", "--namespace", (char*)NULL)) { | |
4186 | opts["namespace"] = val; | |
4187 | } else if (ceph_argparse_flag(args, i, "--all", (char*)NULL)) { | |
4188 | opts["all"] = "true"; | |
4189 | } else if (ceph_argparse_flag(args, i, "--default", (char*)NULL)) { | |
4190 | opts["default"] = "true"; | |
4191 | } else if (ceph_argparse_witharg(args, i, &val, "-o", "--output", (char*)NULL)) { | |
4192 | opts["output"] = val; | |
4193 | } else if (ceph_argparse_flag(args, i, "--write-omap", (char*)NULL)) { | |
4194 | opts["write-dest-omap"] = "true"; | |
4195 | } else if (ceph_argparse_flag(args, i, "--write-object", (char*)NULL)) { | |
4196 | opts["write-dest-obj"] = "true"; | |
4197 | } else if (ceph_argparse_flag(args, i, "--write-xattr", (char*)NULL)) { | |
4198 | opts["write-dest-xattr"] = "true"; | |
4199 | } else if (ceph_argparse_flag(args, i, "--with-clones", (char*)NULL)) { | |
4200 | opts["with-clones"] = "true"; | |
4201 | } else if (ceph_argparse_witharg(args, i, &val, "--omap-key-file", (char*)NULL)) { | |
4202 | opts["omap-key-file"] = val; | |
f67539c2 TL |
4203 | } else if (ceph_argparse_witharg(args, i, &val, "--obj-name-file", (char*)NULL)) { |
4204 | opts["obj-name-file"] = val; | |
11fdf7f2 TL |
4205 | } else if (ceph_argparse_flag(args, i, "--with-reference", (char*)NULL)) { |
4206 | opts["with-reference"] = "true"; | |
4207 | } else if (ceph_argparse_witharg(args, i, &val, "--pgid", (char*)NULL)) { | |
4208 | opts["pgid"] = val; | |
f67539c2 TL |
4209 | } else if (ceph_argparse_witharg(args, i, &val, "--input-file", (char*)NULL)) { |
4210 | opts["input_file"] = val; | |
7c673cae FG |
4211 | } else { |
4212 | if (val[0] == '-') | |
4213 | usage_exit(); | |
4214 | ++i; | |
4215 | } | |
4216 | } | |
4217 | ||
4218 | if (args.empty()) { | |
4219 | cerr << "rados: you must give an action. Try --help" << std::endl; | |
4220 | return 1; | |
4221 | } | |
4222 | ||
4223 | return rados_tool_common(opts, args); | |
4224 | } |