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