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