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) 2018 Red Hat <contact@redhat.com>
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 #define BOOST_BIND_NO_PLACEHOLDERS
18 #include <string_view>
20 #include <boost/intrusive_ptr.hpp>
22 #include <fmt/format.h>
24 #include "include/ceph_fs.h"
26 #include "common/ceph_context.h"
27 #include "common/ceph_argparse.h"
28 #include "common/common_init.h"
29 #include "common/hobject.h"
30 #include "common/EventTrace.h"
32 #include "global/global_init.h"
34 #include "osd/osd_types.h"
35 #include "osdc/error_code.h"
37 #include "neorados/RADOSImpl.h"
38 #include "include/neorados/RADOS.hpp"
40 namespace bc
= boost::container
;
41 namespace bs
= boost::system
;
42 namespace ca
= ceph::async
;
43 namespace cb
= ceph::buffer
;
49 static_assert(impl_size
>= sizeof(object_t
));
50 new (&impl
) object_t();
53 Object::Object(const char* s
) {
54 static_assert(impl_size
>= sizeof(object_t
));
55 new (&impl
) object_t(s
);
58 Object::Object(std::string_view s
) {
59 static_assert(impl_size
>= sizeof(object_t
));
60 new (&impl
) object_t(s
);
63 Object::Object(std::string
&& s
) {
64 static_assert(impl_size
>= sizeof(object_t
));
65 new (&impl
) object_t(std::move(s
));
68 Object::Object(const std::string
& s
) {
69 static_assert(impl_size
>= sizeof(object_t
));
70 new (&impl
) object_t(s
);
74 reinterpret_cast<object_t
*>(&impl
)->~object_t();
77 Object::Object(const Object
& o
) {
78 static_assert(impl_size
>= sizeof(object_t
));
79 new (&impl
) object_t(*reinterpret_cast<const object_t
*>(&o
.impl
));
81 Object
& Object::operator =(const Object
& o
) {
82 *reinterpret_cast<object_t
*>(&impl
) =
83 *reinterpret_cast<const object_t
*>(&o
.impl
);
86 Object::Object(Object
&& o
) {
87 static_assert(impl_size
>= sizeof(object_t
));
88 new (&impl
) object_t(std::move(*reinterpret_cast<object_t
*>(&o
.impl
)));
90 Object
& Object::operator =(Object
&& o
) {
91 *reinterpret_cast<object_t
*>(&impl
) =
92 std::move(*reinterpret_cast<object_t
*>(&o
.impl
));
96 Object::operator std::string_view() const {
97 return std::string_view(reinterpret_cast<const object_t
*>(&impl
)->name
);
100 bool operator <(const Object
& lhs
, const Object
& rhs
) {
101 return (*reinterpret_cast<const object_t
*>(&lhs
.impl
) <
102 *reinterpret_cast<const object_t
*>(&rhs
.impl
));
104 bool operator <=(const Object
& lhs
, const Object
& rhs
) {
105 return (*reinterpret_cast<const object_t
*>(&lhs
.impl
) <=
106 *reinterpret_cast<const object_t
*>(&rhs
.impl
));
108 bool operator >=(const Object
& lhs
, const Object
& rhs
) {
109 return (*reinterpret_cast<const object_t
*>(&lhs
.impl
) >=
110 *reinterpret_cast<const object_t
*>(&rhs
.impl
));
112 bool operator >(const Object
& lhs
, const Object
& rhs
) {
113 return (*reinterpret_cast<const object_t
*>(&lhs
.impl
) >
114 *reinterpret_cast<const object_t
*>(&rhs
.impl
));
117 bool operator ==(const Object
& lhs
, const Object
& rhs
) {
118 return (*reinterpret_cast<const object_t
*>(&lhs
.impl
) ==
119 *reinterpret_cast<const object_t
*>(&rhs
.impl
));
121 bool operator !=(const Object
& lhs
, const Object
& rhs
) {
122 return (*reinterpret_cast<const object_t
*>(&lhs
.impl
) !=
123 *reinterpret_cast<const object_t
*>(&rhs
.impl
));
126 std::ostream
& operator <<(std::ostream
& m
, const Object
& o
) {
127 return (m
<< *reinterpret_cast<const object_t
*>(&o
.impl
));
132 struct IOContextImpl
{
133 object_locator_t oloc
;
134 snapid_t snap_seq
= CEPH_NOSNAP
;
136 int extra_op_flags
= 0;
139 IOContext::IOContext() {
140 static_assert(impl_size
>= sizeof(IOContextImpl
));
141 new (&impl
) IOContextImpl();
144 IOContext::IOContext(std::int64_t _pool
) : IOContext() {
148 IOContext::IOContext(std::int64_t _pool
, std::string_view _ns
)
154 IOContext::IOContext(std::int64_t _pool
, std::string
&& _ns
)
160 IOContext::~IOContext() {
161 reinterpret_cast<IOContextImpl
*>(&impl
)->~IOContextImpl();
164 IOContext::IOContext(const IOContext
& rhs
) {
165 static_assert(impl_size
>= sizeof(IOContextImpl
));
166 new (&impl
) IOContextImpl(*reinterpret_cast<const IOContextImpl
*>(&rhs
.impl
));
169 IOContext
& IOContext::operator =(const IOContext
& rhs
) {
170 *reinterpret_cast<IOContextImpl
*>(&impl
) =
171 *reinterpret_cast<const IOContextImpl
*>(&rhs
.impl
);
175 IOContext::IOContext(IOContext
&& rhs
) {
176 static_assert(impl_size
>= sizeof(IOContextImpl
));
177 new (&impl
) IOContextImpl(
178 std::move(*reinterpret_cast<IOContextImpl
*>(&rhs
.impl
)));
181 IOContext
& IOContext::operator =(IOContext
&& rhs
) {
182 *reinterpret_cast<IOContextImpl
*>(&impl
) =
183 std::move(*reinterpret_cast<IOContextImpl
*>(&rhs
.impl
));
187 std::int64_t IOContext::pool() const {
188 return reinterpret_cast<const IOContextImpl
*>(&impl
)->oloc
.pool
;
191 void IOContext::pool(std::int64_t _pool
) {
192 reinterpret_cast<IOContextImpl
*>(&impl
)->oloc
.pool
= _pool
;
195 std::string_view
IOContext::ns() const {
196 return reinterpret_cast<const IOContextImpl
*>(&impl
)->oloc
.nspace
;
199 void IOContext::ns(std::string_view _ns
) {
200 reinterpret_cast<IOContextImpl
*>(&impl
)->oloc
.nspace
= _ns
;
203 void IOContext::ns(std::string
&& _ns
) {
204 reinterpret_cast<IOContextImpl
*>(&impl
)->oloc
.nspace
= std::move(_ns
);
207 std::optional
<std::string_view
> IOContext::key() const {
208 auto& oloc
= reinterpret_cast<const IOContextImpl
*>(&impl
)->oloc
;
209 if (oloc
.key
.empty())
212 return std::string_view(oloc
.key
);
215 void IOContext::key(std::string_view _key
) {
216 auto& oloc
= reinterpret_cast<IOContextImpl
*>(&impl
)->oloc
;
221 void IOContext::key(std::string
&&_key
) {
222 auto& oloc
= reinterpret_cast<IOContextImpl
*>(&impl
)->oloc
;
224 oloc
.key
= std::move(_key
);
227 void IOContext::clear_key() {
228 auto& oloc
= reinterpret_cast<IOContextImpl
*>(&impl
)->oloc
;
233 std::optional
<std::int64_t> IOContext::hash() const {
234 auto& oloc
= reinterpret_cast<const IOContextImpl
*>(&impl
)->oloc
;
241 void IOContext::hash(std::int64_t _hash
) {
242 auto& oloc
= reinterpret_cast<IOContextImpl
*>(&impl
)->oloc
;
247 void IOContext::clear_hash() {
248 auto& oloc
= reinterpret_cast<IOContextImpl
*>(&impl
)->oloc
;
254 std::optional
<std::uint64_t> IOContext::read_snap() const {
255 auto& snap_seq
= reinterpret_cast<const IOContextImpl
*>(&impl
)->snap_seq
;
256 if (snap_seq
== CEPH_NOSNAP
)
261 void IOContext::read_snap(std::optional
<std::uint64_t> _snapid
) {
262 auto& snap_seq
= reinterpret_cast<IOContextImpl
*>(&impl
)->snap_seq
;
263 snap_seq
= _snapid
.value_or(CEPH_NOSNAP
);
267 std::pair
<std::uint64_t,
268 std::vector
<std::uint64_t>>> IOContext::write_snap_context() const {
269 auto& snapc
= reinterpret_cast<const IOContextImpl
*>(&impl
)->snapc
;
273 std::vector
<uint64_t> v(snapc
.snaps
.begin(), snapc
.snaps
.end());
274 return std::make_optional(std::make_pair(uint64_t(snapc
.seq
), v
));
278 void IOContext::write_snap_context(
279 std::optional
<std::pair
<std::uint64_t, std::vector
<std::uint64_t>>> _snapc
) {
280 auto& snapc
= reinterpret_cast<IOContextImpl
*>(&impl
)->snapc
;
284 SnapContext
n(_snapc
->first
, { _snapc
->second
.begin(), _snapc
->second
.end()});
286 throw bs::system_error(EINVAL
,
287 bs::system_category(),
288 "Invalid snap context.");
296 bool IOContext::full_try() const {
297 const auto ioc
= reinterpret_cast<const IOContextImpl
*>(&impl
);
298 return (ioc
->extra_op_flags
& CEPH_OSD_FLAG_FULL_TRY
) != 0;
301 void IOContext::full_try(bool _full_try
) {
302 auto ioc
= reinterpret_cast<IOContextImpl
*>(&impl
);
304 ioc
->extra_op_flags
|= CEPH_OSD_FLAG_FULL_TRY
;
306 ioc
->extra_op_flags
&= ~CEPH_OSD_FLAG_FULL_TRY
;
310 bool operator <(const IOContext
& lhs
, const IOContext
& rhs
) {
311 const auto l
= reinterpret_cast<const IOContextImpl
*>(&lhs
.impl
);
312 const auto r
= reinterpret_cast<const IOContextImpl
*>(&rhs
.impl
);
314 return (std::tie(l
->oloc
.pool
, l
->oloc
.nspace
, l
->oloc
.key
) <
315 std::tie(r
->oloc
.pool
, r
->oloc
.nspace
, r
->oloc
.key
));
318 bool operator <=(const IOContext
& lhs
, const IOContext
& rhs
) {
319 const auto l
= reinterpret_cast<const IOContextImpl
*>(&lhs
.impl
);
320 const auto r
= reinterpret_cast<const IOContextImpl
*>(&rhs
.impl
);
322 return (std::tie(l
->oloc
.pool
, l
->oloc
.nspace
, l
->oloc
.key
) <=
323 std::tie(r
->oloc
.pool
, r
->oloc
.nspace
, r
->oloc
.key
));
326 bool operator >=(const IOContext
& lhs
, const IOContext
& rhs
) {
327 const auto l
= reinterpret_cast<const IOContextImpl
*>(&lhs
.impl
);
328 const auto r
= reinterpret_cast<const IOContextImpl
*>(&rhs
.impl
);
330 return (std::tie(l
->oloc
.pool
, l
->oloc
.nspace
, l
->oloc
.key
) >=
331 std::tie(r
->oloc
.pool
, r
->oloc
.nspace
, r
->oloc
.key
));
334 bool operator >(const IOContext
& lhs
, const IOContext
& rhs
) {
335 const auto l
= reinterpret_cast<const IOContextImpl
*>(&lhs
.impl
);
336 const auto r
= reinterpret_cast<const IOContextImpl
*>(&rhs
.impl
);
338 return (std::tie(l
->oloc
.pool
, l
->oloc
.nspace
, l
->oloc
.key
) >
339 std::tie(r
->oloc
.pool
, r
->oloc
.nspace
, r
->oloc
.key
));
342 bool operator ==(const IOContext
& lhs
, const IOContext
& rhs
) {
343 const auto l
= reinterpret_cast<const IOContextImpl
*>(&lhs
.impl
);
344 const auto r
= reinterpret_cast<const IOContextImpl
*>(&rhs
.impl
);
346 return (std::tie(l
->oloc
.pool
, l
->oloc
.nspace
, l
->oloc
.key
) ==
347 std::tie(r
->oloc
.pool
, r
->oloc
.nspace
, r
->oloc
.key
));
350 bool operator !=(const IOContext
& lhs
, const IOContext
& rhs
) {
351 const auto l
= reinterpret_cast<const IOContextImpl
*>(&lhs
.impl
);
352 const auto r
= reinterpret_cast<const IOContextImpl
*>(&rhs
.impl
);
354 return (std::tie(l
->oloc
.pool
, l
->oloc
.nspace
, l
->oloc
.key
) !=
355 std::tie(r
->oloc
.pool
, r
->oloc
.nspace
, r
->oloc
.key
));
358 std::ostream
& operator <<(std::ostream
& m
, const IOContext
& o
) {
359 const auto l
= reinterpret_cast<const IOContextImpl
*>(&o
.impl
);
360 return (m
<< l
->oloc
.pool
<< ":" << l
->oloc
.nspace
<< ":" << l
->oloc
.key
);
368 std::optional
<ceph::real_time
> mtime
;
372 OpImpl(const OpImpl
& rhs
) = delete;
373 OpImpl(OpImpl
&& rhs
) = default;
375 OpImpl
& operator =(const OpImpl
& rhs
) = delete;
376 OpImpl
& operator =(OpImpl
&& rhs
) = default;
380 static_assert(Op::impl_size
>= sizeof(OpImpl
));
385 new (&impl
) OpImpl(std::move(*reinterpret_cast<OpImpl
*>(&rhs
.impl
)));
387 Op
& Op::operator =(Op
&& rhs
) {
388 reinterpret_cast<OpImpl
*>(&impl
)->~OpImpl();
389 new (&impl
) OpImpl(std::move(*reinterpret_cast<OpImpl
*>(&rhs
.impl
)));
393 reinterpret_cast<OpImpl
*>(&impl
)->~OpImpl();
396 void Op::set_excl() {
397 reinterpret_cast<OpImpl
*>(&impl
)->op
.set_last_op_flags(CEPH_OSD_OP_FLAG_EXCL
);
399 void Op::set_failok() {
400 reinterpret_cast<OpImpl
*>(&impl
)->op
.set_last_op_flags(
401 CEPH_OSD_OP_FLAG_FAILOK
);
403 void Op::set_fadvise_random() {
404 reinterpret_cast<OpImpl
*>(&impl
)->op
.set_last_op_flags(
405 CEPH_OSD_OP_FLAG_FADVISE_RANDOM
);
407 void Op::set_fadvise_sequential() {
408 reinterpret_cast<OpImpl
*>(&impl
)->op
.set_last_op_flags(
409 CEPH_OSD_OP_FLAG_FADVISE_SEQUENTIAL
);
411 void Op::set_fadvise_willneed() {
412 reinterpret_cast<OpImpl
*>(&impl
)->op
.set_last_op_flags(
413 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
415 void Op::set_fadvise_dontneed() {
416 reinterpret_cast<OpImpl
*>(&impl
)->op
.set_last_op_flags(
417 CEPH_OSD_OP_FLAG_FADVISE_DONTNEED
);
419 void Op::set_fadvise_nocache() {
420 reinterpret_cast<OpImpl
*>(&impl
)->op
.set_last_op_flags(
421 CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
424 void Op::cmpext(uint64_t off
, bufferlist
&& cmp_bl
, std::size_t* s
) {
425 reinterpret_cast<OpImpl
*>(&impl
)->op
.cmpext(off
, std::move(cmp_bl
), nullptr,
428 void Op::cmpxattr(std::string_view name
, cmpxattr_op op
, const bufferlist
& val
) {
429 reinterpret_cast<OpImpl
*>(&impl
)->
430 op
.cmpxattr(name
, std::uint8_t(op
), CEPH_OSD_CMPXATTR_MODE_STRING
, val
);
432 void Op::cmpxattr(std::string_view name
, cmpxattr_op op
, std::uint64_t val
) {
435 reinterpret_cast<OpImpl
*>(&impl
)->
436 op
.cmpxattr(name
, std::uint8_t(op
), CEPH_OSD_CMPXATTR_MODE_U64
, bl
);
439 void Op::assert_version(uint64_t ver
) {
440 reinterpret_cast<OpImpl
*>(&impl
)->op
.assert_version(ver
);
442 void Op::assert_exists() {
443 reinterpret_cast<OpImpl
*>(&impl
)->op
.stat(
445 static_cast<ceph::real_time
*>(nullptr),
446 static_cast<bs::error_code
*>(nullptr));
448 void Op::cmp_omap(const bc::flat_map
<
449 std::string
, std::pair
<cb::list
,
451 reinterpret_cast<OpImpl
*>(&impl
)->op
.omap_cmp(assertions
, nullptr);
454 void Op::exec(std::string_view cls
, std::string_view method
,
455 const bufferlist
& inbl
,
457 bs::error_code
* ec
) {
458 reinterpret_cast<OpImpl
*>(&impl
)->op
.call(cls
, method
, inbl
, ec
, out
);
461 void Op::exec(std::string_view cls
, std::string_view method
,
462 const bufferlist
& inbl
,
463 fu2::unique_function
<void(bs::error_code
,
464 const cb::list
&) &&> f
) {
465 reinterpret_cast<OpImpl
*>(&impl
)->op
.call(cls
, method
, inbl
, std::move(f
));
468 void Op::exec(std::string_view cls
, std::string_view method
,
469 const bufferlist
& inbl
,
470 fu2::unique_function
<void(bs::error_code
, int,
471 const cb::list
&) &&> f
) {
472 reinterpret_cast<OpImpl
*>(&impl
)->op
.call(cls
, method
, inbl
, std::move(f
));
475 void Op::exec(std::string_view cls
, std::string_view method
,
476 const bufferlist
& inbl
, bs::error_code
* ec
) {
477 reinterpret_cast<OpImpl
*>(&impl
)->op
.call(cls
, method
, inbl
, ec
);
480 void Op::balance_reads() {
481 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_BALANCE_READS
;
483 void Op::localize_reads() {
484 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_LOCALIZE_READS
;
486 void Op::order_reads_writes() {
487 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_RWORDERED
;
489 void Op::ignore_cache() {
490 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_IGNORE_CACHE
;
492 void Op::skiprwlocks() {
493 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_SKIPRWLOCKS
;
495 void Op::ignore_overlay() {
496 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_IGNORE_OVERLAY
;
498 void Op::full_try() {
499 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_FULL_TRY
;
501 void Op::full_force() {
502 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_FULL_FORCE
;
504 void Op::ignore_redirect() {
505 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_IGNORE_REDIRECT
;
507 void Op::ordersnap() {
508 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_ORDERSNAP
;
510 void Op::returnvec() {
511 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_RETURNVEC
;
514 std::size_t Op::size() const {
515 return reinterpret_cast<const OpImpl
*>(&impl
)->op
.size();
518 std::ostream
& operator <<(std::ostream
& m
, const Op
& o
) {
519 return m
<< reinterpret_cast<const OpImpl
*>(&o
.impl
)->op
;
527 void ReadOp::read(size_t off
, uint64_t len
, cb::list
* out
,
528 bs::error_code
* ec
) {
529 reinterpret_cast<OpImpl
*>(&impl
)->op
.read(off
, len
, ec
, out
);
532 void ReadOp::get_xattr(std::string_view name
, cb::list
* out
,
533 bs::error_code
* ec
) {
534 reinterpret_cast<OpImpl
*>(&impl
)->op
.getxattr(name
, ec
, out
);
537 void ReadOp::get_omap_header(cb::list
* out
,
538 bs::error_code
* ec
) {
539 reinterpret_cast<OpImpl
*>(&impl
)->op
.omap_get_header(ec
, out
);
542 void ReadOp::sparse_read(uint64_t off
, uint64_t len
, cb::list
* out
,
543 std::vector
<std::pair
<std::uint64_t,
544 std::uint64_t>>* extents
,
545 bs::error_code
* ec
) {
546 reinterpret_cast<OpImpl
*>(&impl
)->op
.sparse_read(off
, len
, ec
, extents
, out
);
549 void ReadOp::stat(std::uint64_t* size
, ceph::real_time
* mtime
,
550 bs::error_code
* ec
) {
551 reinterpret_cast<OpImpl
*>(&impl
)->op
.stat(size
, mtime
, ec
);
554 void ReadOp::get_omap_keys(std::optional
<std::string_view
> start_after
,
555 std::uint64_t max_return
,
556 bc::flat_set
<std::string
>* keys
,
558 bs::error_code
* ec
) {
559 reinterpret_cast<OpImpl
*>(&impl
)->op
.omap_get_keys(start_after
, max_return
,
563 void ReadOp::get_xattrs(bc::flat_map
<std::string
,
565 bs::error_code
* ec
) {
566 reinterpret_cast<OpImpl
*>(&impl
)->op
.getxattrs(ec
, kv
);
569 void ReadOp::get_omap_vals(std::optional
<std::string_view
> start_after
,
570 std::optional
<std::string_view
> filter_prefix
,
572 bc::flat_map
<std::string
,
575 bs::error_code
* ec
) {
576 reinterpret_cast<OpImpl
*>(&impl
)->op
.omap_get_vals(start_after
, filter_prefix
,
577 max_return
, ec
, kv
, done
);
580 void ReadOp::get_omap_vals_by_keys(
581 const bc::flat_set
<std::string
>& keys
,
582 bc::flat_map
<std::string
, cb::list
>* kv
,
583 bs::error_code
* ec
) {
584 reinterpret_cast<OpImpl
*>(&impl
)->op
.omap_get_vals_by_keys(keys
, ec
, kv
);
587 void ReadOp::list_watchers(std::vector
<ObjWatcher
>* watchers
,
588 bs::error_code
* ec
) {
589 reinterpret_cast<OpImpl
*>(&impl
)-> op
.list_watchers(watchers
, ec
);
592 void ReadOp::list_snaps(SnapSet
* snaps
,
593 bs::error_code
* ec
) {
594 reinterpret_cast<OpImpl
*>(&impl
)->op
.list_snaps(snaps
, nullptr, ec
);
599 void WriteOp::set_mtime(ceph::real_time t
) {
600 auto o
= reinterpret_cast<OpImpl
*>(&impl
);
604 void WriteOp::create(bool exclusive
) {
605 reinterpret_cast<OpImpl
*>(&impl
)->op
.create(exclusive
);
608 void WriteOp::write(uint64_t off
, bufferlist
&& bl
) {
609 reinterpret_cast<OpImpl
*>(&impl
)->op
.write(off
, bl
);
612 void WriteOp::write_full(bufferlist
&& bl
) {
613 reinterpret_cast<OpImpl
*>(&impl
)->op
.write_full(bl
);
616 void WriteOp::writesame(uint64_t off
, uint64_t write_len
, bufferlist
&& bl
) {
617 reinterpret_cast<OpImpl
*>(&impl
)->op
.writesame(off
, write_len
, bl
);
620 void WriteOp::append(bufferlist
&& bl
) {
621 reinterpret_cast<OpImpl
*>(&impl
)->op
.append(bl
);
624 void WriteOp::remove() {
625 reinterpret_cast<OpImpl
*>(&impl
)->op
.remove();
628 void WriteOp::truncate(uint64_t off
) {
629 reinterpret_cast<OpImpl
*>(&impl
)->op
.truncate(off
);
632 void WriteOp::zero(uint64_t off
, uint64_t len
) {
633 reinterpret_cast<OpImpl
*>(&impl
)->op
.zero(off
, len
);
636 void WriteOp::rmxattr(std::string_view name
) {
637 reinterpret_cast<OpImpl
*>(&impl
)->op
.rmxattr(name
);
640 void WriteOp::setxattr(std::string_view name
,
642 reinterpret_cast<OpImpl
*>(&impl
)->op
.setxattr(name
, bl
);
645 void WriteOp::rollback(uint64_t snapid
) {
646 reinterpret_cast<OpImpl
*>(&impl
)->op
.rollback(snapid
);
649 void WriteOp::set_omap(
650 const bc::flat_map
<std::string
, cb::list
>& map
) {
651 reinterpret_cast<OpImpl
*>(&impl
)->op
.omap_set(map
);
654 void WriteOp::set_omap_header(bufferlist
&& bl
) {
655 reinterpret_cast<OpImpl
*>(&impl
)->op
.omap_set_header(bl
);
658 void WriteOp::clear_omap() {
659 reinterpret_cast<OpImpl
*>(&impl
)->op
.omap_clear();
662 void WriteOp::rm_omap_keys(
663 const bc::flat_set
<std::string
>& to_rm
) {
664 reinterpret_cast<OpImpl
*>(&impl
)->op
.omap_rm_keys(to_rm
);
667 void WriteOp::set_alloc_hint(uint64_t expected_object_size
,
668 uint64_t expected_write_size
,
669 alloc_hint::alloc_hint_t flags
) {
670 using namespace alloc_hint
;
671 static_assert(sequential_write
==
672 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_WRITE
));
673 static_assert(random_write
==
674 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_WRITE
));
675 static_assert(sequential_read
==
676 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ
));
677 static_assert(random_read
==
678 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_READ
));
679 static_assert(append_only
==
680 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_APPEND_ONLY
));
681 static_assert(immutable
==
682 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_IMMUTABLE
));
683 static_assert(shortlived
==
684 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_SHORTLIVED
));
685 static_assert(longlived
==
686 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_LONGLIVED
));
687 static_assert(compressible
==
688 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_COMPRESSIBLE
));
689 static_assert(incompressible
==
690 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_INCOMPRESSIBLE
));
692 reinterpret_cast<OpImpl
*>(&impl
)->op
.set_alloc_hint(expected_object_size
,
699 RADOS::Builder
& RADOS::Builder::add_conf_file(std::string_view f
) {
701 *conf_files
+= (", " + std::string(f
));
703 conf_files
= std::string(f
);
707 void RADOS::Builder::build(boost::asio::io_context
& ioctx
,
708 std::unique_ptr
<BuildComp
> c
) {
709 constexpr auto env
= CODE_ENVIRONMENT_LIBRARY
;
710 CephInitParameters
ci(env
);
712 ci
.name
.set(CEPH_ENTITY_TYPE_CLIENT
, *name
);
714 ci
.name
.set(CEPH_ENTITY_TYPE_CLIENT
, "admin");
717 flags
|= CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
;
719 flags
|= CINIT_FLAG_NO_MON_CONFIG
;
721 CephContext
*cct
= common_preinit(ci
, env
, flags
);
723 cct
->_conf
->cluster
= *cluster
;
726 cct
->_conf
->no_mon_config
= true;
728 // TODO: Come up with proper error codes here. Maybe augment the
729 // functions with a default bs::error_code* parameter to
732 std::ostringstream ss
;
733 auto r
= cct
->_conf
.parse_config_files(conf_files
? conf_files
->data() : nullptr,
736 c
->post(std::move(c
), ceph::to_error_code(r
), RADOS
{nullptr});
739 cct
->_conf
.parse_env(cct
->get_module_type());
741 for (const auto& [n
, v
] : configs
) {
742 std::stringstream ss
;
743 auto r
= cct
->_conf
.set_val(n
, v
, &ss
);
745 c
->post(std::move(c
), ceph::to_error_code(-EINVAL
), RADOS
{nullptr});
749 MonClient
mc_bootstrap(cct
, ioctx
);
750 // TODO This function should return an error code.
751 auto err
= mc_bootstrap
.get_monmap_and_config();
753 c
->post(std::move(c
), ceph::to_error_code(err
), RADOS
{nullptr});
755 if (!cct
->_log
->is_started()) {
758 common_init_finish(cct
);
760 RADOS::make_with_cct(cct
, ioctx
, std::move(c
));
763 void RADOS::make_with_cct(CephContext
* cct
,
764 boost::asio::io_context
& ioctx
,
765 std::unique_ptr
<BuildComp
> c
) {
767 auto r
= new detail::NeoClient
{std::make_unique
<detail::RADOS
>(ioctx
, cct
)};
768 r
->objecter
->wait_for_osd_map(
769 [c
= std::move(c
), r
= std::unique_ptr
<detail::Client
>(r
)]() mutable {
770 c
->dispatch(std::move(c
), bs::error_code
{},
771 RADOS
{std::move(r
)});
773 } catch (const bs::system_error
& err
) {
774 c
->post(std::move(c
), err
.code(), RADOS
{nullptr});
778 RADOS
RADOS::make_with_librados(librados::Rados
& rados
) {
779 return RADOS
{std::make_unique
<detail::RadosClient
>(rados
.client
)};
782 RADOS::RADOS() = default;
784 RADOS::RADOS(std::unique_ptr
<detail::Client
> impl
)
785 : impl(std::move(impl
)) {}
787 RADOS::RADOS(RADOS
&&) = default;
788 RADOS
& RADOS::operator =(RADOS
&&) = default;
790 RADOS::~RADOS() = default;
792 RADOS::executor_type
RADOS::get_executor() const {
793 return impl
->ioctx
.get_executor();
796 boost::asio::io_context
& RADOS::get_io_context() {
800 void RADOS::execute(const Object
& o
, const IOContext
& _ioc
, ReadOp
&& _op
,
802 std::unique_ptr
<ReadOp::Completion
> c
, version_t
* objver
,
803 const blkin_trace_info
*trace_info
) {
804 auto oid
= reinterpret_cast<const object_t
*>(&o
.impl
);
805 auto ioc
= reinterpret_cast<const IOContextImpl
*>(&_ioc
.impl
);
806 auto op
= reinterpret_cast<OpImpl
*>(&_op
.impl
);
807 auto flags
= op
->op
.flags
| ioc
->extra_op_flags
;
809 ZTracer::Trace trace
;
811 ZTracer::Trace
parent_trace("", nullptr, trace_info
);
812 trace
.init("rados execute", &impl
->objecter
->trace_endpoint
, &parent_trace
);
816 impl
->objecter
->read(
817 *oid
, ioc
->oloc
, std::move(op
->op
), ioc
->snap_seq
, bl
, flags
,
818 std::move(c
), objver
, nullptr /* data_offset */, 0 /* features */, &trace
);
820 trace
.event("submitted");
823 void RADOS::execute(const Object
& o
, const IOContext
& _ioc
, WriteOp
&& _op
,
824 std::unique_ptr
<WriteOp::Completion
> c
, version_t
* objver
,
825 const blkin_trace_info
*trace_info
) {
826 auto oid
= reinterpret_cast<const object_t
*>(&o
.impl
);
827 auto ioc
= reinterpret_cast<const IOContextImpl
*>(&_ioc
.impl
);
828 auto op
= reinterpret_cast<OpImpl
*>(&_op
.impl
);
829 auto flags
= op
->op
.flags
| ioc
->extra_op_flags
;
830 ceph::real_time mtime
;
834 mtime
= ceph::real_clock::now();
836 ZTracer::Trace trace
;
838 ZTracer::Trace
parent_trace("", nullptr, trace_info
);
839 trace
.init("rados execute", &impl
->objecter
->trace_endpoint
, &parent_trace
);
843 impl
->objecter
->mutate(
844 *oid
, ioc
->oloc
, std::move(op
->op
), ioc
->snapc
,
846 std::move(c
), objver
, osd_reqid_t
{}, &trace
);
847 trace
.event("submitted");
850 void RADOS::execute(const Object
& o
, std::int64_t pool
, ReadOp
&& _op
,
852 std::unique_ptr
<ReadOp::Completion
> c
,
853 std::optional
<std::string_view
> ns
,
854 std::optional
<std::string_view
> key
,
856 auto oid
= reinterpret_cast<const object_t
*>(&o
.impl
);
857 auto op
= reinterpret_cast<OpImpl
*>(&_op
.impl
);
858 auto flags
= op
->op
.flags
;
859 object_locator_t oloc
;
866 impl
->objecter
->read(
867 *oid
, oloc
, std::move(op
->op
), CEPH_NOSNAP
, bl
, flags
,
868 std::move(c
), objver
);
871 void RADOS::execute(const Object
& o
, std::int64_t pool
, WriteOp
&& _op
,
872 std::unique_ptr
<WriteOp::Completion
> c
,
873 std::optional
<std::string_view
> ns
,
874 std::optional
<std::string_view
> key
,
876 auto oid
= reinterpret_cast<const object_t
*>(&o
.impl
);
877 auto op
= reinterpret_cast<OpImpl
*>(&_op
.impl
);
878 auto flags
= op
->op
.flags
;
879 object_locator_t oloc
;
886 ceph::real_time mtime
;
890 mtime
= ceph::real_clock::now();
892 impl
->objecter
->mutate(
893 *oid
, oloc
, std::move(op
->op
), {},
895 std::move(c
), objver
);
898 boost::uuids::uuid
RADOS::get_fsid() const noexcept
{
899 return impl
->monclient
.get_fsid().uuid
;
903 void RADOS::lookup_pool(std::string_view name
,
904 std::unique_ptr
<LookupPoolComp
> c
)
906 // I kind of want to make lookup_pg_pool return
907 // std::optional<int64_t> since it can only return one error code.
908 int64_t ret
= impl
->objecter
->with_osdmap(
909 std::mem_fn(&OSDMap::lookup_pg_pool_name
),
912 impl
->objecter
->wait_for_latest_osdmap(
913 [name
= std::string(name
), c
= std::move(c
),
914 objecter
= impl
->objecter
]
915 (bs::error_code ec
) mutable {
917 objecter
->with_osdmap([&](const OSDMap
&osdmap
) {
918 return osdmap
.lookup_pg_pool_name(name
);
921 ca::dispatch(std::move(c
), osdc_errc::pool_dne
,
924 ca::dispatch(std::move(c
), bs::error_code
{}, ret
);
926 } else if (ret
< 0) {
927 ca::post(std::move(c
), osdc_errc::pool_dne
,
930 ca::post(std::move(c
), bs::error_code
{}, ret
);
935 std::optional
<uint64_t> RADOS::get_pool_alignment(int64_t pool_id
)
937 return impl
->objecter
->with_osdmap(
938 [pool_id
](const OSDMap
&o
) -> std::optional
<uint64_t> {
939 if (!o
.have_pg_pool(pool_id
)) {
940 throw bs::system_error(
941 ENOENT
, bs::system_category(),
942 "Cannot find pool in OSDMap.");
943 } else if (o
.get_pg_pool(pool_id
)->requires_aligned_append()) {
944 return o
.get_pg_pool(pool_id
)->required_alignment();
951 void RADOS::list_pools(std::unique_ptr
<LSPoolsComp
> c
) {
952 impl
->objecter
->with_osdmap(
954 std::vector
<std::pair
<std::int64_t, std::string
>> v
;
955 for (auto p
: o
.get_pools())
956 v
.push_back(std::make_pair(p
.first
, o
.get_pool_name(p
.first
)));
957 ca::dispatch(std::move(c
), std::move(v
));
961 void RADOS::create_pool_snap(std::int64_t pool
,
962 std::string_view snapName
,
963 std::unique_ptr
<SimpleOpComp
> c
)
965 impl
->objecter
->create_pool_snap(
967 Objecter::PoolOp::OpComp::create(
969 [c
= std::move(c
)](bs::error_code e
, const bufferlist
&) mutable {
970 ca::dispatch(std::move(c
), e
);
974 void RADOS::allocate_selfmanaged_snap(int64_t pool
,
975 std::unique_ptr
<SMSnapComp
> c
) {
976 impl
->objecter
->allocate_selfmanaged_snap(
978 ca::Completion
<void(bs::error_code
, snapid_t
)>::create(
980 [c
= std::move(c
)](bs::error_code e
, snapid_t snap
) mutable {
981 ca::dispatch(std::move(c
), e
, snap
);
985 void RADOS::delete_pool_snap(std::int64_t pool
,
986 std::string_view snapName
,
987 std::unique_ptr
<SimpleOpComp
> c
)
989 impl
->objecter
->delete_pool_snap(
991 Objecter::PoolOp::OpComp::create(
993 [c
= std::move(c
)](bs::error_code e
, const bufferlist
&) mutable {
994 ca::dispatch(std::move(c
), e
);
998 void RADOS::delete_selfmanaged_snap(std::int64_t pool
,
1000 std::unique_ptr
<SimpleOpComp
> c
)
1002 impl
->objecter
->delete_selfmanaged_snap(
1004 Objecter::PoolOp::OpComp::create(
1006 [c
= std::move(c
)](bs::error_code e
, const bufferlist
&) mutable {
1007 ca::dispatch(std::move(c
), e
);
1011 void RADOS::create_pool(std::string_view name
,
1012 std::optional
<int> crush_rule
,
1013 std::unique_ptr
<SimpleOpComp
> c
)
1015 impl
->objecter
->create_pool(
1017 Objecter::PoolOp::OpComp::create(
1019 [c
= std::move(c
)](bs::error_code e
, const bufferlist
&) mutable {
1020 ca::dispatch(std::move(c
), e
);
1022 crush_rule
.value_or(-1));
1025 void RADOS::delete_pool(std::string_view name
,
1026 std::unique_ptr
<SimpleOpComp
> c
)
1028 impl
->objecter
->delete_pool(
1030 Objecter::PoolOp::OpComp::create(
1032 [c
= std::move(c
)](bs::error_code e
, const bufferlist
&) mutable {
1033 ca::dispatch(std::move(c
), e
);
1037 void RADOS::delete_pool(std::int64_t pool
,
1038 std::unique_ptr
<SimpleOpComp
> c
)
1040 impl
->objecter
->delete_pool(
1042 Objecter::PoolOp::OpComp::create(
1044 [c
= std::move(c
)](bs::error_code e
, const bufferlist
&) mutable {
1045 ca::dispatch(std::move(c
), e
);
1049 void RADOS::stat_pools(const std::vector
<std::string
>& pools
,
1050 std::unique_ptr
<PoolStatComp
> c
) {
1051 impl
->objecter
->get_pool_stats(
1055 bc::flat_map
<std::string
, pool_stat_t
> rawresult
,
1056 bool per_pool
) mutable {
1057 bc::flat_map
<std::string
, PoolStats
> result
;
1058 for (auto p
= rawresult
.begin(); p
!= rawresult
.end(); ++p
) {
1059 auto& pv
= result
[p
->first
];
1060 auto& pstat
= p
->second
;
1061 store_statfs_t
&statfs
= pstat
.store_stats
;
1062 uint64_t allocated_bytes
= pstat
.get_allocated_data_bytes(per_pool
) +
1063 pstat
.get_allocated_omap_bytes(per_pool
);
1064 // FIXME: raw_used_rate is unknown hence use 1.0 here
1065 // meaning we keep net amount aggregated over all replicas
1066 // Not a big deal so far since this field isn't exposed
1067 uint64_t user_bytes
= pstat
.get_user_data_bytes(1.0, per_pool
) +
1068 pstat
.get_user_omap_bytes(1.0, per_pool
);
1070 object_stat_sum_t
*sum
= &p
->second
.stats
.sum
;
1071 pv
.num_kb
= shift_round_up(allocated_bytes
, 10);
1072 pv
.num_bytes
= allocated_bytes
;
1073 pv
.num_objects
= sum
->num_objects
;
1074 pv
.num_object_clones
= sum
->num_object_clones
;
1075 pv
.num_object_copies
= sum
->num_object_copies
;
1076 pv
.num_objects_missing_on_primary
= sum
->num_objects_missing_on_primary
;
1077 pv
.num_objects_unfound
= sum
->num_objects_unfound
;
1078 pv
.num_objects_degraded
= sum
->num_objects_degraded
;
1079 pv
.num_rd
= sum
->num_rd
;
1080 pv
.num_rd_kb
= sum
->num_rd_kb
;
1081 pv
.num_wr
= sum
->num_wr
;
1082 pv
.num_wr_kb
= sum
->num_wr_kb
;
1083 pv
.num_user_bytes
= user_bytes
;
1084 pv
.compressed_bytes_orig
= statfs
.data_compressed_original
;
1085 pv
.compressed_bytes
= statfs
.data_compressed
;
1086 pv
.compressed_bytes_alloc
= statfs
.data_compressed_allocated
;
1089 ca::dispatch(std::move(c
), ec
, std::move(result
), per_pool
);
1093 void RADOS::stat_fs(std::optional
<std::int64_t> _pool
,
1094 std::unique_ptr
<StatFSComp
> c
) {
1095 std::optional
<int64_t> pool
;
1098 impl
->objecter
->get_fs_stats(
1100 [c
= std::move(c
)](bs::error_code ec
, const struct ceph_statfs s
) mutable {
1101 FSStats fso
{s
.kb
, s
.kb_used
, s
.kb_avail
, s
.num_objects
};
1102 c
->dispatch(std::move(c
), ec
, std::move(fso
));
1108 void RADOS::watch(const Object
& o
, const IOContext
& _ioc
,
1109 std::optional
<std::chrono::seconds
> timeout
, WatchCB
&& cb
,
1110 std::unique_ptr
<WatchComp
> c
) {
1111 auto oid
= reinterpret_cast<const object_t
*>(&o
.impl
);
1112 auto ioc
= reinterpret_cast<const IOContextImpl
*>(&_ioc
.impl
);
1116 auto linger_op
= impl
->objecter
->linger_register(*oid
, ioc
->oloc
,
1117 ioc
->extra_op_flags
);
1118 uint64_t cookie
= linger_op
->get_cookie();
1119 linger_op
->handle
= std::move(cb
);
1120 op
.watch(cookie
, CEPH_OSD_WATCH_OP_WATCH
, timeout
.value_or(0s
).count());
1122 impl
->objecter
->linger_watch(
1123 linger_op
, op
, ioc
->snapc
, ceph::real_clock::now(), bl
,
1124 Objecter::LingerOp::OpComp::create(
1126 [c
= std::move(c
), cookie
](bs::error_code e
, cb::list
) mutable {
1127 ca::dispatch(std::move(c
), e
, cookie
);
1131 void RADOS::watch(const Object
& o
, std::int64_t pool
,
1132 std::optional
<std::chrono::seconds
> timeout
, WatchCB
&& cb
,
1133 std::unique_ptr
<WatchComp
> c
,
1134 std::optional
<std::string_view
> ns
,
1135 std::optional
<std::string_view
> key
) {
1136 auto oid
= reinterpret_cast<const object_t
*>(&o
.impl
);
1137 object_locator_t oloc
;
1146 Objecter::LingerOp
*linger_op
= impl
->objecter
->linger_register(*oid
, oloc
, 0);
1147 uint64_t cookie
= linger_op
->get_cookie();
1148 linger_op
->handle
= std::move(cb
);
1149 op
.watch(cookie
, CEPH_OSD_WATCH_OP_WATCH
, timeout
.value_or(0s
).count());
1151 impl
->objecter
->linger_watch(
1152 linger_op
, op
, {}, ceph::real_clock::now(), bl
,
1153 Objecter::LingerOp::OpComp::create(
1155 [c
= std::move(c
), cookie
](bs::error_code e
, bufferlist
) mutable {
1156 ca::dispatch(std::move(c
), e
, cookie
);
1160 void RADOS::notify_ack(const Object
& o
,
1161 const IOContext
& _ioc
,
1165 std::unique_ptr
<SimpleOpComp
> c
)
1167 auto oid
= reinterpret_cast<const object_t
*>(&o
.impl
);
1168 auto ioc
= reinterpret_cast<const IOContextImpl
*>(&_ioc
.impl
);
1171 op
.notify_ack(notify_id
, cookie
, bl
);
1173 impl
->objecter
->read(*oid
, ioc
->oloc
, std::move(op
), ioc
->snap_seq
,
1174 nullptr, ioc
->extra_op_flags
, std::move(c
));
1177 void RADOS::notify_ack(const Object
& o
,
1182 std::unique_ptr
<SimpleOpComp
> c
,
1183 std::optional
<std::string_view
> ns
,
1184 std::optional
<std::string_view
> key
) {
1185 auto oid
= reinterpret_cast<const object_t
*>(&o
.impl
);
1186 object_locator_t oloc
;
1194 op
.notify_ack(notify_id
, cookie
, bl
);
1195 impl
->objecter
->read(*oid
, oloc
, std::move(op
), CEPH_NOSNAP
, nullptr, 0,
1199 tl::expected
<ceph::timespan
, bs::error_code
> RADOS::watch_check(uint64_t cookie
)
1201 Objecter::LingerOp
*linger_op
= reinterpret_cast<Objecter::LingerOp
*>(cookie
);
1202 return impl
->objecter
->linger_check(linger_op
);
1205 void RADOS::unwatch(uint64_t cookie
, const IOContext
& _ioc
,
1206 std::unique_ptr
<SimpleOpComp
> c
)
1208 auto ioc
= reinterpret_cast<const IOContextImpl
*>(&_ioc
.impl
);
1210 Objecter::LingerOp
*linger_op
= reinterpret_cast<Objecter::LingerOp
*>(cookie
);
1213 op
.watch(cookie
, CEPH_OSD_WATCH_OP_UNWATCH
);
1214 impl
->objecter
->mutate(linger_op
->target
.base_oid
, ioc
->oloc
, std::move(op
),
1215 ioc
->snapc
, ceph::real_clock::now(), ioc
->extra_op_flags
,
1216 Objecter::Op::OpComp::create(
1218 [objecter
= impl
->objecter
,
1219 linger_op
, c
= std::move(c
)]
1220 (bs::error_code ec
) mutable {
1221 objecter
->linger_cancel(linger_op
);
1222 ca::dispatch(std::move(c
), ec
);
1226 void RADOS::unwatch(uint64_t cookie
, std::int64_t pool
,
1227 std::unique_ptr
<SimpleOpComp
> c
,
1228 std::optional
<std::string_view
> ns
,
1229 std::optional
<std::string_view
> key
)
1231 object_locator_t oloc
;
1238 Objecter::LingerOp
*linger_op
= reinterpret_cast<Objecter::LingerOp
*>(cookie
);
1241 op
.watch(cookie
, CEPH_OSD_WATCH_OP_UNWATCH
);
1242 impl
->objecter
->mutate(linger_op
->target
.base_oid
, oloc
, std::move(op
),
1243 {}, ceph::real_clock::now(), 0,
1244 Objecter::Op::OpComp::create(
1246 [objecter
= impl
->objecter
,
1247 linger_op
, c
= std::move(c
)]
1248 (bs::error_code ec
) mutable {
1249 objecter
->linger_cancel(linger_op
);
1250 ca::dispatch(std::move(c
), ec
);
1254 void RADOS::flush_watch(std::unique_ptr
<VoidOpComp
> c
)
1256 impl
->objecter
->linger_callback_flush([c
= std::move(c
)]() mutable {
1257 ca::post(std::move(c
));
1261 struct NotifyHandler
: std::enable_shared_from_this
<NotifyHandler
> {
1262 boost::asio::io_context
& ioc
;
1263 boost::asio::io_context::strand strand
;
1265 Objecter::LingerOp
* op
;
1266 std::unique_ptr
<RADOS::NotifyComp
> c
;
1269 bool finished
= false;
1273 NotifyHandler(boost::asio::io_context
& ioc
,
1275 Objecter::LingerOp
* op
,
1276 std::unique_ptr
<RADOS::NotifyComp
> c
)
1277 : ioc(ioc
), strand(ioc
), objecter(objecter
), op(op
), c(std::move(c
)) {}
1279 // Use bind or a lambda to pass this in.
1280 void handle_ack(bs::error_code ec
,
1284 [this, ec
, p
= shared_from_this()]() mutable {
1290 // Notify finish callback. It can actually own the object's storage.
1292 void operator()(bs::error_code ec
,
1296 [this, ec
, p
= shared_from_this()]() mutable {
1302 // Should be called from strand.
1303 void maybe_cleanup(bs::error_code ec
) {
1306 if ((acked
&& finished
) || res
) {
1307 objecter
->linger_cancel(op
);
1309 ca::dispatch(std::move(c
), res
, std::move(rbl
));
1314 void RADOS::notify(const Object
& o
, const IOContext
& _ioc
, bufferlist
&& bl
,
1315 std::optional
<std::chrono::milliseconds
> timeout
,
1316 std::unique_ptr
<NotifyComp
> c
)
1318 auto oid
= reinterpret_cast<const object_t
*>(&o
.impl
);
1319 auto ioc
= reinterpret_cast<const IOContextImpl
*>(&_ioc
.impl
);
1320 auto linger_op
= impl
->objecter
->linger_register(*oid
, ioc
->oloc
,
1321 ioc
->extra_op_flags
);
1323 auto cb
= std::make_shared
<NotifyHandler
>(impl
->ioctx
, impl
->objecter
,
1324 linger_op
, std::move(c
));
1325 linger_op
->on_notify_finish
=
1326 Objecter::LingerOp::OpComp::create(
1328 [cb
](bs::error_code ec
, ceph::bufferlist bl
) mutable {
1329 (*cb
)(ec
, std::move(bl
));
1334 linger_op
->get_cookie(), 1,
1335 timeout
? timeout
->count() : impl
->cct
->_conf
->client_notify_timeout
,
1338 impl
->objecter
->linger_notify(
1339 linger_op
, rd
, ioc
->snap_seq
, inbl
,
1340 Objecter::LingerOp::OpComp::create(
1342 [cb
](bs::error_code ec
, ceph::bufferlist bl
) mutable {
1343 cb
->handle_ack(ec
, std::move(bl
));
1347 void RADOS::notify(const Object
& o
, std::int64_t pool
, bufferlist
&& bl
,
1348 std::optional
<std::chrono::milliseconds
> timeout
,
1349 std::unique_ptr
<NotifyComp
> c
,
1350 std::optional
<std::string_view
> ns
,
1351 std::optional
<std::string_view
> key
)
1353 auto oid
= reinterpret_cast<const object_t
*>(&o
.impl
);
1354 object_locator_t oloc
;
1360 auto linger_op
= impl
->objecter
->linger_register(*oid
, oloc
, 0);
1362 auto cb
= std::make_shared
<NotifyHandler
>(impl
->ioctx
, impl
->objecter
,
1363 linger_op
, std::move(c
));
1364 linger_op
->on_notify_finish
=
1365 Objecter::LingerOp::OpComp::create(
1367 [cb
](bs::error_code ec
, ceph::bufferlist
&& bl
) mutable {
1368 (*cb
)(ec
, std::move(bl
));
1373 linger_op
->get_cookie(), 1,
1374 timeout
? timeout
->count() : impl
->cct
->_conf
->client_notify_timeout
,
1377 impl
->objecter
->linger_notify(
1378 linger_op
, rd
, CEPH_NOSNAP
, inbl
,
1379 Objecter::LingerOp::OpComp::create(
1381 [cb
](bs::error_code ec
, bufferlist
&& bl
) mutable {
1382 cb
->handle_ack(ec
, std::move(bl
));
1389 static_assert(impl_size
>= sizeof(hobject_t
));
1390 new (&impl
) hobject_t();
1393 Cursor::Cursor(end_magic_t
) {
1394 static_assert(impl_size
>= sizeof(hobject_t
));
1395 new (&impl
) hobject_t(hobject_t::get_max());
1398 Cursor::Cursor(void* p
) {
1399 static_assert(impl_size
>= sizeof(hobject_t
));
1400 new (&impl
) hobject_t(std::move(*reinterpret_cast<hobject_t
*>(p
)));
1403 Cursor
Cursor::begin() {
1408 Cursor
Cursor::end() {
1409 Cursor
e(end_magic_t
{});
1413 Cursor::Cursor(const Cursor
& rhs
) {
1414 static_assert(impl_size
>= sizeof(hobject_t
));
1415 new (&impl
) hobject_t(*reinterpret_cast<const hobject_t
*>(&rhs
.impl
));
1418 Cursor
& Cursor::operator =(const Cursor
& rhs
) {
1419 static_assert(impl_size
>= sizeof(hobject_t
));
1420 reinterpret_cast<hobject_t
*>(&impl
)->~hobject_t();
1421 new (&impl
) hobject_t(*reinterpret_cast<const hobject_t
*>(&rhs
.impl
));
1425 Cursor::Cursor(Cursor
&& rhs
) {
1426 static_assert(impl_size
>= sizeof(hobject_t
));
1427 new (&impl
) hobject_t(std::move(*reinterpret_cast<hobject_t
*>(&rhs
.impl
)));
1430 Cursor
& Cursor::operator =(Cursor
&& rhs
) {
1431 static_assert(impl_size
>= sizeof(hobject_t
));
1432 reinterpret_cast<hobject_t
*>(&impl
)->~hobject_t();
1433 new (&impl
) hobject_t(std::move(*reinterpret_cast<hobject_t
*>(&rhs
.impl
)));
1437 reinterpret_cast<hobject_t
*>(&impl
)->~hobject_t();
1440 bool operator ==(const Cursor
& lhs
, const Cursor
& rhs
) {
1441 return (*reinterpret_cast<const hobject_t
*>(&lhs
.impl
) ==
1442 *reinterpret_cast<const hobject_t
*>(&rhs
.impl
));
1445 bool operator !=(const Cursor
& lhs
, const Cursor
& rhs
) {
1446 return (*reinterpret_cast<const hobject_t
*>(&lhs
.impl
) !=
1447 *reinterpret_cast<const hobject_t
*>(&rhs
.impl
));
1450 bool operator <(const Cursor
& lhs
, const Cursor
& rhs
) {
1451 return (*reinterpret_cast<const hobject_t
*>(&lhs
.impl
) <
1452 *reinterpret_cast<const hobject_t
*>(&rhs
.impl
));
1455 bool operator <=(const Cursor
& lhs
, const Cursor
& rhs
) {
1456 return (*reinterpret_cast<const hobject_t
*>(&lhs
.impl
) <=
1457 *reinterpret_cast<const hobject_t
*>(&rhs
.impl
));
1460 bool operator >=(const Cursor
& lhs
, const Cursor
& rhs
) {
1461 return (*reinterpret_cast<const hobject_t
*>(&lhs
.impl
) >=
1462 *reinterpret_cast<const hobject_t
*>(&rhs
.impl
));
1465 bool operator >(const Cursor
& lhs
, const Cursor
& rhs
) {
1466 return (*reinterpret_cast<const hobject_t
*>(&lhs
.impl
) >
1467 *reinterpret_cast<const hobject_t
*>(&rhs
.impl
));
1470 std::string
Cursor::to_str() const {
1471 using namespace std::literals
;
1472 auto& h
= *reinterpret_cast<const hobject_t
*>(&impl
);
1474 return h
.is_max() ? "MAX"s
: h
.to_str();
1477 std::optional
<Cursor
>
1478 Cursor::from_str(const std::string
& s
) {
1480 auto& h
= *reinterpret_cast<hobject_t
*>(&e
.impl
);
1482 return std::nullopt
;
1487 void RADOS::enumerate_objects(const IOContext
& _ioc
,
1488 const Cursor
& begin
,
1490 const std::uint32_t max
,
1491 const bufferlist
& filter
,
1492 std::unique_ptr
<EnumerateComp
> c
) {
1493 auto ioc
= reinterpret_cast<const IOContextImpl
*>(&_ioc
.impl
);
1495 impl
->objecter
->enumerate_objects
<Entry
>(
1498 *reinterpret_cast<const hobject_t
*>(&begin
.impl
),
1499 *reinterpret_cast<const hobject_t
*>(&end
.impl
),
1503 (bs::error_code ec
, std::vector
<Entry
>&& v
,
1504 hobject_t
&& n
) mutable {
1505 ca::dispatch(std::move(c
), ec
, std::move(v
),
1506 Cursor(static_cast<void*>(&n
)));
1510 void RADOS::enumerate_objects(std::int64_t pool
,
1511 const Cursor
& begin
,
1513 const std::uint32_t max
,
1514 const bufferlist
& filter
,
1515 std::unique_ptr
<EnumerateComp
> c
,
1516 std::optional
<std::string_view
> ns
,
1517 std::optional
<std::string_view
> key
) {
1518 impl
->objecter
->enumerate_objects
<Entry
>(
1520 ns
? *ns
: std::string_view
{},
1521 *reinterpret_cast<const hobject_t
*>(&begin
.impl
),
1522 *reinterpret_cast<const hobject_t
*>(&end
.impl
),
1526 (bs::error_code ec
, std::vector
<Entry
>&& v
,
1527 hobject_t
&& n
) mutable {
1528 ca::dispatch(std::move(c
), ec
, std::move(v
),
1529 Cursor(static_cast<void*>(&n
)));
1534 void RADOS::osd_command(int osd
, std::vector
<std::string
>&& cmd
,
1535 ceph::bufferlist
&& in
, std::unique_ptr
<CommandComp
> c
) {
1536 impl
->objecter
->osd_command(osd
, std::move(cmd
), std::move(in
), nullptr,
1540 ceph::bufferlist
&& b
) mutable {
1541 ca::dispatch(std::move(c
), ec
,
1546 void RADOS::pg_command(PG pg
, std::vector
<std::string
>&& cmd
,
1547 ceph::bufferlist
&& in
, std::unique_ptr
<CommandComp
> c
) {
1548 impl
->objecter
->pg_command(pg_t
{pg
.seed
, pg
.pool
}, std::move(cmd
), std::move(in
), nullptr,
1552 ceph::bufferlist
&& b
) mutable {
1553 ca::dispatch(std::move(c
), ec
,
1559 void RADOS::enable_application(std::string_view pool
, std::string_view app_name
,
1560 bool force
, std::unique_ptr
<SimpleOpComp
> c
) {
1561 // pre-Luminous clusters will return -EINVAL and application won't be
1562 // preserved until Luminous is configured as minimum version.
1563 if (!impl
->get_required_monitor_features().contains_all(
1564 ceph::features::mon::FEATURE_LUMINOUS
)) {
1565 ca::post(std::move(c
), ceph::to_error_code(-EOPNOTSUPP
));
1567 impl
->monclient
.start_mon_command(
1568 { fmt::format("{{ \"prefix\": \"osd pool application enable\","
1569 "\"pool\": \"{}\", \"app\": \"{}\"{}}}",
1571 force
? " ,\"yes_i_really_mean_it\": true" : "")},
1572 {}, [c
= std::move(c
)](bs::error_code e
,
1573 std::string
, cb::list
) mutable {
1574 ca::post(std::move(c
), e
);
1579 void RADOS::blocklist_add(std::string_view client_address
,
1580 std::optional
<std::chrono::seconds
> expire
,
1581 std::unique_ptr
<SimpleOpComp
> c
) {
1582 auto expire_arg
= (expire
?
1583 fmt::format(", \"expire\": \"{}.0\"", expire
->count()) : std::string
{});
1584 impl
->monclient
.start_mon_command(
1586 "\"prefix\": \"osd blocklist\", "
1587 "\"blocklistop\": \"add\", "
1588 "\"addr\": \"{}\"{}}}",
1589 client_address
, expire_arg
) },
1591 [this, client_address
= std::string(client_address
), expire_arg
,
1592 c
= std::move(c
)](bs::error_code ec
, std::string
, cb::list
) mutable {
1593 if (ec
!= bs::errc::invalid_argument
) {
1594 ca::post(std::move(c
), ec
);
1598 // retry using the legacy command
1599 impl
->monclient
.start_mon_command(
1601 "\"prefix\": \"osd blacklist\", "
1602 "\"blacklistop\": \"add\", "
1603 "\"addr\": \"{}\"{}}}",
1604 client_address
, expire_arg
) },
1606 [c
= std::move(c
)](bs::error_code ec
, std::string
, cb::list
) mutable {
1607 ca::post(std::move(c
), ec
);
1612 void RADOS::wait_for_latest_osd_map(std::unique_ptr
<SimpleOpComp
> c
) {
1613 impl
->objecter
->wait_for_latest_osdmap(std::move(c
));
1616 void RADOS::mon_command(std::vector
<std::string
> command
,
1618 std::string
* outs
, cb::list
* outbl
,
1619 std::unique_ptr
<SimpleOpComp
> c
) {
1621 impl
->monclient
.start_mon_command(
1623 [c
= std::move(c
), outs
, outbl
](bs::error_code e
,
1624 std::string s
, cb::list bl
) mutable {
1626 *outs
= std::move(s
);
1628 *outbl
= std::move(bl
);
1629 ca::post(std::move(c
), e
);
1633 uint64_t RADOS::instance_id() const {
1634 return impl
->get_instance_id();
1637 #pragma GCC diagnostic push
1638 #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
1639 #pragma clang diagnostic push
1640 #pragma clang diagnostic ignored "-Wnon-virtual-dtor"
1641 class category
: public ceph::converting_category
{
1644 const char* name() const noexcept override
;
1645 const char* message(int ev
, char*, std::size_t) const noexcept override
;
1646 std::string
message(int ev
) const override
;
1647 bs::error_condition
default_error_condition(int ev
) const noexcept
1649 bool equivalent(int ev
, const bs::error_condition
& c
) const
1651 using ceph::converting_category::equivalent
;
1652 int from_code(int ev
) const noexcept override
;
1654 #pragma GCC diagnostic pop
1655 #pragma clang diagnostic pop
1657 const char* category::name() const noexcept
{
1661 const char* category::message(int ev
, char*,
1662 std::size_t) const noexcept
{
1666 switch (static_cast<errc
>(ev
)) {
1667 case errc::pool_dne
:
1668 return "Pool does not exist";
1670 case errc::invalid_snapcontext
:
1671 return "Invalid snapcontext";
1674 return "Unknown error";
1677 std::string
category::message(int ev
) const {
1678 return message(ev
, nullptr, 0);
1681 bs::error_condition
category::default_error_condition(int ev
) const noexcept
{
1682 switch (static_cast<errc
>(ev
)) {
1683 case errc::pool_dne
:
1684 return ceph::errc::does_not_exist
;
1685 case errc::invalid_snapcontext
:
1686 return bs::errc::invalid_argument
;
1689 return { ev
, *this };
1692 bool category::equivalent(int ev
, const bs::error_condition
& c
) const noexcept
{
1693 if (static_cast<errc
>(ev
) == errc::pool_dne
) {
1694 if (c
== bs::errc::no_such_file_or_directory
) {
1699 return default_error_condition(ev
) == c
;
1702 int category::from_code(int ev
) const noexcept
{
1703 switch (static_cast<errc
>(ev
)) {
1704 case errc::pool_dne
:
1706 case errc::invalid_snapcontext
:
1712 const bs::error_category
& error_category() noexcept
{
1713 static const class category c
;
1717 CephContext
* RADOS::cct() {
1718 return impl
->cct
.get();
1723 size_t hash
<neorados::Object
>::operator ()(
1724 const neorados::Object
& r
) const {
1725 static constexpr const hash
<object_t
> H
;
1726 return H(*reinterpret_cast<const object_t
*>(&r
.impl
));
1729 size_t hash
<neorados::IOContext
>::operator ()(
1730 const neorados::IOContext
& r
) const {
1731 static constexpr const hash
<int64_t> H
;
1732 static constexpr const hash
<std::string
> G
;
1733 const auto l
= reinterpret_cast<const neorados::IOContextImpl
*>(&r
.impl
);
1734 return H(l
->oloc
.pool
) ^ (G(l
->oloc
.nspace
) << 1) ^ (G(l
->oloc
.key
) << 2);