1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
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.
15 #include "include/types.h"
17 #include "include/rados/buffer.h"
18 #include "include/rados/librados.hpp"
19 #include "include/rados/rados_types.hpp"
22 #ifdef WITH_LIBRADOSSTRIPER
23 #include "include/radosstriper/libradosstriper.hpp"
24 using namespace libradosstriper
;
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"
38 #include "include/random.h"
53 #include "cls/lock/cls_lock_client.h"
54 #include "include/compat.h"
55 #include "include/util.h"
56 #include "common/hobject.h"
59 #include "RadosImport.h"
61 #include "osd/ECUtil.h"
63 using namespace std::chrono_literals
;
64 using namespace librados
;
65 using ceph::util::generate_random_number
;
79 using std::unique_ptr
;
82 // two steps seem to be necessary to do this right
83 #define STR(x) _STR(x)
86 void usage(ostream
& out
)
89 "usage: rados [options] [commands]\n"
91 " lspools list pools\n"
92 " cppool <pool-name> <dest-pool> copy content of a pool\n"
93 " purge <pool-name> --yes-i-really-really-mean-it\n"
94 " remove all objects from pool <pool-name> without removing the pool itself\n"
95 " df show per-pool and total usage\n"
96 " ls list objects in pool\n\n"
98 "POOL SNAP COMMANDS\n"
99 " lssnap list snaps\n"
100 " mksnap <snap-name> create snap <snap-name>\n"
101 " rmsnap <snap-name> remove snap <snap-name>\n"
104 " get <obj-name> <outfile> fetch object\n"
105 " put <obj-name> <infile> [--offset offset]\n"
106 " write object with start offset (default:0)\n"
107 " append <obj-name> <infile> append object\n"
108 " truncate <obj-name> length truncate object\n"
109 " create <obj-name> create object\n"
110 " rm <obj-name> ... [--force-full] remove object(s), --force-full forces remove when cluster is full\n"
111 " cp <obj-name> [target-obj] copy object\n"
112 " listxattr <obj-name> list attrs of this object\n"
113 " getxattr <obj-name> <attr> get the <attr> attribute of this object\n"
114 " setxattr <obj-name> attr val\n"
115 " rmxattr <obj-name> attr\n"
116 " stat <obj-name> stat the named object\n"
117 " stat2 <obj-name> stat2 the named object (with high precision time)\n"
118 " touch <obj-name> [timestamp] change the named object modification time\n"
119 " mapext <obj-name>\n"
120 " rollback <obj-name> <snap-name> roll back object to snap <snap-name>\n"
122 " listsnaps <obj-name> list the snapshots of this object\n"
123 " bench <seconds> write|seq|rand [-t concurrent_operations] [--no-cleanup] [--run-name run_name] [--no-hints] [--reuse-bench]\n"
124 " default is 16 concurrent IOs and 4 MB ops\n"
125 " default is to clean up after write benchmark\n"
126 " default run-name is 'benchmark_last_metadata'\n"
127 " cleanup [--run-name run_name] [--prefix prefix]\n"
128 " clean up a previous benchmark operation\n"
129 " default run-name is 'benchmark_last_metadata'\n"
130 " load-gen [options] generate load on the cluster\n"
131 " listomapkeys <obj-name> list the keys in the object map\n"
132 " listomapvals <obj-name> list the keys and vals in the object map \n"
133 " getomapval <obj-name> <key> [file] show the value for the specified key\n"
134 " in the object's object map\n"
135 " setomapval <obj-name> <key> <val | --input-file file>\n"
136 " rmomapkey <obj-name> <key> Remove key from the object map of <obj-name>\n"
137 " clearomap <obj-name> [obj-name2 obj-name3...] clear all the omap keys for the specified objects\n"
138 " getomapheader <obj-name> [file] Dump the hexadecimal value of the object map header of <obj-name>\n"
139 " setomapheader <obj-name> <val> Set the value of the object map header of <obj-name>\n"
140 " watch <obj-name> add watcher on this object\n"
141 " notify <obj-name> <message> notify watcher of this object with message\n"
142 " listwatchers <obj-name> list the watchers of this object\n"
143 " set-alloc-hint <obj-name> <expected-object-size> <expected-write-size>\n"
144 " set allocation hint for an object\n"
145 " set-redirect <object A> --target-pool <caspool> <target object A> [--with-reference]\n"
146 " set redirect target\n"
147 " set-chunk <object A> <offset> <length> --target-pool <caspool> <target object A> <taget-offset> [--with-reference]\n"
148 " convert an object to chunked object\n"
149 " tier-promote <obj-name> promote the object to the base tier\n"
150 " unset-manifest <obj-name> unset redirect or chunked object\n"
151 " tier-flush <obj-name> flush the chunked object\n"
152 " tier-evict <obj-name> evict the chunked object\n"
154 "IMPORT AND EXPORT\n"
155 " export [filename]\n"
156 " Serialize pool contents to a file or standard out.\n"
157 " import [--dry-run] [--no-overwrite] < filename | - >\n"
158 " Load pool contents from a file or standard in\n"
161 " lock list <obj-name>\n"
162 " List all advisory locks on an object\n"
163 " lock get <obj-name> <lock-name> [--lock-cookie locker-cookie] [--lock-tag locker-tag] [--lock-description locker-desc] [--lock-duration locker-dur] [--lock-type locker-type]\n"
164 " Try to acquire a lock\n"
165 " lock break <obj-name> <lock-name> <locker-name> [--lock-cookie locker-cookie]\n"
166 " Try to break a lock acquired by another client\n"
167 " lock info <obj-name> <lock-name>\n"
168 " Show lock information\n"
170 " --lock-tag Lock tag, all locks operation should use\n"
172 " --lock-cookie Locker cookie\n"
173 " --lock-description Description of lock\n"
174 " --lock-duration Lock duration (in seconds)\n"
175 " --lock-type Lock type (shared, exclusive)\n"
177 "SCRUB AND REPAIR:\n"
178 " list-inconsistent-pg <pool> list inconsistent PGs in given pool\n"
179 " list-inconsistent-obj <pgid> list inconsistent objects in given PG\n"
180 " list-inconsistent-snapset <pgid> list inconsistent snapsets in the given PG\n"
182 "CACHE POOLS: (for testing/development only)\n"
183 " cache-flush <obj-name> flush cache pool object (blocking)\n"
184 " cache-try-flush <obj-name> flush cache pool object (non-blocking)\n"
185 " cache-evict <obj-name> evict cache pool object\n"
186 " cache-flush-evict-all flush+evict all objects\n"
187 " cache-try-flush-evict-all try-flush+evict all objects\n"
190 " --object-locator object_locator\n"
191 " set object_locator for operation\n"
194 " select given pool by name\n"
195 " --target-pool=pool\n"
196 " select target pool by name\n"
198 " select given PG id\n"
199 " -f [--format plain|json|json-pretty]\n"
200 " --format=[--format plain|json|json-pretty]\n"
202 " set the block size for put/get ops and for write benchmarking\n"
204 " set the object size for put/get ops and for write benchmarking\n"
206 " set the max number of objects for write benchmarking\n"
207 " --obj-name-file file\n"
208 " use the content of the specified file in place of <obj-name>\n"
211 " select given snap name for (read) IO\n"
212 " --input-file file\n"
213 " use the content of the specified file in place of <val>\n"
215 " create the pool or directory that was specified\n"
217 " --namespace=namespace\n"
218 " specify the namespace to use for the object\n"
220 " Use with ls to list objects in all namespaces\n"
221 " Put in CEPH_ARGS environment variable to make this the default\n"
223 " Use with ls to list objects in default namespace\n"
224 " Takes precedence over --all in case --all is in environment\n"
225 " --target-locator\n"
226 " Use with cp to specify the locator of the new object\n"
228 " Use with cp to specify the namespace of the new object\n"
229 #ifdef WITH_LIBRADOSSTRIPER
231 " Use radostriper interface rather than pure rados\n"
232 " Available for stat, get, put, truncate, rm, ls and \n"
233 " all xattr related operations\n"
238 " --concurrent-ios=N\n"
239 " Set number of concurrent I/O operations\n"
241 " prefix output with date/time\n"
243 " do not verify contents of read objects\n"
245 " write contents to the objects\n"
247 " write contents to the omap\n"
249 " write contents to the extended attributes\n"
251 "LOAD GEN OPTIONS:\n"
252 " --num-objects total number of objects\n"
253 " --min-object-size min object size\n"
254 " --max-object-size max object size\n"
255 " --min-op-len min io size of operations\n"
256 " --max-op-len max io size of operations\n"
257 " --max-ops max number of operations\n"
258 " --max-backlog max backlog size\n"
259 " --read-percent percent of operations that are read\n"
260 " --target-throughput target throughput (in bytes)\n"
261 " --run-length total time (in seconds)\n"
262 " --offset-align at what boundary to align random op offsets\n"
264 "CACHE POOLS OPTIONS:\n"
265 " --with-clones include clones when doing flush or evict\n"
268 " --omap-key-file file read the omap key from a file\n"
270 "GENERIC OPTIONS:\n";
271 generic_client_usage();
276 #ifdef WITH_LIBRADOSSTRIPER
277 RadosStriper
& striper()
279 static RadosStriper s
;
284 int read([[maybe_unused
]] IoCtx
& io_ctx
, const std::string
& oid
, buffer::list
& out_data
, const unsigned op_size
, const uint64_t offset
, [[maybe_unused
]] const bool use_striper
)
286 #ifdef WITH_LIBRADOSSTRIPER
288 return striper().read(oid
, &out_data
, op_size
, offset
);
291 return io_ctx
.read(oid
, out_data
, op_size
, offset
);
294 int write([[maybe_unused
]] IoCtx
& io_ctx
, const std::string
& oid
, buffer::list
& indata
, const uint64_t count
, const uint64_t offset
, [[maybe_unused
]] const bool use_striper
)
296 #ifdef WITH_LIBRADOSSTRIPER
298 return striper().write(oid
, indata
, count
, offset
);
301 return io_ctx
.write(oid
, indata
, count
, offset
);
304 int write_full([[maybe_unused
]] IoCtx
& io_ctx
, const std::string
& oid
, bufferlist
& indata
, [[maybe_unused
]] const bool use_striper
)
306 #ifdef WITH_LIBRADOSSTRIPER
308 return striper().write_full(oid
, indata
);
311 return io_ctx
.write_full(oid
, indata
);
314 int trunc([[maybe_unused
]] IoCtx
& io_ctx
, const std::string
& oid
, const uint64_t offset
, [[maybe_unused
]] const bool use_striper
)
316 #ifdef WITH_LIBRADOSSTRIPER
318 return striper().trunc(oid
, offset
);
321 return io_ctx
.trunc(oid
, offset
);
324 int append([[maybe_unused
]] IoCtx
& io_ctx
, const std::string
& oid
, buffer::list
& indata
, const uint64_t count
, [[maybe_unused
]] const bool use_striper
)
326 #ifdef WITH_LIBRADOSSTRIPER
328 return striper().append(oid
, indata
, count
);
331 return io_ctx
.append(oid
, indata
, count
);
334 int setxattr([[maybe_unused
]] IoCtx
& io_ctx
, const std::string
& oid
, const std::string
& attr_name
, buffer::list
& bl
, [[maybe_unused
]] const bool use_striper
)
336 #ifdef WITH_LIBRADOSSTRIPER
338 return striper().setxattr(oid
, attr_name
.c_str(), bl
);
341 return io_ctx
.setxattr(oid
, attr_name
.c_str(), bl
);
344 int getxattr([[maybe_unused
]] IoCtx
& io_ctx
, const std::string
& oid
, const std::string
& attr_name
, buffer::list
& bl
, [[maybe_unused
]] const bool use_striper
)
346 #ifdef WITH_LIBRADOSSTRIPER
348 return striper().getxattr(oid
, attr_name
.c_str(), bl
);
351 return io_ctx
.getxattr(oid
, attr_name
.c_str(), bl
);
354 int rmxattr([[maybe_unused
]] IoCtx
& io_ctx
, const std::string
& oid
, const std::string
& attr_name
, [[maybe_unused
]] const bool use_striper
)
356 #ifdef WITH_LIBRADOSSTRIPER
358 return striper().rmxattr(oid
, attr_name
.c_str());
361 return io_ctx
.rmxattr(oid
, attr_name
.c_str());
364 int getxattrs([[maybe_unused
]] IoCtx
& io_ctx
, const std::string
& oid
, std::map
<std::string
, buffer::list
>& attrset
, [[maybe_unused
]] const bool use_striper
)
366 #ifdef WITH_LIBRADOSSTRIPER
368 return striper().getxattrs(oid
, attrset
);
371 return io_ctx
.getxattrs(oid
, attrset
);
374 int remove([[maybe_unused
]] IoCtx
& io_ctx
, const std::string
& oid
, const int flags
, [[maybe_unused
]] const bool use_striper
)
376 #ifdef WITH_LIBRADOSSTRIPER
378 return striper().remove(oid
, flags
);
381 return io_ctx
.remove(oid
, flags
);
384 int remove([[maybe_unused
]] IoCtx
& io_ctx
, const std::string
& oid
, [[maybe_unused
]] const bool use_striper
)
386 #ifdef WITH_LIBRADOSSTRIPER
388 return striper().remove(oid
);
391 return io_ctx
.remove(oid
);
394 std::string
get_oid(librados::NObjectIterator
& i
, [[maybe_unused
]] const bool use_striper
)
396 #ifdef WITH_LIBRADOSSTRIPER
398 return i
->get_oid().substr(0, i
->get_oid().length()-17);
404 int stat([[maybe_unused
]] IoCtx
& io_ctx
, const std::string
& oid
, uint64_t& size
, time_t& mtime
, [[maybe_unused
]] const bool use_striper
)
406 #ifdef WITH_LIBRADOSSTRIPER
408 return striper().stat(oid
, &size
, &mtime
);
411 return io_ctx
.stat(oid
, &size
, &mtime
);
414 int stat2([[maybe_unused
]] IoCtx
& io_ctx
, const std::string
& oid
, uint64_t& size
, timespec
& mtime
, [[maybe_unused
]] const bool use_striper
)
416 #ifdef WITH_LIBRADOSSTRIPER
418 return striper().stat2(oid
, &size
, &mtime
);
421 return io_ctx
.stat2(oid
, &size
, &mtime
);
424 void dump_name(Formatter
*formatter
, const librados::NObjectIterator
& i
, [[maybe_unused
]] const bool use_striper
)
426 #ifdef WITH_LIBRADOSSTRIPER
428 formatter
->dump_string("name", i
->get_oid().substr(0, i
->get_oid().length()-17));
433 formatter
->dump_string("name", i
->get_oid());
436 } // namespace detail
438 unsigned default_op_size
= 1 << 22;
439 static const unsigned MAX_OMAP_BYTES_PER_REQUEST
= 1 << 10;
441 [[noreturn
]] static void usage_exit()
448 template <typename I
, typename T
>
449 static int rados_sistrtoll(I
&i
, T
*val
) {
451 *val
= strict_iecstrtoll(i
->second
.c_str(), &err
);
453 cerr
<< "Invalid value for " << i
->first
<< ": " << err
<< std::endl
;
461 static int dump_data(std::string
const &filename
, bufferlist
const &data
)
464 if (filename
== "-") {
467 fd
= TEMP_FAILURE_RETRY(::open(filename
.c_str(), O_WRONLY
|O_CREAT
|O_TRUNC
|O_BINARY
, 0644));
470 cerr
<< "failed to open file: " << cpp_strerror(err
) << std::endl
;
475 int r
= data
.write_fd(fd
);
478 VOID_TEMP_FAILURE_RETRY(::close(fd
));
485 static int do_get(IoCtx
& io_ctx
, const std::string
& oid
, const char *outfile
, unsigned op_size
, [[maybe_unused
]] const bool use_striper
)
488 if (strcmp(outfile
, "-") == 0) {
491 fd
= TEMP_FAILURE_RETRY(::open(outfile
, O_WRONLY
|O_CREAT
|O_TRUNC
|O_BINARY
, 0644));
494 cerr
<< "failed to open file: " << cpp_strerror(err
) << std::endl
;
504 ret
= detail::read(io_ctx
, oid
, outdata
, op_size
, offset
, use_striper
);
508 ret
= outdata
.write_fd(fd
);
510 cerr
<< "error writing to file: " << cpp_strerror(ret
) << std::endl
;
513 if (outdata
.length() < op_size
)
515 offset
+= outdata
.length();
521 VOID_TEMP_FAILURE_RETRY(::close(fd
));
525 static int do_copy(IoCtx
& io_ctx
, const char *objname
,
526 IoCtx
& target_ctx
, const char *target_obj
)
528 uint32_t src_fadvise_flags
= LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
| LIBRADOS_OP_FLAG_FADVISE_NOCACHE
;
529 uint32_t dest_fadvise_flags
= LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
| LIBRADOS_OP_FLAG_FADVISE_DONTNEED
;
530 ObjectWriteOperation op
;
531 op
.copy_from(objname
, io_ctx
, 0, src_fadvise_flags
);
532 op
.set_op_flags2(dest_fadvise_flags
);
534 return target_ctx
.operate(target_obj
, &op
);
537 static int do_copy_pool(Rados
& rados
, const char *src_pool
, const char *target_pool
)
539 IoCtx src_ctx
, target_ctx
;
540 int ret
= rados
.ioctx_create(src_pool
, src_ctx
);
542 cerr
<< "cannot open source pool: " << src_pool
<< std::endl
;
545 ret
= rados
.ioctx_create(target_pool
, target_ctx
);
547 cerr
<< "cannot open target pool: " << target_pool
<< std::endl
;
550 src_ctx
.set_namespace(all_nspaces
);
551 librados::NObjectIterator i
= src_ctx
.nobjects_begin();
552 librados::NObjectIterator i_end
= src_ctx
.nobjects_end();
553 for (; i
!= i_end
; ++i
) {
554 string nspace
= i
->get_nspace();
555 string oid
= i
->get_oid();
556 string locator
= i
->get_locator();
558 string target_name
= (nspace
.size() ? nspace
+ "/" : "") + oid
;
559 string src_name
= target_name
;
561 src_name
+= "(@" + locator
+ ")";
562 cout
<< src_pool
<< ":" << src_name
<< " => "
563 << target_pool
<< ":" << target_name
<< std::endl
;
565 src_ctx
.locator_set_key(locator
);
566 src_ctx
.set_namespace(nspace
);
567 target_ctx
.set_namespace(nspace
);
568 ret
= do_copy(src_ctx
, oid
.c_str(), target_ctx
, oid
.c_str());
570 cerr
<< "error copying object: " << cpp_strerror(errno
) << std::endl
;
578 static int do_put(IoCtx
& io_ctx
,
579 const std::string
& oid
, const char *infile
, int op_size
,
580 uint64_t obj_offset
, bool create_object
,
581 const bool use_striper
)
583 bool stdio
= (strcmp(infile
, "-") == 0);
585 int fd
= STDIN_FILENO
;
587 fd
= open(infile
, O_RDONLY
|O_BINARY
);
589 cerr
<< "error reading input file " << infile
<< ": " << cpp_strerror(errno
) << std::endl
;
593 uint64_t offset
= obj_offset
;
596 count
= indata
.read_fd(fd
, op_size
);
599 cerr
<< "error reading input file " << infile
<< ": " << cpp_strerror(ret
) << std::endl
;
604 if (offset
== obj_offset
) { // in case we have to create an empty object & if obj_offset > 0 do a hole
605 ret
= detail::write_full(io_ctx
, oid
, indata
, use_striper
); // indata is empty
612 ret
= detail::trunc(io_ctx
, oid
, offset
, use_striper
); // before truncate, object must be existed.
622 if (0 == offset
&& create_object
)
623 ret
= detail::write_full(io_ctx
, oid
, indata
, use_striper
);
625 ret
= detail::write(io_ctx
, oid
, indata
, count
, offset
, use_striper
);
634 if (fd
!= STDOUT_FILENO
)
635 VOID_TEMP_FAILURE_RETRY(close(fd
));
639 static int do_append(IoCtx
& io_ctx
,
640 const std::string
& oid
, const char *infile
, int op_size
,
641 const bool use_striper
)
643 bool stdio
= (strcmp(infile
, "-") == 0);
645 int fd
= STDIN_FILENO
;
647 fd
= open(infile
, O_RDONLY
|O_BINARY
);
649 cerr
<< "error reading input file " << infile
<< ": " << cpp_strerror(errno
) << std::endl
;
655 count
= indata
.read_fd(fd
, op_size
);
658 cerr
<< "error reading input file " << infile
<< ": " << cpp_strerror(ret
) << std::endl
;
661 ret
= detail::append(io_ctx
, oid
, indata
, count
, use_striper
);
669 if (fd
!= STDOUT_FILENO
)
670 VOID_TEMP_FAILURE_RETRY(close(fd
));
674 class RadosWatchCtx
: public librados::WatchCtx2
{
678 RadosWatchCtx(IoCtx
& io
, const char *imgname
) : ioctx(io
), name(imgname
) {}
679 ~RadosWatchCtx() override
{}
680 void handle_notify(uint64_t notify_id
,
682 uint64_t notifier_id
,
683 bufferlist
& bl
) override
{
685 << " cookie " << cookie
686 << " notify_id " << notify_id
687 << " from " << notifier_id
690 ioctx
.notify_ack(name
, notify_id
, cookie
, bl
);
692 void handle_error(uint64_t cookie
, int err
) override
{
694 << " cookie " << cookie
695 << " err " << cpp_strerror(err
)
700 static const char alphanum_table
[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
702 void gen_rand_alphanumeric(char *dest
, int size
) /* size should be the required string size + 1 */
704 const int max
= sizeof(alphanum_table
) - 2;
707 for (i
=0; i
<size
- 1; i
++) {
708 int pos
= generate_random_number(0, max
);
709 dest
[i
] = alphanum_table
[pos
];
721 size_t total_completed
;
726 map
<int, obj_info
> objs
;
741 size_t target_throughput
;
742 size_t offset_align
= 0;
758 librados::AioCompletion
*completion
;
760 LoadGenOp() : id(0), type(0), off(0), len(0), lg(NULL
), completion(NULL
) {}
761 explicit LoadGenOp(LoadGen
*_lg
) : id(0), type(0), off(0), len(0), lg(_lg
), completion(NULL
) {}
766 map
<int, LoadGenOp
*> pending_ops
;
768 void gen_op(LoadGenOp
*op
);
769 uint64_t gen_next_op();
770 void run_op(LoadGenOp
*op
);
772 uint64_t cur_sent_rate() {
773 return total_sent
/ time_passed();
776 uint64_t cur_completed_rate() {
777 return total_completed
/ time_passed();
780 uint64_t total_expected() {
781 return target_throughput
* time_passed();
784 float time_passed() {
785 utime_t now
= ceph_clock_now();
787 uint64_t ns
= now
.nsec();
788 float total
= (float) ns
/ 1000000000.0;
793 ceph::mutex lock
= ceph::make_mutex("LoadGen");
794 ceph::condition_variable cond
;
796 explicit LoadGen(Rados
*_rados
) : rados(_rados
), going_down(false) {
799 max_obj_len
= 5ull * 1024ull * 1024ull * 1024ull;
801 target_throughput
= 5 * 1024 * 1024; // B/sec
802 max_op_len
= 2 * 1024 * 1024;
804 max_backlog
= target_throughput
* 2;
812 int bootstrap(const char *pool
);
816 void io_cb(completion_t c
, LoadGenOp
*op
) {
817 std::lock_guard l
{lock
};
819 total_completed
+= op
->len
;
821 double rate
= (double)cur_completed_rate() / (1024 * 1024);
822 std::streamsize original_precision
= cout
.precision();
824 cout
<< "op " << op
->id
<< " completed, throughput=" << rate
<< "MB/sec" << std::endl
;
825 cout
.precision(original_precision
);
827 map
<int, LoadGenOp
*>::iterator iter
= pending_ops
.find(op
->id
);
828 if (iter
!= pending_ops
.end())
829 pending_ops
.erase(iter
);
832 op
->completion
->release();
840 static void _load_gen_cb(completion_t c
, void *param
)
842 LoadGen::LoadGenOp
*op
= (LoadGen::LoadGenOp
*)param
;
843 op
->lg
->io_cb(c
, op
);
846 int LoadGen::bootstrap(const char *pool
)
852 cerr
<< "ERROR: pool name was not specified" << std::endl
;
856 int ret
= rados
->ioctx_create(pool
, io_ctx
);
858 cerr
<< "error opening pool " << pool
<< ": " << cpp_strerror(ret
) << std::endl
;
863 bufferptr p
= buffer::create(buf_len
);
865 memset(p
.c_str(), 0, buf_len
);
868 list
<librados::AioCompletion
*> completions
;
869 for (i
= 0; i
< num_objs
; i
++) {
871 gen_rand_alphanumeric(buf
, 16);
873 info
.name
.append(buf
);
874 info
.len
= generate_random_number(min_obj_len
, max_obj_len
);
877 while (completions
.size() > max_ops
) {
878 AioCompletion
*c
= completions
.front();
879 c
->wait_for_complete();
880 ret
= c
->get_return_value();
882 completions
.pop_front();
884 cerr
<< "aio_write failed" << std::endl
;
889 librados::AioCompletion
*c
= rados
->aio_create_completion(nullptr, nullptr);
890 completions
.push_back(c
);
892 ret
= io_ctx
.aio_write(info
.name
, c
, bl
, buf_len
, info
.len
- buf_len
);
894 cerr
<< "couldn't write obj: " << info
.name
<< " ret=" << ret
<< std::endl
;
900 list
<librados::AioCompletion
*>::iterator iter
;
901 for (iter
= completions
.begin(); iter
!= completions
.end(); ++iter
) {
902 AioCompletion
*c
= *iter
;
903 c
->wait_for_complete();
904 ret
= c
->get_return_value();
906 if (ret
< 0) { // yes, we leak.
907 cerr
<< "aio_write failed" << std::endl
;
914 void LoadGen::run_op(LoadGenOp
*op
)
916 op
->completion
= rados
->aio_create_completion(op
, _load_gen_cb
);
920 io_ctx
.aio_read(op
->oid
, op
->completion
, &op
->bl
, op
->len
, op
->off
);
923 bufferptr p
= buffer::create(op
->len
);
924 memset(p
.c_str(), 0, op
->len
);
927 io_ctx
.aio_write(op
->oid
, op
->completion
, op
->bl
, op
->len
, op
->off
);
931 total_sent
+= op
->len
;
934 void LoadGen::gen_op(LoadGenOp
*op
)
936 int i
= generate_random_number
<int>(0, objs
.size() - 1);
937 obj_info
& info
= objs
[i
];
940 size_t len
= generate_random_number(min_op_len
, max_op_len
);
943 size_t off
= generate_random_number
<size_t>(0, info
.len
);
945 if (off
+ len
> info
.len
)
946 off
= info
.len
- len
;
949 off
= p2align(off
, offset_align
);
954 i
= generate_random_number(1, 100);
955 if (i
> read_percent
)
960 cout
<< (op
->type
== OP_READ
? "READ" : "WRITE") << " : oid=" << op
->oid
<< " off=" << op
->off
<< " len=" << op
->len
<< std::endl
;
963 uint64_t LoadGen::gen_next_op()
967 LoadGenOp
*op
= new LoadGenOp(this);
970 pending_ops
[op
->id
] = op
;
981 start_time
= ceph_clock_now();
982 utime_t end_time
= start_time
;
983 end_time
+= run_length
;
984 utime_t stamp_time
= start_time
;
985 uint32_t total_sec
= 0;
989 std::unique_lock l
{lock
};
990 cond
.wait_for(l
, 1s
);
992 utime_t now
= ceph_clock_now();
997 uint64_t expected
= total_expected();
999 uint64_t sent
= total_sent
;
1000 uint64_t completed
= total_completed
;
1003 if (now
- stamp_time
>= utime_t(1, 0)) {
1004 double rate
= (double)cur_completed_rate() / (1024 * 1024);
1006 std::streamsize original_precision
= cout
.precision();
1008 cout
<< std::setw(5) << total_sec
<< ": throughput=" << rate
<< "MB/sec" << " pending data=" << sent
- completed
<< std::endl
;
1009 cout
.precision(original_precision
);
1013 while (sent
< expected
&&
1014 sent
- completed
< max_backlog
&&
1015 pending_ops
.size() < max_ops
) {
1016 sent
+= gen_next_op();
1020 // get a reference to all pending requests
1021 vector
<librados::AioCompletion
*> completions
;
1024 map
<int, LoadGenOp
*>::iterator iter
;
1025 for (iter
= pending_ops
.begin(); iter
!= pending_ops
.end(); ++iter
) {
1026 LoadGenOp
*op
= iter
->second
;
1027 completions
.push_back(op
->completion
);
1031 cout
<< "waiting for all operations to complete" << std::endl
;
1033 // now wait on all the pending requests
1034 for (vector
<librados::AioCompletion
*>::iterator citer
= completions
.begin(); citer
!= completions
.end(); ++citer
) {
1035 librados::AioCompletion
*c
= *citer
;
1036 c
->wait_for_complete();
1043 void LoadGen::cleanup()
1045 cout
<< "cleaning up objects" << std::endl
;
1046 map
<int, obj_info
>::iterator iter
;
1047 for (iter
= objs
.begin(); iter
!= objs
.end(); ++iter
) {
1048 obj_info
& info
= iter
->second
;
1049 int ret
= io_ctx
.remove(info
.name
);
1051 cerr
<< "couldn't remove obj: " << info
.name
<< " ret=" << ret
<< std::endl
;
1056 OP_WRITE_DEST_OBJ
= 2 << 0,
1057 OP_WRITE_DEST_OMAP
= 2 << 1,
1058 OP_WRITE_DEST_XATTR
= 2 << 2,
1061 class RadosBencher
: public ObjBencher
{
1062 librados::AioCompletion
**completions
;
1063 librados::Rados
& rados
;
1064 librados::IoCtx
& io_ctx
;
1065 librados::NObjectIterator oi
;
1066 bool iterator_valid
;
1067 OpWriteDest write_destination
;
1070 int completions_init(int concurrentios
) override
{
1071 completions
= new librados::AioCompletion
*[concurrentios
];
1074 void completions_done() override
{
1075 delete[] completions
;
1078 int create_completion(int slot
, void (*cb
)(void *, void*), void *arg
) override
{
1079 completions
[slot
] = rados
.aio_create_completion((void *) arg
, cb
);
1081 if (!completions
[slot
])
1086 void release_completion(int slot
) override
{
1087 completions
[slot
]->release();
1088 completions
[slot
] = 0;
1091 int aio_read(const std::string
& oid
, int slot
, bufferlist
*pbl
, size_t len
,
1092 size_t offset
) override
{
1093 return io_ctx
.aio_read(oid
, completions
[slot
], pbl
, len
, offset
);
1096 int aio_write(const std::string
& oid
, int slot
, bufferlist
& bl
, size_t len
,
1097 size_t offset
) override
{
1098 librados::ObjectWriteOperation op
;
1100 if (write_destination
& OP_WRITE_DEST_OBJ
) {
1102 op
.set_alloc_hint2(data
.object_size
, data
.op_size
,
1103 ALLOC_HINT_FLAG_SEQUENTIAL_WRITE
|
1104 ALLOC_HINT_FLAG_SEQUENTIAL_READ
|
1105 ALLOC_HINT_FLAG_APPEND_ONLY
|
1106 ALLOC_HINT_FLAG_IMMUTABLE
);
1107 op
.write(offset
, bl
);
1110 if (write_destination
& OP_WRITE_DEST_OMAP
) {
1111 std::map
<std::string
, librados::bufferlist
> omap
;
1112 omap
[string("bench-omap-key-") + stringify(offset
)] = bl
;
1116 if (write_destination
& OP_WRITE_DEST_XATTR
) {
1118 snprintf(key
, sizeof(key
), "bench-xattr-key-%d", (int)offset
);
1119 op
.setxattr(key
, bl
);
1122 return io_ctx
.aio_operate(oid
, completions
[slot
], &op
);
1125 int aio_remove(const std::string
& oid
, int slot
) override
{
1126 return io_ctx
.aio_remove(oid
, completions
[slot
]);
1129 int sync_read(const std::string
& oid
, bufferlist
& bl
, size_t len
) override
{
1130 return io_ctx
.read(oid
, bl
, len
, 0);
1132 int sync_write(const std::string
& oid
, bufferlist
& bl
, size_t len
) override
{
1133 return io_ctx
.write_full(oid
, bl
);
1136 int sync_remove(const std::string
& oid
) override
{
1137 return io_ctx
.remove(oid
);
1140 bool completion_is_done(int slot
) override
{
1141 return completions
[slot
] && completions
[slot
]->is_complete();
1144 int completion_wait(int slot
) override
{
1145 return completions
[slot
]->wait_for_complete_and_cb();
1147 int completion_ret(int slot
) override
{
1148 return completions
[slot
]->get_return_value();
1151 bool get_objects(std::list
<Object
>* objects
, int num
) override
{
1154 if (!iterator_valid
) {
1155 oi
= io_ctx
.nobjects_begin();
1156 iterator_valid
= true;
1159 librados::NObjectIterator ei
= io_ctx
.nobjects_end();
1162 iterator_valid
= false;
1167 for ( ; oi
!= ei
&& count
< num
; ++oi
) {
1168 Object
obj(oi
->get_oid(), oi
->get_nspace());
1169 objects
->push_back(obj
);
1176 void set_namespace( const std::string
& ns
) override
{
1177 io_ctx
.set_namespace(ns
);
1181 RadosBencher(CephContext
*cct_
, librados::Rados
& _r
, librados::IoCtx
& _i
)
1182 : ObjBencher(cct_
), completions(NULL
), rados(_r
), io_ctx(_i
), iterator_valid(false), write_destination(OP_WRITE_DEST_OBJ
) {}
1183 ~RadosBencher() override
{ }
1185 void set_write_destination(OpWriteDest dest
) {
1186 write_destination
= dest
;
1190 static int do_lock_cmd(std::vector
<const char*> &nargs
,
1191 const std::map
< std::string
, std::string
> &opts
,
1193 Formatter
*formatter
)
1195 if (nargs
.size() < 3)
1198 string
cmd(nargs
[1]);
1199 string
oid(nargs
[2]);
1203 string lock_description
;
1204 int lock_duration
= 0;
1205 ClsLockType lock_type
= ClsLockType::EXCLUSIVE
;
1207 map
<string
, string
>::const_iterator i
;
1208 i
= opts
.find("lock-tag");
1209 if (i
!= opts
.end()) {
1210 lock_tag
= i
->second
;
1212 i
= opts
.find("lock-cookie");
1213 if (i
!= opts
.end()) {
1214 lock_cookie
= i
->second
;
1216 i
= opts
.find("lock-description");
1217 if (i
!= opts
.end()) {
1218 lock_description
= i
->second
;
1220 i
= opts
.find("lock-duration");
1221 if (i
!= opts
.end()) {
1222 if (rados_sistrtoll(i
, &lock_duration
)) {
1226 i
= opts
.find("lock-type");
1227 if (i
!= opts
.end()) {
1228 const string
& type_str
= i
->second
;
1229 if (type_str
.compare("exclusive") == 0) {
1230 lock_type
= ClsLockType::EXCLUSIVE
;
1231 } else if (type_str
.compare("shared") == 0) {
1232 lock_type
= ClsLockType::SHARED
;
1234 cerr
<< "unknown lock type was specified, aborting" << std::endl
;
1239 if (cmd
.compare("list") == 0) {
1241 int ret
= rados::cls::lock::list_locks(ioctx
, oid
, &locks
);
1243 cerr
<< "ERROR: rados_list_locks(): " << cpp_strerror(ret
) << std::endl
;
1247 formatter
->open_object_section("object");
1248 formatter
->dump_string("objname", oid
);
1249 formatter
->open_array_section("locks");
1250 list
<string
>::iterator iter
;
1251 for (iter
= locks
.begin(); iter
!= locks
.end(); ++iter
) {
1252 formatter
->open_object_section("lock");
1253 formatter
->dump_string("name", *iter
);
1254 formatter
->close_section();
1256 formatter
->close_section();
1257 formatter
->close_section();
1258 formatter
->flush(cout
);
1262 if (nargs
.size() < 4)
1265 string
lock_name(nargs
[3]);
1267 if (cmd
.compare("info") == 0) {
1268 map
<rados::cls::lock::locker_id_t
, rados::cls::lock::locker_info_t
> lockers
;
1269 ClsLockType type
= ClsLockType::NONE
;
1271 int ret
= rados::cls::lock::get_lock_info(ioctx
, oid
, lock_name
, &lockers
, &type
, &tag
);
1273 cerr
<< "ERROR: rados_lock_get_lock_info(): " << cpp_strerror(ret
) << std::endl
;
1277 formatter
->open_object_section("lock");
1278 formatter
->dump_string("name", lock_name
);
1279 formatter
->dump_string("type", cls_lock_type_str(type
));
1280 formatter
->dump_string("tag", tag
);
1281 formatter
->open_array_section("lockers");
1282 map
<rados::cls::lock::locker_id_t
, rados::cls::lock::locker_info_t
>::iterator iter
;
1283 for (iter
= lockers
.begin(); iter
!= lockers
.end(); ++iter
) {
1284 const rados::cls::lock::locker_id_t
& id
= iter
->first
;
1285 const rados::cls::lock::locker_info_t
& info
= iter
->second
;
1286 formatter
->open_object_section("locker");
1287 formatter
->dump_stream("name") << id
.locker
;
1288 formatter
->dump_string("cookie", id
.cookie
);
1289 formatter
->dump_string("description", info
.description
);
1290 formatter
->dump_stream("expiration") << info
.expiration
;
1291 formatter
->dump_stream("addr") << info
.addr
.get_legacy_str();
1292 formatter
->close_section();
1294 formatter
->close_section();
1295 formatter
->close_section();
1296 formatter
->flush(cout
);
1299 } else if (cmd
.compare("get") == 0) {
1300 rados::cls::lock::Lock
l(lock_name
);
1301 l
.set_cookie(lock_cookie
);
1302 l
.set_tag(lock_tag
);
1303 l
.set_duration(utime_t(lock_duration
, 0));
1304 l
.set_description(lock_description
);
1306 switch (lock_type
) {
1307 case ClsLockType::SHARED
:
1308 ret
= l
.lock_shared(ioctx
, oid
);
1311 ret
= l
.lock_exclusive(ioctx
, oid
);
1314 cerr
<< "ERROR: failed locking: " << cpp_strerror(ret
) << std::endl
;
1321 if (nargs
.size() < 5)
1324 if (cmd
.compare("break") == 0) {
1325 const char* locker
= nargs
[4];
1326 rados::cls::lock::Lock
l(lock_name
);
1327 l
.set_cookie(lock_cookie
);
1328 l
.set_tag(lock_tag
);
1330 if (!name
.parse(locker
)) {
1331 cerr
<< "ERROR: failed to parse locker name (" << locker
<< ")" << std::endl
;
1334 int ret
= l
.break_lock(ioctx
, oid
, name
);
1336 cerr
<< "ERROR: failed breaking lock: " << cpp_strerror(ret
) << std::endl
;
1346 static int do_cache_flush(IoCtx
& io_ctx
, string oid
)
1348 ObjectReadOperation op
;
1350 librados::AioCompletion
*completion
=
1351 librados::Rados::aio_create_completion();
1352 io_ctx
.aio_operate(oid
.c_str(), completion
, &op
,
1353 librados::OPERATION_IGNORE_CACHE
|
1354 librados::OPERATION_IGNORE_OVERLAY
,
1356 completion
->wait_for_complete();
1357 int r
= completion
->get_return_value();
1358 completion
->release();
1362 static int do_cache_try_flush(IoCtx
& io_ctx
, string oid
)
1364 ObjectReadOperation op
;
1365 op
.cache_try_flush();
1366 librados::AioCompletion
*completion
=
1367 librados::Rados::aio_create_completion();
1368 io_ctx
.aio_operate(oid
.c_str(), completion
, &op
,
1369 librados::OPERATION_IGNORE_CACHE
|
1370 librados::OPERATION_IGNORE_OVERLAY
|
1371 librados::OPERATION_SKIPRWLOCKS
,
1373 completion
->wait_for_complete();
1374 int r
= completion
->get_return_value();
1375 completion
->release();
1379 static int do_cache_evict(IoCtx
& io_ctx
, string oid
)
1381 ObjectReadOperation op
;
1383 librados::AioCompletion
*completion
=
1384 librados::Rados::aio_create_completion();
1385 io_ctx
.aio_operate(oid
.c_str(), completion
, &op
,
1386 librados::OPERATION_IGNORE_CACHE
|
1387 librados::OPERATION_IGNORE_OVERLAY
|
1388 librados::OPERATION_SKIPRWLOCKS
,
1390 completion
->wait_for_complete();
1391 int r
= completion
->get_return_value();
1392 completion
->release();
1396 static int do_cache_flush_evict_all(IoCtx
& io_ctx
, bool blocking
)
1399 io_ctx
.set_namespace(all_nspaces
);
1401 librados::NObjectIterator i
= io_ctx
.nobjects_begin();
1402 librados::NObjectIterator i_end
= io_ctx
.nobjects_end();
1403 for (; i
!= i_end
; ++i
) {
1405 cout
<< i
->get_nspace() << "\t" << i
->get_oid() << "\t" << i
->get_locator() << std::endl
;
1406 if (i
->get_locator().size()) {
1407 io_ctx
.locator_set_key(i
->get_locator());
1409 io_ctx
.locator_set_key(string());
1411 io_ctx
.set_namespace(i
->get_nspace());
1413 io_ctx
.snap_set_read(LIBRADOS_SNAP_DIR
);
1414 r
= io_ctx
.list_snaps(i
->get_oid(), &ls
);
1416 cerr
<< "error listing snap shots " << i
->get_nspace() << "/" << i
->get_oid() << ": "
1417 << cpp_strerror(r
) << std::endl
;
1421 std::vector
<clone_info_t
>::iterator ci
= ls
.clones
.begin();
1423 if (ci
== ls
.clones
.end()) {
1424 io_ctx
.snap_set_read(CEPH_NOSNAP
);
1426 r
= do_cache_flush(io_ctx
, i
->get_oid());
1428 r
= do_cache_try_flush(io_ctx
, i
->get_oid());
1430 cerr
<< "failed to flush " << i
->get_nspace() << "/" << i
->get_oid() << ": "
1431 << cpp_strerror(r
) << std::endl
;
1435 r
= do_cache_evict(io_ctx
, i
->get_oid());
1437 cerr
<< "failed to evict " << i
->get_nspace() << "/" << i
->get_oid() << ": "
1438 << cpp_strerror(r
) << std::endl
;
1444 for (std::vector
<clone_info_t
>::iterator ci
= ls
.clones
.begin();
1445 ci
!= ls
.clones
.end(); ++ci
) {
1446 io_ctx
.snap_set_read(ci
->cloneid
);
1448 r
= do_cache_flush(io_ctx
, i
->get_oid());
1450 r
= do_cache_try_flush(io_ctx
, i
->get_oid());
1452 cerr
<< "failed to flush " << i
->get_nspace() << "/" << i
->get_oid() << ": "
1453 << cpp_strerror(r
) << std::endl
;
1457 r
= do_cache_evict(io_ctx
, i
->get_oid());
1459 cerr
<< "failed to evict " << i
->get_nspace() << "/" << i
->get_oid() << ": "
1460 << cpp_strerror(r
) << std::endl
;
1468 catch (const std::exception
& e
) {
1469 cerr
<< e
.what() << std::endl
;
1472 return errors
? -1 : 0;
1475 static int do_get_inconsistent_pg_cmd(const std::vector
<const char*> &nargs
,
1477 Formatter
& formatter
)
1479 if (nargs
.size() < 2) {
1482 int64_t pool_id
= rados
.pool_lookup(nargs
[1]);
1484 cerr
<< "pool \"" << nargs
[1] << "\" not found" << std::endl
;
1485 return (int)pool_id
;
1487 std::vector
<PlacementGroup
> pgs
;
1488 int ret
= rados
.get_inconsistent_pgs(pool_id
, &pgs
);
1492 formatter
.open_array_section("pgs");
1493 for (auto& pg
: pgs
) {
1494 formatter
.dump_stream("pg") << pg
;
1496 formatter
.close_section();
1497 formatter
.flush(cout
);
1502 static void dump_errors(const err_t
&err
, Formatter
&f
, const char *name
)
1504 f
.open_array_section(name
);
1505 if (err
.has_shard_missing())
1506 f
.dump_string("error", "missing");
1507 if (err
.has_stat_error())
1508 f
.dump_string("error", "stat_error");
1509 if (err
.has_read_error())
1510 f
.dump_string("error", "read_error");
1511 if (err
.has_data_digest_mismatch_info())
1512 f
.dump_string("error", "data_digest_mismatch_info");
1513 if (err
.has_omap_digest_mismatch_info())
1514 f
.dump_string("error", "omap_digest_mismatch_info");
1515 if (err
.has_size_mismatch_info())
1516 f
.dump_string("error", "size_mismatch_info");
1517 if (err
.has_ec_hash_error())
1518 f
.dump_string("error", "ec_hash_error");
1519 if (err
.has_ec_size_error())
1520 f
.dump_string("error", "ec_size_error");
1521 if (err
.has_info_missing())
1522 f
.dump_string("error", "info_missing");
1523 if (err
.has_info_corrupted())
1524 f
.dump_string("error", "info_corrupted");
1525 if (err
.has_obj_size_info_mismatch())
1526 f
.dump_string("error", "obj_size_info_mismatch");
1527 if (err
.has_snapset_missing())
1528 f
.dump_string("error", "snapset_missing");
1529 if (err
.has_snapset_corrupted())
1530 f
.dump_string("error", "snapset_corrupted");
1531 if (err
.has_hinfo_missing())
1532 f
.dump_string("error", "hinfo_missing");
1533 if (err
.has_hinfo_corrupted())
1534 f
.dump_string("error", "hinfo_corrupted");
1538 static void dump_shard(const shard_info_t
& shard
,
1539 const inconsistent_obj_t
& inc
,
1542 dump_errors(shard
, f
, "errors");
1544 if (shard
.has_shard_missing())
1547 if (!shard
.has_stat_error())
1548 f
.dump_unsigned("size", shard
.size
);
1549 if (shard
.omap_digest_present
) {
1550 f
.dump_format("omap_digest", "0x%08x", shard
.omap_digest
);
1552 if (shard
.data_digest_present
) {
1553 f
.dump_format("data_digest", "0x%08x", shard
.data_digest
);
1556 if ((inc
.union_shards
.has_info_missing()
1557 || inc
.union_shards
.has_info_corrupted()
1558 || inc
.has_object_info_inconsistency()
1559 || shard
.has_obj_size_info_mismatch()) &&
1560 !shard
.has_info_missing()) {
1561 map
<std::string
, ceph::bufferlist
>::iterator k
= (const_cast<shard_info_t
&>(shard
)).attrs
.find(OI_ATTR
);
1562 ceph_assert(k
!= shard
.attrs
.end()); // Can't be missing
1563 if (!shard
.has_info_corrupted()) {
1566 auto bliter
= k
->second
.cbegin();
1567 decode(oi
, bliter
); // Can't be corrupted
1568 f
.open_object_section("object_info");
1573 f
.dump_string("object_info", cleanbin(k
->second
, b64
));
1576 if ((inc
.union_shards
.has_snapset_missing()
1577 || inc
.union_shards
.has_snapset_corrupted()
1578 || inc
.has_snapset_inconsistency()) &&
1579 !shard
.has_snapset_missing()) {
1580 map
<std::string
, ceph::bufferlist
>::iterator k
= (const_cast<shard_info_t
&>(shard
)).attrs
.find(SS_ATTR
);
1581 ceph_assert(k
!= shard
.attrs
.end()); // Can't be missing
1582 if (!shard
.has_snapset_corrupted()) {
1585 auto bliter
= k
->second
.cbegin();
1586 decode(ss
, bliter
); // Can't be corrupted
1587 f
.open_object_section("snapset");
1592 f
.dump_string("snapset", cleanbin(k
->second
, b64
));
1595 if ((inc
.union_shards
.has_hinfo_missing()
1596 || inc
.union_shards
.has_hinfo_corrupted()
1597 || inc
.has_hinfo_inconsistency()) &&
1598 !shard
.has_hinfo_missing()) {
1599 map
<std::string
, ceph::bufferlist
>::iterator k
= (const_cast<shard_info_t
&>(shard
)).attrs
.find(ECUtil::get_hinfo_key());
1600 ceph_assert(k
!= shard
.attrs
.end()); // Can't be missing
1601 if (!shard
.has_hinfo_corrupted()) {
1602 ECUtil::HashInfo hi
;
1604 auto bliter
= k
->second
.cbegin();
1605 decode(hi
, bliter
); // Can't be corrupted
1606 f
.open_object_section("hashinfo");
1611 f
.dump_string("hashinfo", cleanbin(k
->second
, b64
));
1614 if (inc
.has_attr_name_mismatch() || inc
.has_attr_value_mismatch()) {
1615 f
.open_array_section("attrs");
1616 for (auto kv
: shard
.attrs
) {
1617 // System attribute handled above
1618 if (kv
.first
== OI_ATTR
|| kv
.first
[0] != '_')
1620 f
.open_object_section("attr");
1621 // Skip leading underscore since only giving user attrs
1622 f
.dump_string("name", kv
.first
.substr(1));
1624 f
.dump_string("value", cleanbin(kv
.second
, b64
));
1625 f
.dump_bool("Base64", b64
);
1632 static void dump_obj_errors(const obj_err_t
&err
, Formatter
&f
)
1634 f
.open_array_section("errors");
1635 if (err
.has_object_info_inconsistency())
1636 f
.dump_string("error", "object_info_inconsistency");
1637 if (err
.has_data_digest_mismatch())
1638 f
.dump_string("error", "data_digest_mismatch");
1639 if (err
.has_omap_digest_mismatch())
1640 f
.dump_string("error", "omap_digest_mismatch");
1641 if (err
.has_size_mismatch())
1642 f
.dump_string("error", "size_mismatch");
1643 if (err
.has_attr_value_mismatch())
1644 f
.dump_string("error", "attr_value_mismatch");
1645 if (err
.has_attr_name_mismatch())
1646 f
.dump_string("error", "attr_name_mismatch");
1647 if (err
.has_snapset_inconsistency())
1648 f
.dump_string("error", "snapset_inconsistency");
1649 if (err
.has_hinfo_inconsistency())
1650 f
.dump_string("error", "hinfo_inconsistency");
1651 if (err
.has_size_too_large())
1652 f
.dump_string("error", "size_too_large");
1656 static void dump_object_id(const object_id_t
& object
,
1659 f
.dump_string("name", object
.name
);
1660 f
.dump_string("nspace", object
.nspace
);
1661 f
.dump_string("locator", object
.locator
);
1662 switch (object
.snap
) {
1664 f
.dump_string("snap", "head");
1667 f
.dump_string("snap", "snapdir");
1670 f
.dump_unsigned("snap", object
.snap
);
1675 static void dump_inconsistent(const inconsistent_obj_t
& inc
,
1678 f
.open_object_section("object");
1679 dump_object_id(inc
.object
, f
);
1680 f
.dump_unsigned("version", inc
.version
);
1683 dump_obj_errors(inc
, f
);
1684 dump_errors(inc
.union_shards
, f
, "union_shard_errors");
1685 for (const auto& shard_info
: inc
.shards
) {
1686 shard_info_t shard
= const_cast<shard_info_t
&>(shard_info
.second
);
1687 if (shard
.selected_oi
) {
1690 auto k
= shard
.attrs
.find(OI_ATTR
);
1691 ceph_assert(k
!= shard
.attrs
.end()); // Can't be missing
1692 auto bliter
= k
->second
.cbegin();
1693 decode(oi
, bliter
); // Can't be corrupted
1694 f
.open_object_section("selected_object_info");
1700 f
.open_array_section("shards");
1701 for (const auto& shard_info
: inc
.shards
) {
1702 f
.open_object_section("shard");
1703 auto& osd_shard
= shard_info
.first
;
1704 f
.dump_int("osd", osd_shard
.osd
);
1705 f
.dump_bool("primary", shard_info
.second
.primary
);
1706 auto shard
= osd_shard
.shard
;
1707 if (shard
!= shard_id_t::NO_SHARD
)
1708 f
.dump_unsigned("shard", shard
);
1709 dump_shard(shard_info
.second
, inc
, f
);
1715 static void dump_inconsistent(const inconsistent_snapset_t
& inc
,
1718 dump_object_id(inc
.object
, f
);
1720 if (inc
.ss_bl
.length()) {
1722 bufferlist bl
= inc
.ss_bl
;
1723 auto bliter
= bl
.cbegin();
1724 decode(ss
, bliter
); // Can't be corrupted
1725 f
.open_object_section("snapset");
1729 f
.open_array_section("errors");
1730 if (inc
.snapset_missing())
1731 f
.dump_string("error", "snapset_missing");
1732 if (inc
.snapset_corrupted())
1733 f
.dump_string("error", "snapset_corrupted");
1734 if (inc
.info_missing())
1735 f
.dump_string("error", "info_missing");
1736 if (inc
.info_corrupted())
1737 f
.dump_string("error", "info_corrupted");
1738 if (inc
.snapset_error())
1739 f
.dump_string("error", "snapset_error");
1741 f
.dump_string("error", "headless");
1742 if (inc
.size_mismatch())
1743 f
.dump_string("error", "size_mismatch");
1744 if (inc
.extra_clones())
1745 f
.dump_string("error", "extra_clones");
1746 if (inc
.clone_missing())
1747 f
.dump_string("error", "clone_missing");
1750 if (inc
.extra_clones()) {
1751 f
.open_array_section("extra clones");
1752 for (auto snap
: inc
.clones
) {
1753 f
.dump_unsigned("snap", snap
);
1758 if (inc
.clone_missing()) {
1759 f
.open_array_section("missing");
1760 for (auto snap
: inc
.missing
) {
1761 f
.dump_unsigned("snap", snap
);
1767 // dispatch the call by type
1768 static int do_get_inconsistent(Rados
& rados
,
1769 const PlacementGroup
& pg
,
1770 const librados::object_id_t
&start
,
1771 unsigned max_return
,
1773 std::vector
<inconsistent_obj_t
>* objs
,
1776 return rados
.get_inconsistent_objects(pg
, start
, max_return
, c
,
1780 static int do_get_inconsistent(Rados
& rados
,
1781 const PlacementGroup
& pg
,
1782 const librados::object_id_t
&start
,
1783 unsigned max_return
,
1785 std::vector
<inconsistent_snapset_t
>* snapsets
,
1788 return rados
.get_inconsistent_snapsets(pg
, start
, max_return
, c
,
1789 snapsets
, interval
);
1792 template <typename T
>
1793 static int do_get_inconsistent_cmd(const std::vector
<const char*> &nargs
,
1795 Formatter
& formatter
)
1797 if (nargs
.size() < 2) {
1802 ret
= pg
.parse(nargs
[1]);
1804 cerr
<< "bad pg: " << nargs
[1] << std::endl
;
1807 uint32_t interval
= 0, first_interval
= 0;
1808 const unsigned max_item_num
= 32;
1809 bool opened
= false;
1810 for (librados::object_id_t start
;;) {
1811 std::vector
<T
> items
;
1812 auto completion
= librados::Rados::aio_create_completion();
1813 ret
= do_get_inconsistent(rados
, pg
, start
, max_item_num
, completion
,
1815 completion
->wait_for_complete();
1816 ret
= completion
->get_return_value();
1817 completion
->release();
1820 cerr
<< "interval#" << interval
<< " expired." << std::endl
;
1821 else if (ret
== -ENOENT
)
1822 cerr
<< "No scrub information available for pg " << pg
<< std::endl
;
1825 // It must be the same interval every time. EAGAIN would
1826 // occur if interval changes.
1827 ceph_assert(start
.name
.empty() || first_interval
== interval
);
1828 if (start
.name
.empty()) {
1829 first_interval
= interval
;
1830 formatter
.open_object_section("info");
1831 formatter
.dump_int("epoch", interval
);
1832 formatter
.open_array_section("inconsistents");
1835 for (auto& inc
: items
) {
1836 formatter
.open_object_section("inconsistent");
1837 dump_inconsistent(inc
, formatter
);
1838 formatter
.close_section();
1840 if (items
.size() < max_item_num
) {
1841 formatter
.close_section();
1844 if (!items
.empty()) {
1845 start
= items
.back().object
;
1850 formatter
.close_section();
1851 formatter
.flush(cout
);
1856 static std::string
prettify(const std::string
& s
)
1858 if (std::find_if_not(s
.begin(), s
.end(),
1859 (int (*)(int))isprint
) != s
.end()) {
1860 return "(binary key)";
1866 /**********************************************
1868 **********************************************/
1869 static int rados_tool_common(const std::map
< std::string
, std::string
> &opts
,
1870 std::vector
<const char*> &nargs
)
1873 bool create_pool
= false;
1874 const char *pool_name
= NULL
;
1875 const char *target_pool_name
= NULL
;
1876 string oloc
, target_oloc
, nspace
, target_nspace
;
1877 int concurrent_ios
= 16;
1878 unsigned op_size
= default_op_size
;
1879 unsigned object_size
= 0;
1880 unsigned max_objects
= 0;
1881 uint64_t obj_offset
= 0;
1882 bool obj_offset_specified
= false;
1883 bool block_size_specified
= false;
1884 int bench_write_dest
= 0;
1885 bool cleanup
= true;
1886 bool hints
= true; // for rados bench
1887 bool reuse_bench
= false;
1888 bool no_verify
= false;
1889 bool use_striper
= false;
1890 bool with_clones
= false;
1891 const char *snapname
= NULL
;
1892 snap_t snapid
= CEPH_NOSNAP
;
1893 std::map
<std::string
, std::string
>::const_iterator i
;
1895 uint64_t offset_align
= 0;
1896 uint64_t min_obj_len
= 0;
1897 uint64_t max_obj_len
= 0;
1898 uint64_t min_op_len
= 0;
1899 uint64_t max_op_len
= 0;
1900 uint64_t max_ops
= 0;
1901 uint64_t max_backlog
= 0;
1902 uint64_t target_throughput
= 0;
1903 int64_t read_percent
= -1;
1904 uint64_t num_objs
= 0;
1907 bool show_time
= false;
1908 bool wildcard
= false;
1910 std::string run_name
;
1912 bool forcefull
= false;
1913 unique_ptr
<Formatter
> formatter
= nullptr;
1914 bool pretty_format
= false;
1915 const char *output
= NULL
;
1916 std::optional
<std::string
> omap_key
;
1917 std::optional
<std::string
> obj_name
;
1918 std::string input_file
;
1919 bool with_reference
= false;
1924 i
= opts
.find("create");
1925 if (i
!= opts
.end()) {
1928 i
= opts
.find("pool");
1929 if (i
!= opts
.end()) {
1930 pool_name
= i
->second
.c_str();
1932 i
= opts
.find("target_pool");
1933 if (i
!= opts
.end()) {
1934 target_pool_name
= i
->second
.c_str();
1936 i
= opts
.find("object_locator");
1937 if (i
!= opts
.end()) {
1940 i
= opts
.find("target_locator");
1941 if (i
!= opts
.end()) {
1942 target_oloc
= i
->second
;
1944 i
= opts
.find("target_nspace");
1945 if (i
!= opts
.end()) {
1946 target_nspace
= i
->second
;
1948 i
= opts
.find("concurrent-ios");
1949 if (i
!= opts
.end()) {
1950 if (rados_sistrtoll(i
, &concurrent_ios
)) {
1954 i
= opts
.find("run-name");
1955 if (i
!= opts
.end()) {
1956 run_name
= i
->second
;
1959 i
= opts
.find("force-full");
1960 if (i
!= opts
.end()) {
1963 i
= opts
.find("prefix");
1964 if (i
!= opts
.end()) {
1967 i
= opts
.find("block-size");
1968 if (i
!= opts
.end()) {
1969 if (rados_sistrtoll(i
, &op_size
)) {
1972 block_size_specified
= true;
1974 i
= opts
.find("object-size");
1975 if (i
!= opts
.end()) {
1976 if (rados_sistrtoll(i
, &object_size
)) {
1979 block_size_specified
= true;
1981 i
= opts
.find("max-objects");
1982 if (i
!= opts
.end()) {
1983 if (rados_sistrtoll(i
, &max_objects
)) {
1987 i
= opts
.find("offset");
1988 if (i
!= opts
.end()) {
1989 if (rados_sistrtoll(i
, &obj_offset
)) {
1992 obj_offset_specified
= true;
1994 i
= opts
.find("snap");
1995 if (i
!= opts
.end()) {
1996 snapname
= i
->second
.c_str();
1998 i
= opts
.find("snapid");
1999 if (i
!= opts
.end()) {
2000 if (rados_sistrtoll(i
, &snapid
)) {
2004 i
= opts
.find("min-object-size");
2005 if (i
!= opts
.end()) {
2006 if (rados_sistrtoll(i
, &min_obj_len
)) {
2010 i
= opts
.find("max-object-size");
2011 if (i
!= opts
.end()) {
2012 if (rados_sistrtoll(i
, &max_obj_len
)) {
2016 i
= opts
.find("min-op-len");
2017 if (i
!= opts
.end()) {
2018 if (rados_sistrtoll(i
, &min_op_len
)) {
2022 i
= opts
.find("max-op-len");
2023 if (i
!= opts
.end()) {
2024 if (rados_sistrtoll(i
, &max_op_len
)) {
2028 i
= opts
.find("max-ops");
2029 if (i
!= opts
.end()) {
2030 if (rados_sistrtoll(i
, &max_ops
)) {
2034 i
= opts
.find("max-backlog");
2035 if (i
!= opts
.end()) {
2036 if (rados_sistrtoll(i
, &max_backlog
)) {
2040 i
= opts
.find("target-throughput");
2041 if (i
!= opts
.end()) {
2042 if (rados_sistrtoll(i
, &target_throughput
)) {
2046 i
= opts
.find("read-percent");
2047 if (i
!= opts
.end()) {
2048 if (rados_sistrtoll(i
, &read_percent
)) {
2052 i
= opts
.find("num-objects");
2053 if (i
!= opts
.end()) {
2054 if (rados_sistrtoll(i
, &num_objs
)) {
2058 i
= opts
.find("run-length");
2059 if (i
!= opts
.end()) {
2060 if (rados_sistrtoll(i
, &run_length
)) {
2064 i
= opts
.find("show-time");
2065 if (i
!= opts
.end()) {
2068 i
= opts
.find("no-cleanup");
2069 if (i
!= opts
.end()) {
2072 i
= opts
.find("no-hints");
2073 if (i
!= opts
.end()) {
2076 i
= opts
.find("reuse-bench");
2077 if (i
!= opts
.end()) {
2080 i
= opts
.find("pretty-format");
2081 if (i
!= opts
.end()) {
2082 pretty_format
= true;
2084 i
= opts
.find("format");
2085 if (i
!= opts
.end()) {
2086 const char *format
= i
->second
.c_str();
2087 formatter
.reset(Formatter::create(format
));
2089 cerr
<< "unrecognized format: " << format
<< std::endl
;
2093 i
= opts
.find("namespace");
2094 if (i
!= opts
.end()) {
2097 i
= opts
.find("no-verify");
2098 if (i
!= opts
.end()) {
2101 i
= opts
.find("output");
2102 if (i
!= opts
.end()) {
2103 output
= i
->second
.c_str();
2105 i
= opts
.find("write-dest-obj");
2106 if (i
!= opts
.end()) {
2107 bench_write_dest
|= static_cast<int>(OP_WRITE_DEST_OBJ
);
2109 i
= opts
.find("write-dest-omap");
2110 if (i
!= opts
.end()) {
2111 bench_write_dest
|= static_cast<int>(OP_WRITE_DEST_OMAP
);
2113 i
= opts
.find("write-dest-xattr");
2114 if (i
!= opts
.end()) {
2115 bench_write_dest
|= static_cast<int>(OP_WRITE_DEST_XATTR
);
2117 i
= opts
.find("with-clones");
2118 if (i
!= opts
.end()) {
2121 i
= opts
.find("omap-key-file");
2122 if (i
!= opts
.end()) {
2125 ret
= indata
.read_file(i
->second
.c_str(), &err
);
2127 cerr
<< err
<< std::endl
;
2130 omap_key
= std::string(indata
.c_str(), indata
.length());
2132 i
= opts
.find("obj-name-file");
2133 if (i
!= opts
.end()) {
2136 ret
= indata
.read_file(i
->second
.c_str(), &err
);
2138 cerr
<< err
<< std::endl
;
2141 obj_name
= std::string(indata
.c_str(), indata
.length());
2143 i
= opts
.find("offset_align");
2144 if (i
!= opts
.end()) {
2145 if (rados_sistrtoll(i
, &offset_align
)) {
2149 i
= opts
.find("with-reference");
2150 if (i
!= opts
.end()) {
2151 with_reference
= true;
2153 i
= opts
.find("input_file");
2154 if (i
!= opts
.end()) {
2155 input_file
= i
->second
;
2159 ret
= rados
.init_with_context(g_ceph_context
);
2161 cerr
<< "couldn't initialize rados: " << cpp_strerror(ret
) << std::endl
;
2165 ret
= rados
.connect();
2167 cerr
<< "couldn't connect to cluster: " << cpp_strerror(ret
) << std::endl
;
2171 if (create_pool
&& !pool_name
) {
2172 cerr
<< "--create-pool requested but pool_name was not specified!" << std::endl
;
2178 ret
= rados
.pool_create(pool_name
);
2180 cerr
<< "error creating pool " << pool_name
<< ": "
2181 << cpp_strerror(ret
) << std::endl
;
2186 i
= opts
.find("pgid");
2187 boost::optional
<pg_t
> pgid(i
!= opts
.end(), pg_t());
2188 if (pgid
&& (!pgid
->parse(i
->second
.c_str()) || (pool_name
&& rados
.pool_lookup(pool_name
) != pgid
->pool()))) {
2189 cerr
<< "invalid pgid" << std::endl
;
2194 if (pool_name
|| pgid
) {
2195 ret
= pool_name
? rados
.ioctx_create(pool_name
, io_ctx
) : rados
.ioctx_create2(pgid
->pool(), io_ctx
);
2197 cerr
<< "error opening pool "
2198 << (pool_name
? pool_name
: std::string("with id ") + std::to_string(pgid
->pool())) << ": "
2199 << cpp_strerror(ret
) << std::endl
;
2206 ret
= io_ctx
.pool_requires_alignment2(&req
);
2208 cerr
<< "error checking pool alignment requirement"
2209 << cpp_strerror(ret
) << std::endl
;
2215 ret
= io_ctx
.pool_required_alignment2(&align
);
2217 cerr
<< "error getting pool alignment"
2218 << cpp_strerror(ret
) << std::endl
;
2222 const uint64_t prev_op_size
= op_size
;
2223 op_size
= uint64_t((op_size
+ align
- 1) / align
) * align
;
2224 // Warn: if user specified and it was rounded
2225 if (prev_op_size
!= default_op_size
&& prev_op_size
!= op_size
)
2226 cerr
<< "INFO: op_size has been rounded to " << op_size
<< std::endl
;
2230 #ifdef WITH_LIBRADOSSTRIPER
2231 // create striper interface
2232 if (opts
.find("striper") != opts
.end()) {
2233 // Note that this call does a tricky thing by reaching into a "singleton". We count
2234 // on this happening only once:
2235 ret
= RadosStriper::striper_create(io_ctx
, &detail::striper());
2237 cerr
<< "error opening pool " << pool_name
<< " with striper interface: "
2238 << cpp_strerror(ret
) << std::endl
;
2243 #endif // USE_LIBRADOSSTRIPER
2249 cerr
<< "pool name must be specified with --snap" << std::endl
;
2252 ret
= io_ctx
.snap_lookup(snapname
, &snapid
);
2254 cerr
<< "error looking up snap '" << snapname
<< "': " << cpp_strerror(ret
) << std::endl
;
2260 cerr
<< "pool name must be specified with --object-locator" << std::endl
;
2263 io_ctx
.locator_set_key(oloc
);
2265 // Use namespace from command line if specified
2266 if (opts
.find("namespace") != opts
.end()) {
2268 cerr
<< "pool name must be specified with --namespace" << std::endl
;
2271 io_ctx
.set_namespace(nspace
);
2272 // Use wildcard if --all specified and --default NOT specified
2273 } else if (opts
.find("all") != opts
.end() && opts
.find("default") == opts
.end()) {
2274 // Only the ls should ever set namespace to special value
2277 if (snapid
!= CEPH_NOSNAP
) {
2279 cerr
<< "pool name must be specified with --snapid" << std::endl
;
2283 ret
= io_ctx
.snap_get_name(snapid
, &name
);
2285 cerr
<< "snapid " << snapid
<< " doesn't exist in pool "
2286 << io_ctx
.get_pool_name() << std::endl
;
2289 io_ctx
.snap_set_read(snapid
);
2290 cout
<< "selected snap " << snapid
<< " '" << name
<< "'" << std::endl
;
2293 ceph_assert(!nargs
.empty());
2296 if (strcmp(nargs
[0], "lspools") == 0) {
2298 ret
= rados
.pool_list(vec
);
2300 cerr
<< "error listing pools: " << cpp_strerror(ret
) << std::endl
;
2303 for (list
<string
>::iterator i
= vec
.begin(); i
!= vec
.end(); ++i
)
2304 cout
<< *i
<< std::endl
;
2306 else if (strcmp(nargs
[0], "df") == 0) {
2311 ret
= rados
.pool_list(vec
);
2313 cerr
<< "error listing pools: " << cpp_strerror(ret
) << std::endl
;
2317 vec
.push_back(pool_name
);
2320 map
<string
,librados::pool_stat_t
> stats
;
2321 ret
= rados
.get_pool_stats(vec
, stats
);
2323 cerr
<< "error fetching pool stats: " << cpp_strerror(ret
) << std::endl
;
2330 tab
.define_column("POOL_NAME", TextTable::LEFT
, TextTable::LEFT
);
2331 tab
.define_column("USED", TextTable::RIGHT
, TextTable::RIGHT
);
2332 tab
.define_column("OBJECTS", TextTable::RIGHT
, TextTable::RIGHT
);
2333 tab
.define_column("CLONES", TextTable::RIGHT
, TextTable::RIGHT
);
2334 tab
.define_column("COPIES", TextTable::RIGHT
, TextTable::RIGHT
);
2335 tab
.define_column("MISSING_ON_PRIMARY", TextTable::RIGHT
, TextTable::RIGHT
);
2336 tab
.define_column("UNFOUND", TextTable::RIGHT
, TextTable::RIGHT
);
2337 tab
.define_column("DEGRADED", TextTable::RIGHT
, TextTable::RIGHT
);
2338 tab
.define_column("RD_OPS", TextTable::RIGHT
, TextTable::RIGHT
);
2339 tab
.define_column("RD", TextTable::RIGHT
, TextTable::RIGHT
);
2340 tab
.define_column("WR_OPS", TextTable::RIGHT
, TextTable::RIGHT
);
2341 tab
.define_column("WR", TextTable::RIGHT
, TextTable::RIGHT
);
2342 tab
.define_column("USED COMPR", TextTable::RIGHT
, TextTable::RIGHT
);
2343 tab
.define_column("UNDER COMPR", TextTable::RIGHT
, TextTable::RIGHT
);
2345 formatter
->open_object_section("stats");
2346 formatter
->open_array_section("pools");
2348 for (map
<string
,librados::pool_stat_t
>::iterator i
= stats
.begin();
2351 const char *pool_name
= i
->first
.c_str();
2352 librados::pool_stat_t
& s
= i
->second
;
2355 << byte_u_t(s
.num_bytes
)
2357 << s
.num_object_clones
2358 << s
.num_object_copies
2359 << s
.num_objects_missing_on_primary
2360 << s
.num_objects_unfound
2361 << s
.num_objects_degraded
2363 << byte_u_t(s
.num_rd_kb
<< 10)
2365 << byte_u_t(s
.num_wr_kb
<< 10)
2366 << byte_u_t(s
.compressed_bytes_alloc
)
2367 << byte_u_t(s
.compressed_bytes_orig
)
2368 << TextTable::endrow
;
2370 formatter
->open_object_section("pool");
2371 int64_t pool_id
= rados
.pool_lookup(pool_name
);
2372 formatter
->dump_string("name", pool_name
);
2374 formatter
->dump_int("id", pool_id
);
2376 cerr
<< "ERROR: lookup_pg_pool_name for name=" << pool_name
2377 << " returned " << pool_id
<< std::endl
;
2378 formatter
->dump_int("size_bytes",s
.num_bytes
);
2379 formatter
->dump_int("size_kb", s
.num_kb
);
2380 formatter
->dump_int("num_objects", s
.num_objects
);
2381 formatter
->dump_int("num_object_clones", s
.num_object_clones
);
2382 formatter
->dump_int("num_object_copies", s
.num_object_copies
);
2383 formatter
->dump_int("num_objects_missing_on_primary", s
.num_objects_missing_on_primary
);
2384 formatter
->dump_int("num_objects_unfound", s
.num_objects_unfound
);
2385 formatter
->dump_int("num_objects_degraded", s
.num_objects_degraded
);
2386 formatter
->dump_int("read_ops", s
.num_rd
);
2387 formatter
->dump_int("read_bytes", s
.num_rd_kb
* 1024ull);
2388 formatter
->dump_int("write_ops", s
.num_wr
);
2389 formatter
->dump_int("write_bytes", s
.num_wr_kb
* 1024ull);
2390 formatter
->dump_int("compress_bytes_used", s
.compressed_bytes_alloc
);
2391 formatter
->dump_int("compress_under_bytes", s
.compressed_bytes_orig
);
2392 formatter
->close_section();
2401 cluster_stat_t tstats
;
2402 ret
= rados
.cluster_stat(tstats
);
2404 cerr
<< "error getting total cluster usage: " << cpp_strerror(ret
) << std::endl
;
2409 cout
<< "total_objects " << tstats
.num_objects
2411 cout
<< "total_used " << byte_u_t(tstats
.kb_used
<< 10)
2413 cout
<< "total_avail " << byte_u_t(tstats
.kb_avail
<< 10)
2415 cout
<< "total_space " << byte_u_t(tstats
.kb
<< 10)
2418 formatter
->close_section();
2419 formatter
->dump_int("total_objects", tstats
.num_objects
);
2420 formatter
->dump_int("total_used", tstats
.kb_used
);
2421 formatter
->dump_int("total_avail", tstats
.kb_avail
);
2422 formatter
->dump_int("total_space", tstats
.kb
);
2423 formatter
->close_section();
2424 formatter
->flush(cout
);
2428 else if (strcmp(nargs
[0], "ls") == 0) {
2429 if (!pool_name
&& !pgid
) {
2430 cerr
<< "either pool name or pg id needs to be specified" << std::endl
;
2435 io_ctx
.set_namespace(all_nspaces
);
2437 bool use_stdout
= (!output
&& (nargs
.size() < 2 || (strcmp(nargs
[1], "-") == 0)));
2438 if (!use_stdout
&& !output
) {
2439 cerr
<< "Please use --output to specify the output file name" << std::endl
;
2447 outstream
= new ofstream(output
);
2452 formatter
->open_array_section("objects");
2455 librados::NObjectIterator i
= pgid
? io_ctx
.nobjects_begin(pgid
->ps()) : io_ctx
.nobjects_begin();
2456 const librados::NObjectIterator i_end
= io_ctx
.nobjects_end();
2457 for (; i
!= i_end
; ++i
) {
2458 #ifdef WITH_LIBRADOSSTRIPER
2460 // in case of --striper option, we only list striped
2461 // objects, so we only display the first object of
2462 // each, without its suffix '.000...000'
2463 size_t l
= i
->get_oid().length();
2465 (0 != i
->get_oid().compare(l
-17, 17,".0000000000000000"))) {
2469 #endif // WITH_LIBRADOSSTRIPER
2472 if (io_ctx
.get_object_pg_hash_position2(i
->get_oid(), &ps
) || pgid
->ps() != ps
) {
2477 // Only include namespace in output when wildcard specified
2479 *outstream
<< i
->get_nspace() << "\t";
2481 *outstream
<< detail::get_oid(i
, use_striper
);
2482 if (i
->get_locator().size()) {
2483 *outstream
<< "\t" << i
->get_locator();
2485 *outstream
<< std::endl
;
2487 formatter
->open_object_section("object");
2488 formatter
->dump_string("namespace", i
->get_nspace());
2490 detail::dump_name(formatter
.get(), i
, use_striper
);
2492 if (i
->get_locator().size()) {
2493 formatter
->dump_string("locator", i
->get_locator());
2495 formatter
->close_section(); //object
2497 constexpr int TARGET_BYTES_PER_FLUSH
= 4096;
2498 if (formatter
->get_len() >= TARGET_BYTES_PER_FLUSH
) {
2499 formatter
->flush(*outstream
);
2504 catch (const std::exception
& e
) {
2505 cerr
<< e
.what() << std::endl
;
2510 formatter
->close_section(); //objects
2511 formatter
->flush(*outstream
);
2512 if (pretty_format
) {
2513 *outstream
<< std::endl
;
2515 formatter
->flush(*outstream
);
2521 else if (strcmp(nargs
[0], "mapext") == 0) {
2522 if (!pool_name
|| (nargs
.size() < 2 && !obj_name
)) {
2527 obj_name
= nargs
[1];
2529 std::map
<uint64_t,uint64_t> m
;
2530 ret
= io_ctx
.mapext(*obj_name
, 0, -1, m
);
2532 cerr
<< "mapext error on " << pool_name
<< "/" << prettify(*obj_name
) << ": " << cpp_strerror(ret
) << std::endl
;
2535 std::map
<uint64_t,uint64_t>::iterator iter
;
2536 for (iter
= m
.begin(); iter
!= m
.end(); ++iter
) {
2537 cout
<< hex
<< iter
->first
<< "\t" << iter
->second
<< dec
<< std::endl
;
2540 else if (strcmp(nargs
[0], "stat") == 0) {
2541 if (!pool_name
|| (nargs
.size() < 2 && !obj_name
)) {
2546 obj_name
= nargs
[1];
2551 ret
= detail::stat(io_ctx
, *obj_name
, size
, mtime
, use_striper
);
2554 cerr
<< " error stat-ing " << pool_name
<< "/" << prettify(*obj_name
) << ": "
2555 << cpp_strerror(ret
) << std::endl
;
2558 utime_t
t(mtime
, 0);
2559 cout
<< pool_name
<< "/" << prettify(*obj_name
)
2560 << " mtime " << t
<< ", size " << size
<< std::endl
;
2563 else if (strcmp(nargs
[0], "stat2") == 0) {
2564 if (!pool_name
|| (nargs
.size() < 2 && !obj_name
)) {
2569 obj_name
= nargs
[1];
2572 struct timespec mtime
;
2574 ret
= detail::stat2(io_ctx
, *obj_name
, size
, mtime
, use_striper
);
2577 cerr
<< " error stat-ing " << pool_name
<< "/" << prettify(*obj_name
) << ": "
2578 << cpp_strerror(ret
) << std::endl
;
2582 cout
<< pool_name
<< "/" << prettify(*obj_name
)
2583 << " mtime " << t
<< ", size " << size
<< std::endl
;
2586 else if (strcmp(nargs
[0], "touch") == 0) {
2587 if (!pool_name
|| (nargs
.size() < 2 && !obj_name
)) {
2591 time_t timestamp
= time(NULL
);
2592 if (nargs
.size() > (obj_name
? 1 : 2)) {
2593 char* endptr
= NULL
;
2594 timestamp
= static_cast<time_t>(strtoll(nargs
[obj_name
? 1 : 2], &endptr
, 10));
2596 cerr
<< "Invalid value for timestamp: '" << nargs
[obj_name
? 1 : 2] << "'" << std::endl
;
2602 obj_name
= nargs
[1];
2604 ObjectWriteOperation op
;
2606 op
.mtime(×tamp
);
2607 ret
= io_ctx
.operate(*obj_name
, &op
);
2609 cerr
<< " error touch-ing " << pool_name
<< "/" << prettify(*obj_name
) << ": "
2610 << cpp_strerror(ret
) << std::endl
;
2614 else if (strcmp(nargs
[0], "get") == 0) {
2615 if (!pool_name
|| nargs
.size() < (obj_name
? 2 : 3)) {
2619 const char* out_filename
;
2621 out_filename
= nargs
[1];
2623 obj_name
= nargs
[1];
2624 out_filename
= nargs
[2];
2626 ret
= do_get(io_ctx
, *obj_name
, out_filename
, op_size
, use_striper
);
2628 cerr
<< "error getting " << pool_name
<< "/" << prettify(*obj_name
) << ": " << cpp_strerror(ret
) << std::endl
;
2632 else if (strcmp(nargs
[0], "put") == 0) {
2633 if (!pool_name
|| nargs
.size() < (obj_name
? 2 : 3)) {
2637 const char* in_filename
;
2639 in_filename
= nargs
[1];
2641 obj_name
= nargs
[1];
2642 in_filename
= nargs
[2];
2644 bool create_object
= !obj_offset_specified
;
2645 ret
= do_put(io_ctx
, *obj_name
, in_filename
, op_size
, obj_offset
, create_object
, use_striper
);
2647 cerr
<< "error putting " << pool_name
<< "/" << prettify(*obj_name
) << ": " << cpp_strerror(ret
) << std::endl
;
2651 else if (strcmp(nargs
[0], "append") == 0) {
2652 if (!pool_name
|| nargs
.size() < (obj_name
? 2 : 3)) {
2656 const char* in_filename
;
2658 in_filename
= nargs
[1];
2660 obj_name
= nargs
[1];
2661 in_filename
= nargs
[2];
2663 ret
= do_append(io_ctx
, *obj_name
, in_filename
, op_size
, use_striper
);
2665 cerr
<< "error appending " << pool_name
<< "/" << prettify(*obj_name
) << ": " << cpp_strerror(ret
) << std::endl
;
2669 else if (strcmp(nargs
[0], "truncate") == 0) {
2670 if (!pool_name
|| nargs
.size() < (obj_name
? 2 : 3)) {
2675 char* endptr
= NULL
;
2678 obj_name
= nargs
[1];
2679 size
= strtoll(nargs
[2], &endptr
, 10);
2681 size
= strtoll(nargs
[1], &endptr
, 10);
2684 cerr
<< "Invalid value for size: '" << nargs
[2] << "'" << std::endl
;
2689 cerr
<< "error, cannot truncate to negative value" << std::endl
;
2694 ret
= detail::trunc(io_ctx
, *obj_name
, size
, use_striper
);
2697 cerr
<< "error truncating oid "
2698 << prettify(*obj_name
) << " to " << size
<< ": "
2699 << cpp_strerror(ret
) << std::endl
;
2704 else if (strcmp(nargs
[0], "setxattr") == 0) {
2705 if (!pool_name
|| nargs
.size() < (obj_name
? 2 : 3) ||
2706 nargs
.size() > (obj_name
? 3 : 4)) {
2710 string
attr_name(nargs
[obj_name
? 1 : 2]);
2712 if (nargs
.size() == (obj_name
? 3 : 4)) {
2713 string
attr_val(nargs
[obj_name
? 2 : 3]);
2714 bl
.append(attr_val
.c_str(), attr_val
.length());
2717 ret
= bl
.read_fd(STDIN_FILENO
, 1024); // from stdin
2723 obj_name
= nargs
[1];
2726 ret
= detail::setxattr(io_ctx
, *obj_name
, attr_name
, bl
, use_striper
);
2729 cerr
<< "error setting xattr " << pool_name
<< "/" << prettify(*obj_name
) << "/" << attr_name
<< ": " << cpp_strerror(ret
) << std::endl
;
2735 else if (strcmp(nargs
[0], "getxattr") == 0) {
2736 if (!pool_name
|| nargs
.size() < (obj_name
? 2 : 3)) {
2740 string
attr_name(nargs
[obj_name
? 1 : 2]);
2742 obj_name
= nargs
[1];
2745 ret
= detail::getxattr(io_ctx
, *obj_name
, attr_name
, bl
, use_striper
);
2748 cerr
<< "error getting xattr " << pool_name
<< "/" << prettify(*obj_name
) << "/" << attr_name
<< ": " << cpp_strerror(ret
) << std::endl
;
2753 string
s(bl
.c_str(), bl
.length());
2755 } else if (strcmp(nargs
[0], "rmxattr") == 0) {
2756 if (!pool_name
|| nargs
.size() < (obj_name
? 2 : 3)) {
2761 string
attr_name(nargs
[obj_name
? 1 : 2]);
2763 obj_name
= nargs
[1];
2765 ret
= detail::rmxattr(io_ctx
, *obj_name
, attr_name
, use_striper
);
2768 cerr
<< "error removing xattr " << pool_name
<< "/" << prettify(*obj_name
) << "/" << attr_name
<< ": " << cpp_strerror(ret
) << std::endl
;
2771 } else if (strcmp(nargs
[0], "listxattr") == 0) {
2772 if (!pool_name
|| (nargs
.size() < 2 && !obj_name
)) {
2777 obj_name
= nargs
[1];
2780 map
<std::string
, bufferlist
> attrset
;
2782 ret
= detail::getxattrs(io_ctx
, *obj_name
, attrset
, use_striper
);
2785 cerr
<< "error getting xattr set " << pool_name
<< "/" << prettify(*obj_name
) << ": " << cpp_strerror(ret
) << std::endl
;
2789 for (map
<std::string
, bufferlist
>::iterator iter
= attrset
.begin();
2790 iter
!= attrset
.end(); ++iter
) {
2791 cout
<< iter
->first
<< std::endl
;
2793 } else if (strcmp(nargs
[0], "getomapheader") == 0) {
2794 if (!pool_name
|| (nargs
.size() < 2 && !obj_name
)) {
2799 if (nargs
.size() >= (obj_name
? 2 : 3)) {
2800 outfile
= nargs
[obj_name
? 1 : 2];
2803 obj_name
= nargs
[1];
2806 ret
= io_ctx
.omap_get_header(*obj_name
, &header
);
2808 cerr
<< "error getting omap header " << pool_name
<< "/" << prettify(*obj_name
)
2809 << ": " << cpp_strerror(ret
) << std::endl
;
2812 if (!outfile
.empty()) {
2813 cerr
<< "Writing to " << outfile
<< std::endl
;
2814 dump_data(outfile
, header
);
2816 cout
<< "header (" << header
.length() << " bytes) :\n";
2817 header
.hexdump(cout
);
2822 } else if (strcmp(nargs
[0], "setomapheader") == 0) {
2823 if (!pool_name
|| nargs
.size() < (obj_name
? 2 : 3)) {
2830 obj_name
= nargs
[1];
2831 bl
.append(nargs
[2]); // val
2833 bl
.append(nargs
[1]); // val
2835 ret
= io_ctx
.omap_set_header(*obj_name
, bl
);
2837 cerr
<< "error setting omap value " << pool_name
<< "/" << prettify(*obj_name
)
2838 << ": " << cpp_strerror(ret
) << std::endl
;
2843 } else if (strcmp(nargs
[0], "setomapval") == 0) {
2844 uint32_t min_args
= (omap_key
? 2 : 3);
2845 if (!pool_name
|| nargs
.size() < min_args
|| nargs
.size() > min_args
+ 1) {
2850 string
oid(nargs
[1]);
2852 omap_key
= nargs
[2];
2856 if (!input_file
.empty()) {
2858 ret
= bl
.read_file(input_file
.c_str(), &err
);
2860 cerr
<< "error reading file " << input_file
.c_str() << ": " << err
<< std::endl
;
2863 } else if (nargs
.size() > min_args
) {
2864 string
val(nargs
[min_args
]);
2868 ret
= bl
.read_fd(STDIN_FILENO
, 1024); // from stdin
2875 map
<string
, bufferlist
> values
;
2876 values
[*omap_key
] = bl
;
2878 ret
= io_ctx
.omap_set(oid
, values
);
2880 cerr
<< "error setting omap value " << pool_name
<< "/" << oid
<< "/"
2881 << prettify(*omap_key
) << ": " << cpp_strerror(ret
) << std::endl
;
2886 } else if (strcmp(nargs
[0], "getomapval") == 0) {
2887 uint32_t min_args
= (omap_key
? (obj_name
? 1 : 2)
2888 : (obj_name
? 2 : 3));
2889 if (!pool_name
|| nargs
.size() < min_args
|| nargs
.size() > min_args
+ 1) {
2895 omap_key
= nargs
[obj_name
? 1 : 2];
2899 keys
.insert(*omap_key
);
2901 std::string outfile
;
2902 if (nargs
.size() > min_args
) {
2903 outfile
= nargs
[min_args
];
2906 obj_name
= nargs
[1];
2909 map
<string
, bufferlist
> values
;
2910 ret
= io_ctx
.omap_get_vals_by_keys(*obj_name
, keys
, &values
);
2912 cerr
<< "error getting omap value " << pool_name
<< "/" << prettify(*obj_name
) << "/"
2913 << prettify(*omap_key
) << ": " << cpp_strerror(ret
) << std::endl
;
2919 if (values
.size() && values
.begin()->first
== *omap_key
) {
2920 if (!outfile
.empty()) {
2921 cerr
<< "Writing to " << outfile
<< std::endl
;
2922 dump_data(outfile
, values
.begin()->second
);
2924 cout
<< "value (" << values
.begin()->second
.length() << " bytes) :\n";
2925 values
.begin()->second
.hexdump(cout
);
2930 cout
<< "No such key: " << pool_name
<< "/" << prettify(*obj_name
) << "/"
2931 << prettify(*omap_key
) << std::endl
;
2934 } else if (strcmp(nargs
[0], "rmomapkey") == 0) {
2935 uint32_t num_args
= (omap_key
? (obj_name
? 1 : 2)
2936 : (obj_name
? 2 : 3));
2937 if (!pool_name
|| nargs
.size() != num_args
) {
2943 omap_key
= nargs
[obj_name
? 1 : 2];
2946 obj_name
= nargs
[1];
2949 keys
.insert(*omap_key
);
2951 ret
= io_ctx
.omap_rm_keys(*obj_name
, keys
);
2953 cerr
<< "error removing omap key " << pool_name
<< "/" << prettify(*obj_name
) << "/"
2954 << prettify(*omap_key
) << ": " << cpp_strerror(ret
) << std::endl
;
2959 } else if (strcmp(nargs
[0], "clearomap") == 0) {
2960 if (!pool_name
|| (nargs
.size() < 2 && !obj_name
)) {
2964 // strip nargs[0] which is "clearomap"
2965 std::vector
<std::string
> oids(std::next(std::begin(nargs
)),
2968 oids
.push_back(*obj_name
);
2971 for (const auto& oid
: oids
) {
2972 ret
= io_ctx
.omap_clear(oid
);
2974 cerr
<< "error clearing omap keys " << pool_name
<< "/" << prettify(*obj_name
) << "/"
2975 << cpp_strerror(ret
) << std::endl
;
2980 } else if (strcmp(nargs
[0], "listomapvals") == 0) {
2981 if (!pool_name
|| (nargs
.size() < 2 && !obj_name
)) {
2986 obj_name
= nargs
[1];
2988 string last_read
= "";
2990 map
<string
, bufferlist
> values
;
2991 ret
= io_ctx
.omap_get_vals(*obj_name
, last_read
, MAX_OMAP_BYTES_PER_REQUEST
, &values
);
2993 cerr
<< "error getting omap keys " << pool_name
<< "/" << prettify(*obj_name
) << ": "
2994 << cpp_strerror(ret
) << std::endl
;
2997 ret
= values
.size();
2998 for (map
<string
, bufferlist
>::const_iterator it
= values
.begin();
2999 it
!= values
.end(); ++it
) {
3000 last_read
= it
->first
;
3001 // dump key in hex if it contains nonprintable characters
3002 if (std::count_if(it
->first
.begin(), it
->first
.end(),
3003 (int (*)(int))isprint
) < (int)it
->first
.length()) {
3004 cout
<< "key (" << it
->first
.length() << " bytes):\n";
3006 keybl
.append(it
->first
);
3007 keybl
.hexdump(cout
);
3012 cout
<< "value (" << it
->second
.length() << " bytes) :\n";
3013 it
->second
.hexdump(cout
);
3016 } while (ret
== MAX_OMAP_BYTES_PER_REQUEST
);
3019 else if (strcmp(nargs
[0], "cp") == 0) {
3020 // XXX: binary names aren't supported for this operation
3026 if (nargs
.size() < 2 || nargs
.size() > 3) {
3031 const char *target
= target_pool_name
;
3035 const char *target_obj
;
3036 if (nargs
.size() < 3) {
3037 if (strcmp(target
, pool_name
) == 0) {
3038 cerr
<< "cannot copy object into itself" << std::endl
;
3041 target_obj
= nargs
[1];
3043 target_obj
= nargs
[2];
3048 ret
= rados
.ioctx_create(target
, target_ctx
);
3050 cerr
<< "error opening target pool " << target
<< ": "
3051 << cpp_strerror(ret
) << std::endl
;
3054 if (target_oloc
.size()) {
3055 target_ctx
.locator_set_key(target_oloc
);
3057 if (target_nspace
.size()) {
3058 target_ctx
.set_namespace(target_nspace
);
3061 ret
= do_copy(io_ctx
, nargs
[1], target_ctx
, target_obj
);
3063 cerr
<< "error copying " << pool_name
<< "/" << nargs
[1] << " => " << target
<< "/" << target_obj
<< ": " << cpp_strerror(ret
) << std::endl
;
3066 } else if (strcmp(nargs
[0], "rm") == 0) {
3067 if (!pool_name
|| (nargs
.size() < 2 && !obj_name
)) {
3071 // strip nargs[0] which is "rm"
3072 std::vector
<std::string
> oids(std::next(std::begin(nargs
)),
3075 oids
.push_back(*obj_name
);
3077 for (const auto& oid
: oids
) {
3079 ret
= detail::remove(io_ctx
, oid
, (CEPH_OSD_FLAG_FULL_FORCE
|
3080 CEPH_OSD_FLAG_FULL_TRY
), use_striper
);
3082 ret
= detail::remove(io_ctx
, oid
, use_striper
);
3086 string name
= (nspace
.size() ? nspace
+ "/" : "" ) + prettify(oid
);
3087 cerr
<< "error removing " << pool_name
<< ">" << name
<< ": " << cpp_strerror(ret
) << std::endl
;
3092 else if (strcmp(nargs
[0], "create") == 0) {
3093 if (!pool_name
|| (nargs
.size() < 2 && !obj_name
)) {
3098 obj_name
= nargs
[1];
3100 ret
= io_ctx
.create(*obj_name
, true);
3102 cerr
<< "error creating " << pool_name
<< "/" << prettify(*obj_name
) << ": " << cpp_strerror(ret
) << std::endl
;
3106 else if (strcmp(nargs
[0], "cppool") == 0) {
3107 bool force
= nargs
.size() == 4 && !strcmp(nargs
[3], "--yes-i-really-mean-it");
3108 if (nargs
.size() != 3 && !(nargs
.size() == 4 && force
)) {
3112 const char *src_pool
= nargs
[1];
3113 const char *target_pool
= nargs
[2];
3115 if (strcmp(src_pool
, target_pool
) == 0) {
3116 cerr
<< "cannot copy pool into itself" << std::endl
;
3120 cerr
<< "WARNING: pool copy does not preserve user_version, which some "
3121 << "apps may rely on." << std::endl
;
3123 if (rados
.get_pool_is_selfmanaged_snaps_mode(src_pool
)) {
3124 cerr
<< "WARNING: pool " << src_pool
<< " has selfmanaged snaps, which are not preserved\n"
3125 << " by the cppool operation. This will break any snapshot user."
3128 cerr
<< " If you insist on making a broken copy, you can pass\n"
3129 << " --yes-i-really-mean-it to proceed anyway."
3135 ret
= do_copy_pool(rados
, src_pool
, target_pool
);
3137 cerr
<< "error copying pool " << src_pool
<< " => " << target_pool
<< ": "
3138 << cpp_strerror(ret
) << std::endl
;
3141 cout
<< "successfully copied pool " << nargs
[1] << std::endl
;
3143 else if (strcmp(nargs
[0], "purge") == 0) {
3144 if (nargs
.size() < 2) {
3148 if (nargs
.size() < 3 ||
3149 strcmp(nargs
[2], "--yes-i-really-really-mean-it") != 0) {
3150 cerr
<< "WARNING:\n"
3151 << " This will PERMANENTLY DESTROY all objects from a pool with no way back.\n"
3152 << " To confirm, follow pool with --yes-i-really-really-mean-it" << std::endl
;
3155 ret
= rados
.ioctx_create(nargs
[1], io_ctx
);
3157 cerr
<< "error pool " << nargs
[1] << ": "
3158 << cpp_strerror(ret
) << std::endl
;
3161 io_ctx
.set_namespace(all_nspaces
);
3162 io_ctx
.set_pool_full_try();
3163 RadosBencher
bencher(g_ceph_context
, rados
, io_ctx
);
3164 ret
= bencher
.clean_up_slow("", concurrent_ios
);
3166 cout
<< "successfully purged pool " << nargs
[1] << std::endl
;
3168 cerr
<< "pool " << nargs
[1] << " could not be purged" << std::endl
;
3169 cerr
<< "Check your monitor configuration - `mon allow pool delete` is set to false by default,"
3170 << " change it to true to allow deletion of pools" << std::endl
;
3173 else if (strcmp(nargs
[0], "lssnap") == 0) {
3174 if (!pool_name
|| nargs
.size() != 1) {
3179 vector
<snap_t
> snaps
;
3180 io_ctx
.snap_list(&snaps
);
3181 for (vector
<snap_t
>::iterator i
= snaps
.begin();
3186 if (io_ctx
.snap_get_name(*i
, &s
) < 0)
3188 if (io_ctx
.snap_get_stamp(*i
, &t
) < 0)
3191 localtime_r(&t
, &bdt
);
3192 cout
<< *i
<< "\t" << s
<< "\t";
3194 std::ios_base::fmtflags original_flags
= cout
.flags();
3195 cout
.setf(std::ios::right
);
3197 cout
<< std::setw(4) << (bdt
.tm_year
+1900)
3198 << '.' << std::setw(2) << (bdt
.tm_mon
+1)
3199 << '.' << std::setw(2) << bdt
.tm_mday
3201 << std::setw(2) << bdt
.tm_hour
3202 << ':' << std::setw(2) << bdt
.tm_min
3203 << ':' << std::setw(2) << bdt
.tm_sec
3205 cout
.flags(original_flags
);
3207 cout
<< snaps
.size() << " snaps" << std::endl
;
3210 else if (strcmp(nargs
[0], "mksnap") == 0) {
3211 if (!pool_name
|| nargs
.size() < 2) {
3216 if (rados
.get_pool_is_selfmanaged_snaps_mode(pool_name
)) {
3217 cerr
<< "can't create snapshot: pool " << pool_name
3218 << " is in selfmanaged snaps mode" << std::endl
;
3222 ret
= io_ctx
.snap_create(nargs
[1]);
3224 cerr
<< "error creating pool " << pool_name
<< " snapshot " << nargs
[1]
3225 << ": " << cpp_strerror(ret
) << std::endl
;
3228 cout
<< "created pool " << pool_name
<< " snap " << nargs
[1] << std::endl
;
3231 else if (strcmp(nargs
[0], "rmsnap") == 0) {
3232 if (!pool_name
|| nargs
.size() < 2) {
3237 ret
= io_ctx
.snap_remove(nargs
[1]);
3239 cerr
<< "error removing pool " << pool_name
<< " snapshot " << nargs
[1]
3240 << ": " << cpp_strerror(ret
) << std::endl
;
3243 cout
<< "removed pool " << pool_name
<< " snap " << nargs
[1] << std::endl
;
3246 else if (strcmp(nargs
[0], "rollback") == 0) {
3247 if (!pool_name
|| nargs
.size() < 3) {
3252 ret
= io_ctx
.snap_rollback(nargs
[1], nargs
[2]);
3254 cerr
<< "error rolling back pool " << pool_name
<< " to snapshot " << nargs
[1]
3255 << cpp_strerror(ret
) << std::endl
;
3258 cout
<< "rolled back pool " << pool_name
3259 << " to snapshot " << nargs
[2] << std::endl
;
3261 else if (strcmp(nargs
[0], "bench") == 0) {
3262 if (!pool_name
|| nargs
.size() < 3) {
3266 char* endptr
= NULL
;
3267 int seconds
= strtol(nargs
[1], &endptr
, 10);
3269 cerr
<< "Invalid value for seconds: '" << nargs
[1] << "'" << std::endl
;
3273 if (strcmp(nargs
[2], "write") == 0)
3274 operation
= OP_WRITE
;
3275 else if (strcmp(nargs
[2], "seq") == 0)
3276 operation
= OP_SEQ_READ
;
3277 else if (strcmp(nargs
[2], "rand") == 0)
3278 operation
= OP_RAND_READ
;
3283 if (operation
!= OP_WRITE
) {
3284 if (block_size_specified
) {
3285 cerr
<< "-b|--block_size option can be used only with 'write' bench test"
3289 if (bench_write_dest
!= 0) {
3290 cerr
<< "--write-object, --write-omap and --write-xattr options can "
3291 "only be used with the 'write' bench test"
3296 else if (bench_write_dest
== 0) {
3297 bench_write_dest
= OP_WRITE_DEST_OBJ
;
3300 if (!formatter
&& output
) {
3301 cerr
<< "-o|--output option can only be used with '--format' option"
3305 RadosBencher
bencher(g_ceph_context
, rados
, io_ctx
);
3306 bencher
.set_show_time(show_time
);
3307 bencher
.set_write_destination(static_cast<OpWriteDest
>(bench_write_dest
));
3309 ostream
*outstream
= NULL
;
3311 bencher
.set_formatter(formatter
.get());
3313 outstream
= new ofstream(output
);
3316 bencher
.set_outstream(*outstream
);
3319 object_size
= op_size
;
3320 else if (object_size
< op_size
)
3321 op_size
= object_size
;
3322 cout
<< "hints = " << (int)hints
<< std::endl
;
3323 ret
= bencher
.aio_bench(operation
, seconds
,
3324 concurrent_ios
, op_size
, object_size
,
3325 max_objects
, cleanup
, hints
, run_name
, reuse_bench
, no_verify
);
3327 cerr
<< "error during benchmark: " << cpp_strerror(ret
) << std::endl
;
3328 if (formatter
&& output
)
3331 else if (strcmp(nargs
[0], "cleanup") == 0) {
3337 io_ctx
.set_namespace(all_nspaces
);
3338 RadosBencher
bencher(g_ceph_context
, rados
, io_ctx
);
3339 ret
= bencher
.clean_up(prefix
, concurrent_ios
, run_name
);
3341 cerr
<< "error during cleanup: " << cpp_strerror(ret
) << std::endl
;
3343 else if (strcmp(nargs
[0], "watch") == 0) {
3344 if (!pool_name
|| nargs
.size() < 2) {
3348 string
oid(nargs
[1]);
3349 RadosWatchCtx
ctx(io_ctx
, oid
.c_str());
3351 ret
= io_ctx
.watch2(oid
, &cookie
, &ctx
);
3353 cerr
<< "error calling watch: " << cpp_strerror(ret
) << std::endl
;
3355 cout
<< "press enter to exit..." << std::endl
;
3357 io_ctx
.unwatch2(cookie
);
3358 rados
.watch_flush();
3361 else if (strcmp(nargs
[0], "notify") == 0) {
3362 if (!pool_name
|| nargs
.size() < 3) {
3366 string
oid(nargs
[1]);
3367 string
msg(nargs
[2]);
3368 bufferlist bl
, replybl
;
3370 ret
= io_ctx
.notify2(oid
, bl
, 10000, &replybl
);
3372 cerr
<< "error calling notify: " << cpp_strerror(ret
) << std::endl
;
3373 if (replybl
.length()) {
3374 map
<pair
<uint64_t,uint64_t>,bufferlist
> rm
;
3375 set
<pair
<uint64_t,uint64_t> > missed
;
3376 auto p
= replybl
.cbegin();
3379 for (map
<pair
<uint64_t,uint64_t>,bufferlist
>::iterator p
= rm
.begin();
3382 cout
<< "reply client." << p
->first
.first
3383 << " cookie " << p
->first
.second
3384 << " : " << p
->second
.length() << " bytes" << std::endl
;
3385 if (p
->second
.length())
3386 p
->second
.hexdump(cout
);
3388 for (multiset
<pair
<uint64_t,uint64_t> >::iterator p
= missed
.begin();
3389 p
!= missed
.end(); ++p
) {
3390 cout
<< "timeout client." << p
->first
3391 << " cookie " << p
->second
<< std::endl
;
3394 } else if (strcmp(nargs
[0], "set-alloc-hint") == 0) {
3395 // cmd, [oid, ] obj_size, write_size
3396 if (!pool_name
|| nargs
.size() < (obj_name
? 3 : 4)) {
3401 uint64_t expected_object_size
= strict_strtoll(nargs
[obj_name
? 1 : 2], 10, &err
);
3403 cerr
<< "couldn't parse expected_object_size: " << err
<< std::endl
;
3407 uint64_t expected_write_size
= strict_strtoll(nargs
[obj_name
? 2 : 3], 10, &err
);
3409 cerr
<< "couldn't parse expected_write_size: " << err
<< std::endl
;
3414 obj_name
= nargs
[1];
3416 ret
= io_ctx
.set_alloc_hint(*obj_name
, expected_object_size
, expected_write_size
);
3418 cerr
<< "error setting alloc-hint " << pool_name
<< "/" << prettify(*obj_name
) << ": "
3419 << cpp_strerror(ret
) << std::endl
;
3422 } else if (strcmp(nargs
[0], "load-gen") == 0) {
3424 cerr
<< "error: must specify pool" << std::endl
;
3430 lg
.min_obj_len
= min_obj_len
;
3432 lg
.max_obj_len
= max_obj_len
;
3434 lg
.min_op_len
= min_op_len
;
3436 lg
.max_op_len
= max_op_len
;
3438 lg
.max_ops
= max_ops
;
3440 lg
.max_backlog
= max_backlog
;
3441 if (target_throughput
)
3442 lg
.target_throughput
= target_throughput
;
3443 if (read_percent
>= 0)
3444 lg
.read_percent
= read_percent
;
3446 lg
.num_objs
= num_objs
;
3448 lg
.run_length
= run_length
;
3450 lg
.offset_align
= offset_align
;
3452 cout
<< "run length " << run_length
<< " seconds" << std::endl
;
3453 cout
<< "preparing " << lg
.num_objs
<< " objects" << std::endl
;
3454 ret
= lg
.bootstrap(pool_name
);
3456 cerr
<< "load-gen bootstrap failed" << std::endl
;
3459 cout
<< "load-gen will run " << lg
.run_length
<< " seconds" << std::endl
;
3462 } else if (strcmp(nargs
[0], "listomapkeys") == 0) {
3463 if (!pool_name
|| (nargs
.size() < 2 && !obj_name
)) {
3468 obj_name
= nargs
[1];
3473 set
<string
> out_keys
;
3474 ret
= io_ctx
.omap_get_keys2(*obj_name
, last_read
, MAX_OMAP_BYTES_PER_REQUEST
, &out_keys
, &more
);
3476 cerr
<< "error getting omap key set " << pool_name
<< "/"
3477 << prettify(*obj_name
) << ": " << cpp_strerror(ret
) << std::endl
;
3481 for (auto &key
: out_keys
) {
3482 cout
<< key
<< std::endl
;
3483 last_read
= std::move(key
);
3486 } else if (strcmp(nargs
[0], "lock") == 0) {
3493 formatter
= std::make_unique
<JSONFormatter
>(pretty_format
);
3495 ret
= do_lock_cmd(nargs
, opts
, &io_ctx
, formatter
.get());
3496 } else if (strcmp(nargs
[0], "listwatchers") == 0) {
3497 if (!pool_name
|| nargs
.size() < 2) {
3502 string
oid(nargs
[1]);
3503 std::list
<obj_watch_t
> lw
;
3505 ret
= io_ctx
.list_watchers(oid
, &lw
);
3507 cerr
<< "error listing watchers " << pool_name
<< "/" << oid
<< ": " << cpp_strerror(ret
) << std::endl
;
3513 for (std::list
<obj_watch_t
>::iterator i
= lw
.begin(); i
!= lw
.end(); ++i
) {
3514 cout
<< "watcher=" << i
->addr
<< " client." << i
->watcher_id
<< " cookie=" << i
->cookie
<< std::endl
;
3516 } else if (strcmp(nargs
[0], "listsnaps") == 0) {
3517 if (!pool_name
|| (nargs
.size() < 2 && !obj_name
)) {
3522 obj_name
= nargs
[1];
3526 io_ctx
.snap_set_read(LIBRADOS_SNAP_DIR
);
3527 ret
= io_ctx
.list_snaps(*obj_name
, &ls
);
3529 cerr
<< "error listing snap shots " << pool_name
<< "/" << prettify(*obj_name
) << ": " << cpp_strerror(ret
) << std::endl
;
3535 map
<snap_t
,string
> snamemap
;
3536 if (formatter
|| pretty_format
) {
3537 vector
<snap_t
> snaps
;
3538 io_ctx
.snap_list(&snaps
);
3539 for (vector
<snap_t
>::iterator i
= snaps
.begin();
3540 i
!= snaps
.end(); ++i
) {
3542 if (io_ctx
.snap_get_name(*i
, &s
) < 0)
3544 snamemap
.insert(pair
<snap_t
,string
>(*i
, s
));
3549 formatter
->open_object_section("object");
3550 formatter
->dump_string("name", *obj_name
);
3551 formatter
->open_array_section("clones");
3553 cout
<< prettify(*obj_name
) << ":" << std::endl
;
3554 cout
<< "cloneid snaps size overlap" << std::endl
;
3557 for (std::vector
<clone_info_t
>::iterator ci
= ls
.clones
.begin();
3558 ci
!= ls
.clones
.end(); ++ci
) {
3560 if (formatter
) formatter
->open_object_section("clone");
3562 if (ci
->cloneid
== librados::SNAP_HEAD
) {
3564 formatter
->dump_string("id", "head");
3569 formatter
->dump_unsigned("id", ci
->cloneid
);
3571 cout
<< ci
->cloneid
;
3575 formatter
->open_array_section("snapshots");
3579 if (!formatter
&& ci
->snaps
.empty()) {
3582 for (std::vector
<snap_t
>::const_iterator snapindex
= ci
->snaps
.begin();
3583 snapindex
!= ci
->snaps
.end(); ++snapindex
) {
3585 map
<snap_t
,string
>::iterator si
;
3587 if (formatter
|| pretty_format
) si
= snamemap
.find(*snapindex
);
3590 formatter
->open_object_section("snapshot");
3591 formatter
->dump_unsigned("id", *snapindex
);
3592 if (si
!= snamemap
.end())
3593 formatter
->dump_string("name", si
->second
);
3594 formatter
->close_section(); //snapshot
3596 if (snapindex
!= ci
->snaps
.begin()) cout
<< ",";
3597 if (!pretty_format
|| (si
== snamemap
.end()))
3600 cout
<< si
->second
<< "(" << *snapindex
<< ")";
3605 formatter
->close_section(); //Snapshots
3606 formatter
->dump_unsigned("size", ci
->size
);
3608 cout
<< "\t" << ci
->size
;
3611 if (ci
->cloneid
!= librados::SNAP_HEAD
) {
3613 formatter
->open_array_section("overlaps");
3617 for (std::vector
< std::pair
<uint64_t,uint64_t> >::iterator ovi
= ci
->overlap
.begin();
3618 ovi
!= ci
->overlap
.end(); ++ovi
) {
3620 formatter
->open_object_section("section");
3621 formatter
->dump_unsigned("start", ovi
->first
);
3622 formatter
->dump_unsigned("length", ovi
->second
);
3623 formatter
->close_section(); //section
3625 if (ovi
!= ci
->overlap
.begin()) cout
<< ",";
3626 cout
<< ovi
->first
<< "~" << ovi
->second
;
3630 formatter
->close_section(); //overlaps
3632 cout
<< "]" << std::endl
;
3634 if (formatter
) formatter
->close_section(); //clone
3637 formatter
->close_section(); //clones
3638 formatter
->close_section(); //object
3639 formatter
->flush(cout
);
3643 } else if (strcmp(nargs
[0], "list-inconsistent-pg") == 0) {
3645 formatter
= std::make_unique
<JSONFormatter
>(pretty_format
);
3647 ret
= do_get_inconsistent_pg_cmd(nargs
, rados
, *formatter
);
3648 } else if (strcmp(nargs
[0], "list-inconsistent-obj") == 0) {
3650 formatter
= std::make_unique
<JSONFormatter
>(pretty_format
);
3652 ret
= do_get_inconsistent_cmd
<inconsistent_obj_t
>(nargs
, rados
, *formatter
);
3653 } else if (strcmp(nargs
[0], "list-inconsistent-snapset") == 0) {
3655 formatter
= std::make_unique
<JSONFormatter
>(pretty_format
);
3657 ret
= do_get_inconsistent_cmd
<inconsistent_snapset_t
>(nargs
, rados
, *formatter
);
3658 } else if (strcmp(nargs
[0], "cache-flush") == 0) {
3659 if (!pool_name
|| (nargs
.size() < 2 && !obj_name
)) {
3664 obj_name
= nargs
[1];
3668 io_ctx
.snap_set_read(LIBRADOS_SNAP_DIR
);
3669 ret
= io_ctx
.list_snaps(*obj_name
, &ls
);
3671 cerr
<< "error listing snapshots " << pool_name
<< "/" << prettify(*obj_name
) << ": "
3672 << cpp_strerror(ret
) << std::endl
;
3675 for (std::vector
<clone_info_t
>::iterator ci
= ls
.clones
.begin();
3676 ci
!= ls
.clones
.end(); ++ci
) {
3677 if (snapid
!= CEPH_NOSNAP
&& ci
->cloneid
> snapid
)
3679 io_ctx
.snap_set_read(ci
->cloneid
);
3680 ret
= do_cache_flush(io_ctx
, *obj_name
);
3682 cerr
<< "error from cache-flush " << prettify(*obj_name
) << ": "
3683 << cpp_strerror(ret
) << std::endl
;
3688 ret
= do_cache_flush(io_ctx
, *obj_name
);
3690 cerr
<< "error from cache-flush " << prettify(*obj_name
) << ": "
3691 << cpp_strerror(ret
) << std::endl
;
3695 } else if (strcmp(nargs
[0], "cache-try-flush") == 0) {
3696 if (!pool_name
|| (nargs
.size() < 2 && !obj_name
)) {
3701 obj_name
= nargs
[1];
3705 io_ctx
.snap_set_read(LIBRADOS_SNAP_DIR
);
3706 ret
= io_ctx
.list_snaps(*obj_name
, &ls
);
3708 cerr
<< "error listing snapshots " << pool_name
<< "/" << prettify(*obj_name
) << ": "
3709 << cpp_strerror(ret
) << std::endl
;
3712 for (std::vector
<clone_info_t
>::iterator ci
= ls
.clones
.begin();
3713 ci
!= ls
.clones
.end(); ++ci
) {
3714 if (snapid
!= CEPH_NOSNAP
&& ci
->cloneid
> snapid
)
3716 io_ctx
.snap_set_read(ci
->cloneid
);
3717 ret
= do_cache_try_flush(io_ctx
, *obj_name
);
3719 cerr
<< "error from cache-flush " << prettify(*obj_name
) << ": "
3720 << cpp_strerror(ret
) << std::endl
;
3725 ret
= do_cache_try_flush(io_ctx
, *obj_name
);
3727 cerr
<< "error from cache-flush " << prettify(*obj_name
) << ": "
3728 << cpp_strerror(ret
) << std::endl
;
3732 } else if (strcmp(nargs
[0], "cache-evict") == 0) {
3733 if (!pool_name
|| (nargs
.size() < 2 && !obj_name
)) {
3738 obj_name
= nargs
[1];
3742 io_ctx
.snap_set_read(LIBRADOS_SNAP_DIR
);
3743 ret
= io_ctx
.list_snaps(*obj_name
, &ls
);
3745 cerr
<< "error listing snapshots " << pool_name
<< "/" << prettify(*obj_name
) << ": "
3746 << cpp_strerror(ret
) << std::endl
;
3749 for (std::vector
<clone_info_t
>::iterator ci
= ls
.clones
.begin();
3750 ci
!= ls
.clones
.end(); ++ci
) {
3751 if (snapid
!= CEPH_NOSNAP
&& ci
->cloneid
> snapid
)
3753 io_ctx
.snap_set_read(ci
->cloneid
);
3754 ret
= do_cache_evict(io_ctx
, *obj_name
);
3756 cerr
<< "error from cache-flush " << prettify(*obj_name
) << ": "
3757 << cpp_strerror(ret
) << std::endl
;
3762 ret
= do_cache_evict(io_ctx
, *obj_name
);
3764 cerr
<< "error from cache-flush " << prettify(*obj_name
) << ": "
3765 << cpp_strerror(ret
) << std::endl
;
3769 } else if (strcmp(nargs
[0], "cache-flush-evict-all") == 0) {
3774 ret
= do_cache_flush_evict_all(io_ctx
, true);
3776 cerr
<< "cache-flush-evict-all finished with errors" << std::endl
;
3779 } else if (strcmp(nargs
[0], "cache-try-flush-evict-all") == 0) {
3784 ret
= do_cache_flush_evict_all(io_ctx
, false);
3786 cerr
<< "cache-try-flush-evict-all finished with errors" << std::endl
;
3789 } else if (strcmp(nargs
[0], "set-redirect") == 0) {
3795 const char *target
= target_pool_name
;
3799 const char *target_obj
;
3800 if (nargs
.size() < 3) {
3801 if (strcmp(target
, pool_name
) == 0) {
3802 cerr
<< "cannot copy object into itself" << std::endl
;
3805 target_obj
= nargs
[1];
3807 target_obj
= nargs
[2];
3811 ret
= rados
.ioctx_create(target
, target_ctx
);
3812 if (target_oloc
.size()) {
3813 target_ctx
.locator_set_key(target_oloc
);
3815 if (target_nspace
.size()) {
3816 target_ctx
.set_namespace(target_nspace
);
3819 ObjectWriteOperation op
;
3820 if (with_reference
) {
3821 op
.set_redirect(target_obj
, target_ctx
, 0, CEPH_OSD_OP_FLAG_WITH_REFERENCE
);
3823 op
.set_redirect(target_obj
, target_ctx
, 0);
3825 ret
= io_ctx
.operate(nargs
[1], &op
);
3827 cerr
<< "error set-redirect " << pool_name
<< "/" << nargs
[1] << " => " << target
<< "/" << target_obj
<< ": " << cpp_strerror(ret
) << std::endl
;
3830 } else if (strcmp(nargs
[0], "set-chunk") == 0) {
3836 const char *target
= target_pool_name
;
3842 uint64_t tgt_offset
;
3844 if (nargs
.size() < 6) {
3848 char* endptr
= NULL
;
3849 offset
= strtoull(nargs
[2], &endptr
, 10);
3851 cerr
<< "Invalid value for size: '" << nargs
[2] << "'" << std::endl
;
3854 length
= strtoull(nargs
[3], &endptr
, 10);
3856 cerr
<< "Invalid value for size: '" << nargs
[2] << "'" << std::endl
;
3859 tgt_oid
= string(nargs
[4]);
3860 tgt_offset
= strtoull(nargs
[5], &endptr
, 10);
3862 cerr
<< "Invalid value for size: '" << nargs
[2] << "'" << std::endl
;
3868 ret
= rados
.ioctx_create(target
, target_ctx
);
3869 ObjectReadOperation op
;
3870 op
.set_chunk(offset
, length
, target_ctx
, tgt_oid
, tgt_offset
, CEPH_OSD_OP_FLAG_WITH_REFERENCE
);
3871 ret
= io_ctx
.operate(nargs
[1], &op
, NULL
);
3873 cerr
<< "error set-chunk " << pool_name
<< "/" << nargs
[1] << " " << " offset " << offset
3874 << " length " << length
<< " target_pool " << target
3875 << "tgt_offset: " << tgt_offset
<< " : " << cpp_strerror(ret
) << std::endl
;
3878 } else if (strcmp(nargs
[0], "tier-promote") == 0) {
3879 if (!pool_name
|| (nargs
.size() < 2 && !obj_name
)) {
3884 obj_name
= nargs
[1];
3886 ObjectWriteOperation op
;
3888 ret
= io_ctx
.operate(*obj_name
, &op
);
3890 cerr
<< "error tier-promote " << pool_name
<< "/" << prettify(*obj_name
) << " : "
3891 << cpp_strerror(ret
) << std::endl
;
3894 } else if (strcmp(nargs
[0], "unset-manifest") == 0) {
3895 if (!pool_name
|| (nargs
.size() < 2 && !obj_name
)) {
3900 obj_name
= nargs
[1];
3902 ObjectWriteOperation op
;
3903 op
.unset_manifest();
3904 ret
= io_ctx
.operate(*obj_name
, &op
);
3906 cerr
<< "error unset-manifest " << pool_name
<< "/" << prettify(*obj_name
) << " : "
3907 << cpp_strerror(ret
) << std::endl
;
3910 } else if (strcmp(nargs
[0], "tier-flush") == 0) {
3911 if (!pool_name
|| (nargs
.size() < 2 && !obj_name
)) {
3916 obj_name
= nargs
[1];
3918 ObjectReadOperation op
;
3920 librados::AioCompletion
*completion
=
3921 librados::Rados::aio_create_completion();
3922 io_ctx
.aio_operate(*obj_name
, completion
, &op
,
3923 librados::OPERATION_IGNORE_CACHE
|
3924 librados::OPERATION_IGNORE_OVERLAY
,
3926 completion
->wait_for_complete();
3927 ret
= completion
->get_return_value();
3928 completion
->release();
3930 cerr
<< "error tier-flush " << pool_name
<< "/" << prettify(*obj_name
) << " : "
3931 << cpp_strerror(ret
) << std::endl
;
3934 } else if (strcmp(nargs
[0], "tier-evict") == 0) {
3935 if (!pool_name
|| (nargs
.size() < 2 && !obj_name
)) {
3940 obj_name
= nargs
[1];
3942 ObjectReadOperation op
;
3944 librados::AioCompletion
*completion
=
3945 librados::Rados::aio_create_completion();
3946 io_ctx
.aio_operate(*obj_name
, completion
, &op
,
3947 librados::OPERATION_IGNORE_CACHE
|
3948 librados::OPERATION_IGNORE_OVERLAY
,
3950 completion
->wait_for_complete();
3951 ret
= completion
->get_return_value();
3952 completion
->release();
3954 cerr
<< "error tier-evict " << pool_name
<< "/" << prettify(*obj_name
) << " : "
3955 << cpp_strerror(ret
) << std::endl
;
3958 } else if (strcmp(nargs
[0], "export") == 0) {
3959 // export [filename]
3960 if (!pool_name
|| nargs
.size() > 2) {
3966 if (nargs
.size() < 2 || std::string(nargs
[1]) == "-") {
3967 file_fd
= STDOUT_FILENO
;
3969 file_fd
= open(nargs
[1], O_WRONLY
|O_CREAT
|O_TRUNC
|O_BINARY
, 0666);
3971 cerr
<< "Error opening '" << nargs
[1] << "': "
3972 << cpp_strerror(file_fd
) << std::endl
;
3977 ret
= PoolDump(file_fd
).dump(&io_ctx
);
3979 if (file_fd
!= STDIN_FILENO
) {
3980 VOID_TEMP_FAILURE_RETRY(::close(file_fd
));
3984 cerr
<< "error from export: "
3985 << cpp_strerror(ret
) << std::endl
;
3988 } else if (strcmp(nargs
[0], "import") == 0) {
3989 // import [--no-overwrite] [--dry-run] <filename | - >
3990 if (!pool_name
|| nargs
.size() > 4 || nargs
.size() < 2) {
3995 // Last arg is the filename
3996 std::string
const filename
= nargs
[nargs
.size() - 1];
3998 // All other args may be flags
3999 bool dry_run
= false;
4000 bool no_overwrite
= false;
4001 for (unsigned i
= 1; i
< nargs
.size() - 1; ++i
) {
4002 std::string
arg(nargs
[i
]);
4004 if (arg
== std::string("--no-overwrite")) {
4005 no_overwrite
= true;
4006 } else if (arg
== std::string("--dry-run")) {
4009 std::cerr
<< "Invalid argument '" << arg
<< "'" << std::endl
;
4015 if (filename
== "-") {
4016 file_fd
= STDIN_FILENO
;
4018 file_fd
= open(filename
.c_str(), O_RDONLY
|O_BINARY
);
4020 cerr
<< "Error opening '" << filename
<< "': "
4021 << cpp_strerror(file_fd
) << std::endl
;
4026 ret
= RadosImport(file_fd
, 0, dry_run
).import(io_ctx
, no_overwrite
);
4028 if (file_fd
!= STDIN_FILENO
) {
4029 VOID_TEMP_FAILURE_RETRY(::close(file_fd
));
4033 cerr
<< "error from import: "
4034 << cpp_strerror(ret
) << std::endl
;
4038 cerr
<< "unrecognized command " << nargs
[0] << "; -h or --help for usage" << std::endl
;
4043 cerr
<< "error " << (-ret
) << ": " << cpp_strerror(ret
) << std::endl
;
4045 return (ret
< 0) ? 1 : 0;
4048 int main(int argc
, const char **argv
)
4050 auto args
= argv_to_vec(argc
, argv
);
4052 cerr
<< argv
[0] << ": -h or --help for usage" << std::endl
;
4055 if (ceph_argparse_need_usage(args
)) {
4060 std::map
< std::string
, std::string
> opts
;
4063 // Necessary to support usage of -f for formatting,
4064 // since global_init will remove the -f using ceph
4065 // argparse procedures.
4066 for (auto j
= args
.begin(); j
!= args
.end(); ++j
) {
4067 if (strcmp(*j
, "--") == 0) {
4069 } else if ((j
+1) == args
.end()) {
4070 // This can't be a formatting call (no format arg)
4072 } else if (strcmp(*j
, "-f") == 0) {
4074 unique_ptr
<Formatter
> formatter(Formatter::create(val
.c_str()));
4078 opts
["format"] = val
;
4086 auto cct
= global_init(NULL
, args
, CEPH_ENTITY_TYPE_CLIENT
,
4087 CODE_ENVIRONMENT_UTILITY
, 0);
4088 common_init_finish(g_ceph_context
);
4090 std::vector
<const char*>::iterator i
;
4091 for (i
= args
.begin(); i
!= args
.end(); ) {
4092 if (ceph_argparse_double_dash(args
, i
)) {
4094 } else if (ceph_argparse_flag(args
, i
, "--force-full", (char*)NULL
)) {
4095 opts
["force-full"] = "true";
4096 } else if (ceph_argparse_flag(args
, i
, "-d", "--delete-after", (char*)NULL
)) {
4097 opts
["delete-after"] = "true";
4098 } else if (ceph_argparse_flag(args
, i
, "-C", "--create", "--create-pool",
4100 opts
["create"] = "true";
4101 } else if (ceph_argparse_flag(args
, i
, "--pretty-format", (char*)NULL
)) {
4102 opts
["pretty-format"] = "true";
4103 } else if (ceph_argparse_flag(args
, i
, "--show-time", (char*)NULL
)) {
4104 opts
["show-time"] = "true";
4105 } else if (ceph_argparse_flag(args
, i
, "--no-cleanup", (char*)NULL
)) {
4106 opts
["no-cleanup"] = "true";
4107 } else if (ceph_argparse_flag(args
, i
, "--no-hints", (char*)NULL
)) {
4108 opts
["no-hints"] = "true";
4109 } else if (ceph_argparse_flag(args
, i
, "--reuse-bench", (char*)NULL
)) {
4110 opts
["reuse-bench"] = "true";
4111 } else if (ceph_argparse_flag(args
, i
, "--no-verify", (char*)NULL
)) {
4112 opts
["no-verify"] = "true";
4113 } else if (ceph_argparse_witharg(args
, i
, &val
, "--run-name", (char*)NULL
)) {
4114 opts
["run-name"] = val
;
4115 } else if (ceph_argparse_witharg(args
, i
, &val
, "--prefix", (char*)NULL
)) {
4116 opts
["prefix"] = val
;
4117 } else if (ceph_argparse_witharg(args
, i
, &val
, "-p", "--pool", (char*)NULL
)) {
4119 } else if (ceph_argparse_witharg(args
, i
, &val
, "--target-pool", (char*)NULL
)) {
4120 opts
["target_pool"] = val
;
4121 } else if (ceph_argparse_witharg(args
, i
, &val
, "--object-locator" , (char *)NULL
)) {
4122 opts
["object_locator"] = val
;
4123 } else if (ceph_argparse_witharg(args
, i
, &val
, "--target-locator" , (char *)NULL
)) {
4124 opts
["target_locator"] = val
;
4125 } else if (ceph_argparse_witharg(args
, i
, &val
, "--target-nspace" , (char *)NULL
)) {
4126 opts
["target_nspace"] = val
;
4127 #ifdef WITH_LIBRADOSSTRIPER
4128 } else if (ceph_argparse_flag(args
, i
, "--striper" , (char *)NULL
)) {
4129 opts
["striper"] = "true";
4131 } else if (ceph_argparse_witharg(args
, i
, &val
, "-t", "--concurrent-ios", (char*)NULL
)) {
4132 opts
["concurrent-ios"] = val
;
4133 } else if (ceph_argparse_witharg(args
, i
, &val
, "--block-size", (char*)NULL
)) {
4134 opts
["block-size"] = val
;
4135 } else if (ceph_argparse_witharg(args
, i
, &val
, "-b", (char*)NULL
)) {
4136 opts
["block-size"] = val
;
4137 } else if (ceph_argparse_witharg(args
, i
, &val
, "--object-size", (char*)NULL
)) {
4138 opts
["object-size"] = val
;
4139 } else if (ceph_argparse_witharg(args
, i
, &val
, "--max-objects", (char*)NULL
)) {
4140 opts
["max-objects"] = val
;
4141 } else if (ceph_argparse_witharg(args
, i
, &val
, "--offset", (char*)NULL
)) {
4142 opts
["offset"] = val
;
4143 } else if (ceph_argparse_witharg(args
, i
, &val
, "-O", (char*)NULL
)) {
4144 opts
["object-size"] = val
;
4145 } else if (ceph_argparse_witharg(args
, i
, &val
, "-s", "--snap", (char*)NULL
)) {
4147 } else if (ceph_argparse_witharg(args
, i
, &val
, "-S", "--snapid", (char*)NULL
)) {
4148 opts
["snapid"] = val
;
4149 } else if (ceph_argparse_witharg(args
, i
, &val
, "--min-object-size", (char*)NULL
)) {
4150 opts
["min-object-size"] = val
;
4151 } else if (ceph_argparse_witharg(args
, i
, &val
, "--max-object-size", (char*)NULL
)) {
4152 opts
["max-object-size"] = val
;
4153 } else if (ceph_argparse_witharg(args
, i
, &val
, "--min-op-len", (char*)NULL
)) {
4154 opts
["min-op-len"] = val
;
4155 } else if (ceph_argparse_witharg(args
, i
, &val
, "--max-op-len", (char*)NULL
)) {
4156 opts
["max-op-len"] = val
;
4157 } else if (ceph_argparse_witharg(args
, i
, &val
, "--max-ops", (char*)NULL
)) {
4158 opts
["max-ops"] = val
;
4159 } else if (ceph_argparse_witharg(args
, i
, &val
, "--max-backlog", (char*)NULL
)) {
4160 opts
["max-backlog"] = val
;
4161 } else if (ceph_argparse_witharg(args
, i
, &val
, "--target-throughput", (char*)NULL
)) {
4162 opts
["target-throughput"] = val
;
4163 } else if (ceph_argparse_witharg(args
, i
, &val
, "--offset-align", (char*)NULL
)) {
4164 opts
["offset_align"] = val
;
4165 } else if (ceph_argparse_witharg(args
, i
, &val
, "--read-percent", (char*)NULL
)) {
4166 opts
["read-percent"] = val
;
4167 } else if (ceph_argparse_witharg(args
, i
, &val
, "--num-objects", (char*)NULL
)) {
4168 opts
["num-objects"] = val
;
4169 } else if (ceph_argparse_witharg(args
, i
, &val
, "--run-length", (char*)NULL
)) {
4170 opts
["run-length"] = val
;
4171 } else if (ceph_argparse_witharg(args
, i
, &val
, "--workers", (char*)NULL
)) {
4172 opts
["workers"] = val
;
4173 } else if (ceph_argparse_witharg(args
, i
, &val
, "-f", "--format", (char*)NULL
)) {
4174 opts
["format"] = val
;
4175 } else if (ceph_argparse_witharg(args
, i
, &val
, "--lock-tag", (char*)NULL
)) {
4176 opts
["lock-tag"] = val
;
4177 } else if (ceph_argparse_witharg(args
, i
, &val
, "--lock-cookie", (char*)NULL
)) {
4178 opts
["lock-cookie"] = val
;
4179 } else if (ceph_argparse_witharg(args
, i
, &val
, "--lock-description", (char*)NULL
)) {
4180 opts
["lock-description"] = val
;
4181 } else if (ceph_argparse_witharg(args
, i
, &val
, "--lock-duration", (char*)NULL
)) {
4182 opts
["lock-duration"] = val
;
4183 } else if (ceph_argparse_witharg(args
, i
, &val
, "--lock-type", (char*)NULL
)) {
4184 opts
["lock-type"] = val
;
4185 } else if (ceph_argparse_witharg(args
, i
, &val
, "-N", "--namespace", (char*)NULL
)) {
4186 opts
["namespace"] = val
;
4187 } else if (ceph_argparse_flag(args
, i
, "--all", (char*)NULL
)) {
4188 opts
["all"] = "true";
4189 } else if (ceph_argparse_flag(args
, i
, "--default", (char*)NULL
)) {
4190 opts
["default"] = "true";
4191 } else if (ceph_argparse_witharg(args
, i
, &val
, "-o", "--output", (char*)NULL
)) {
4192 opts
["output"] = val
;
4193 } else if (ceph_argparse_flag(args
, i
, "--write-omap", (char*)NULL
)) {
4194 opts
["write-dest-omap"] = "true";
4195 } else if (ceph_argparse_flag(args
, i
, "--write-object", (char*)NULL
)) {
4196 opts
["write-dest-obj"] = "true";
4197 } else if (ceph_argparse_flag(args
, i
, "--write-xattr", (char*)NULL
)) {
4198 opts
["write-dest-xattr"] = "true";
4199 } else if (ceph_argparse_flag(args
, i
, "--with-clones", (char*)NULL
)) {
4200 opts
["with-clones"] = "true";
4201 } else if (ceph_argparse_witharg(args
, i
, &val
, "--omap-key-file", (char*)NULL
)) {
4202 opts
["omap-key-file"] = val
;
4203 } else if (ceph_argparse_witharg(args
, i
, &val
, "--obj-name-file", (char*)NULL
)) {
4204 opts
["obj-name-file"] = val
;
4205 } else if (ceph_argparse_flag(args
, i
, "--with-reference", (char*)NULL
)) {
4206 opts
["with-reference"] = "true";
4207 } else if (ceph_argparse_witharg(args
, i
, &val
, "--pgid", (char*)NULL
)) {
4209 } else if (ceph_argparse_witharg(args
, i
, &val
, "--input-file", (char*)NULL
)) {
4210 opts
["input_file"] = val
;
4219 cerr
<< "rados: you must give an action. Try --help" << std::endl
;
4223 return rados_tool_common(opts
, args
);