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 using namespace std::literals
;
42 namespace bc
= boost::container
;
43 namespace bs
= boost::system
;
44 namespace ca
= ceph::async
;
45 namespace cb
= ceph::buffer
;
51 static_assert(impl_size
>= sizeof(object_t
));
52 new (&impl
) object_t();
55 Object::Object(const char* s
) {
56 static_assert(impl_size
>= sizeof(object_t
));
57 new (&impl
) object_t(s
);
60 Object::Object(std::string_view s
) {
61 static_assert(impl_size
>= sizeof(object_t
));
62 new (&impl
) object_t(s
);
65 Object::Object(std::string
&& s
) {
66 static_assert(impl_size
>= sizeof(object_t
));
67 new (&impl
) object_t(std::move(s
));
70 Object::Object(const std::string
& s
) {
71 static_assert(impl_size
>= sizeof(object_t
));
72 new (&impl
) object_t(s
);
76 reinterpret_cast<object_t
*>(&impl
)->~object_t();
79 Object::Object(const Object
& o
) {
80 static_assert(impl_size
>= sizeof(object_t
));
81 new (&impl
) object_t(*reinterpret_cast<const object_t
*>(&o
.impl
));
83 Object
& Object::operator =(const Object
& o
) {
84 *reinterpret_cast<object_t
*>(&impl
) =
85 *reinterpret_cast<const object_t
*>(&o
.impl
);
88 Object::Object(Object
&& o
) {
89 static_assert(impl_size
>= sizeof(object_t
));
90 new (&impl
) object_t(std::move(*reinterpret_cast<object_t
*>(&o
.impl
)));
92 Object
& Object::operator =(Object
&& o
) {
93 *reinterpret_cast<object_t
*>(&impl
) =
94 std::move(*reinterpret_cast<object_t
*>(&o
.impl
));
98 Object::operator std::string_view() const {
99 return std::string_view(reinterpret_cast<const object_t
*>(&impl
)->name
);
102 bool operator <(const Object
& lhs
, const Object
& rhs
) {
103 return (*reinterpret_cast<const object_t
*>(&lhs
.impl
) <
104 *reinterpret_cast<const object_t
*>(&rhs
.impl
));
106 bool operator <=(const Object
& lhs
, const Object
& rhs
) {
107 return (*reinterpret_cast<const object_t
*>(&lhs
.impl
) <=
108 *reinterpret_cast<const object_t
*>(&rhs
.impl
));
110 bool operator >=(const Object
& lhs
, const Object
& rhs
) {
111 return (*reinterpret_cast<const object_t
*>(&lhs
.impl
) >=
112 *reinterpret_cast<const object_t
*>(&rhs
.impl
));
114 bool operator >(const Object
& lhs
, const Object
& rhs
) {
115 return (*reinterpret_cast<const object_t
*>(&lhs
.impl
) >
116 *reinterpret_cast<const object_t
*>(&rhs
.impl
));
119 bool operator ==(const Object
& lhs
, const Object
& rhs
) {
120 return (*reinterpret_cast<const object_t
*>(&lhs
.impl
) ==
121 *reinterpret_cast<const object_t
*>(&rhs
.impl
));
123 bool operator !=(const Object
& lhs
, const Object
& rhs
) {
124 return (*reinterpret_cast<const object_t
*>(&lhs
.impl
) !=
125 *reinterpret_cast<const object_t
*>(&rhs
.impl
));
128 std::ostream
& operator <<(std::ostream
& m
, const Object
& o
) {
129 return (m
<< *reinterpret_cast<const object_t
*>(&o
.impl
));
134 struct IOContextImpl
{
135 object_locator_t oloc
;
136 snapid_t snap_seq
= CEPH_NOSNAP
;
138 int extra_op_flags
= 0;
141 IOContext::IOContext() {
142 static_assert(impl_size
>= sizeof(IOContextImpl
));
143 new (&impl
) IOContextImpl();
146 IOContext::IOContext(std::int64_t _pool
) : IOContext() {
150 IOContext::IOContext(std::int64_t _pool
, std::string_view _ns
)
156 IOContext::IOContext(std::int64_t _pool
, std::string
&& _ns
)
162 IOContext::~IOContext() {
163 reinterpret_cast<IOContextImpl
*>(&impl
)->~IOContextImpl();
166 IOContext::IOContext(const IOContext
& rhs
) {
167 static_assert(impl_size
>= sizeof(IOContextImpl
));
168 new (&impl
) IOContextImpl(*reinterpret_cast<const IOContextImpl
*>(&rhs
.impl
));
171 IOContext
& IOContext::operator =(const IOContext
& rhs
) {
172 *reinterpret_cast<IOContextImpl
*>(&impl
) =
173 *reinterpret_cast<const IOContextImpl
*>(&rhs
.impl
);
177 IOContext::IOContext(IOContext
&& rhs
) {
178 static_assert(impl_size
>= sizeof(IOContextImpl
));
179 new (&impl
) IOContextImpl(
180 std::move(*reinterpret_cast<IOContextImpl
*>(&rhs
.impl
)));
183 IOContext
& IOContext::operator =(IOContext
&& rhs
) {
184 *reinterpret_cast<IOContextImpl
*>(&impl
) =
185 std::move(*reinterpret_cast<IOContextImpl
*>(&rhs
.impl
));
189 std::int64_t IOContext::pool() const {
190 return reinterpret_cast<const IOContextImpl
*>(&impl
)->oloc
.pool
;
193 void IOContext::pool(std::int64_t _pool
) {
194 reinterpret_cast<IOContextImpl
*>(&impl
)->oloc
.pool
= _pool
;
197 std::string_view
IOContext::ns() const {
198 return reinterpret_cast<const IOContextImpl
*>(&impl
)->oloc
.nspace
;
201 void IOContext::ns(std::string_view _ns
) {
202 reinterpret_cast<IOContextImpl
*>(&impl
)->oloc
.nspace
= _ns
;
205 void IOContext::ns(std::string
&& _ns
) {
206 reinterpret_cast<IOContextImpl
*>(&impl
)->oloc
.nspace
= std::move(_ns
);
209 std::optional
<std::string_view
> IOContext::key() const {
210 auto& oloc
= reinterpret_cast<const IOContextImpl
*>(&impl
)->oloc
;
211 if (oloc
.key
.empty())
214 return std::string_view(oloc
.key
);
217 void IOContext::key(std::string_view _key
) {
218 auto& oloc
= reinterpret_cast<IOContextImpl
*>(&impl
)->oloc
;
223 void IOContext::key(std::string
&&_key
) {
224 auto& oloc
= reinterpret_cast<IOContextImpl
*>(&impl
)->oloc
;
226 oloc
.key
= std::move(_key
);
229 void IOContext::clear_key() {
230 auto& oloc
= reinterpret_cast<IOContextImpl
*>(&impl
)->oloc
;
235 std::optional
<std::int64_t> IOContext::hash() const {
236 auto& oloc
= reinterpret_cast<const IOContextImpl
*>(&impl
)->oloc
;
243 void IOContext::hash(std::int64_t _hash
) {
244 auto& oloc
= reinterpret_cast<IOContextImpl
*>(&impl
)->oloc
;
249 void IOContext::clear_hash() {
250 auto& oloc
= reinterpret_cast<IOContextImpl
*>(&impl
)->oloc
;
256 std::optional
<std::uint64_t> IOContext::read_snap() const {
257 auto& snap_seq
= reinterpret_cast<const IOContextImpl
*>(&impl
)->snap_seq
;
258 if (snap_seq
== CEPH_NOSNAP
)
263 void IOContext::read_snap(std::optional
<std::uint64_t> _snapid
) {
264 auto& snap_seq
= reinterpret_cast<IOContextImpl
*>(&impl
)->snap_seq
;
265 snap_seq
= _snapid
.value_or(CEPH_NOSNAP
);
269 std::pair
<std::uint64_t,
270 std::vector
<std::uint64_t>>> IOContext::write_snap_context() const {
271 auto& snapc
= reinterpret_cast<const IOContextImpl
*>(&impl
)->snapc
;
275 std::vector
<uint64_t> v(snapc
.snaps
.begin(), snapc
.snaps
.end());
276 return std::make_optional(std::make_pair(uint64_t(snapc
.seq
), v
));
280 void IOContext::write_snap_context(
281 std::optional
<std::pair
<std::uint64_t, std::vector
<std::uint64_t>>> _snapc
) {
282 auto& snapc
= reinterpret_cast<IOContextImpl
*>(&impl
)->snapc
;
286 SnapContext
n(_snapc
->first
, { _snapc
->second
.begin(), _snapc
->second
.end()});
288 throw bs::system_error(EINVAL
,
289 bs::system_category(),
290 "Invalid snap context.");
298 bool IOContext::full_try() const {
299 const auto ioc
= reinterpret_cast<const IOContextImpl
*>(&impl
);
300 return (ioc
->extra_op_flags
& CEPH_OSD_FLAG_FULL_TRY
) != 0;
303 void IOContext::full_try(bool _full_try
) {
304 auto ioc
= reinterpret_cast<IOContextImpl
*>(&impl
);
306 ioc
->extra_op_flags
|= CEPH_OSD_FLAG_FULL_TRY
;
308 ioc
->extra_op_flags
&= ~CEPH_OSD_FLAG_FULL_TRY
;
312 bool operator <(const IOContext
& lhs
, const IOContext
& rhs
) {
313 const auto l
= reinterpret_cast<const IOContextImpl
*>(&lhs
.impl
);
314 const auto r
= reinterpret_cast<const IOContextImpl
*>(&rhs
.impl
);
316 return (std::tie(l
->oloc
.pool
, l
->oloc
.nspace
, l
->oloc
.key
) <
317 std::tie(r
->oloc
.pool
, r
->oloc
.nspace
, r
->oloc
.key
));
320 bool operator <=(const IOContext
& lhs
, const IOContext
& rhs
) {
321 const auto l
= reinterpret_cast<const IOContextImpl
*>(&lhs
.impl
);
322 const auto r
= reinterpret_cast<const IOContextImpl
*>(&rhs
.impl
);
324 return (std::tie(l
->oloc
.pool
, l
->oloc
.nspace
, l
->oloc
.key
) <=
325 std::tie(r
->oloc
.pool
, r
->oloc
.nspace
, r
->oloc
.key
));
328 bool operator >=(const IOContext
& lhs
, const IOContext
& rhs
) {
329 const auto l
= reinterpret_cast<const IOContextImpl
*>(&lhs
.impl
);
330 const auto r
= reinterpret_cast<const IOContextImpl
*>(&rhs
.impl
);
332 return (std::tie(l
->oloc
.pool
, l
->oloc
.nspace
, l
->oloc
.key
) >=
333 std::tie(r
->oloc
.pool
, r
->oloc
.nspace
, r
->oloc
.key
));
336 bool operator >(const IOContext
& lhs
, const IOContext
& rhs
) {
337 const auto l
= reinterpret_cast<const IOContextImpl
*>(&lhs
.impl
);
338 const auto r
= reinterpret_cast<const IOContextImpl
*>(&rhs
.impl
);
340 return (std::tie(l
->oloc
.pool
, l
->oloc
.nspace
, l
->oloc
.key
) >
341 std::tie(r
->oloc
.pool
, r
->oloc
.nspace
, r
->oloc
.key
));
344 bool operator ==(const IOContext
& lhs
, const IOContext
& rhs
) {
345 const auto l
= reinterpret_cast<const IOContextImpl
*>(&lhs
.impl
);
346 const auto r
= reinterpret_cast<const IOContextImpl
*>(&rhs
.impl
);
348 return (std::tie(l
->oloc
.pool
, l
->oloc
.nspace
, l
->oloc
.key
) ==
349 std::tie(r
->oloc
.pool
, r
->oloc
.nspace
, r
->oloc
.key
));
352 bool operator !=(const IOContext
& lhs
, const IOContext
& rhs
) {
353 const auto l
= reinterpret_cast<const IOContextImpl
*>(&lhs
.impl
);
354 const auto r
= reinterpret_cast<const IOContextImpl
*>(&rhs
.impl
);
356 return (std::tie(l
->oloc
.pool
, l
->oloc
.nspace
, l
->oloc
.key
) !=
357 std::tie(r
->oloc
.pool
, r
->oloc
.nspace
, r
->oloc
.key
));
360 std::ostream
& operator <<(std::ostream
& m
, const IOContext
& o
) {
361 const auto l
= reinterpret_cast<const IOContextImpl
*>(&o
.impl
);
362 return (m
<< l
->oloc
.pool
<< ":" << l
->oloc
.nspace
<< ":" << l
->oloc
.key
);
370 std::optional
<ceph::real_time
> mtime
;
374 OpImpl(const OpImpl
& rhs
) = delete;
375 OpImpl(OpImpl
&& rhs
) = default;
377 OpImpl
& operator =(const OpImpl
& rhs
) = delete;
378 OpImpl
& operator =(OpImpl
&& rhs
) = default;
382 static_assert(Op::impl_size
>= sizeof(OpImpl
));
387 new (&impl
) OpImpl(std::move(*reinterpret_cast<OpImpl
*>(&rhs
.impl
)));
389 Op
& Op::operator =(Op
&& rhs
) {
390 reinterpret_cast<OpImpl
*>(&impl
)->~OpImpl();
391 new (&impl
) OpImpl(std::move(*reinterpret_cast<OpImpl
*>(&rhs
.impl
)));
395 reinterpret_cast<OpImpl
*>(&impl
)->~OpImpl();
398 void Op::set_excl() {
399 reinterpret_cast<OpImpl
*>(&impl
)->op
.set_last_op_flags(CEPH_OSD_OP_FLAG_EXCL
);
401 void Op::set_failok() {
402 reinterpret_cast<OpImpl
*>(&impl
)->op
.set_last_op_flags(
403 CEPH_OSD_OP_FLAG_FAILOK
);
405 void Op::set_fadvise_random() {
406 reinterpret_cast<OpImpl
*>(&impl
)->op
.set_last_op_flags(
407 CEPH_OSD_OP_FLAG_FADVISE_RANDOM
);
409 void Op::set_fadvise_sequential() {
410 reinterpret_cast<OpImpl
*>(&impl
)->op
.set_last_op_flags(
411 CEPH_OSD_OP_FLAG_FADVISE_SEQUENTIAL
);
413 void Op::set_fadvise_willneed() {
414 reinterpret_cast<OpImpl
*>(&impl
)->op
.set_last_op_flags(
415 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED
);
417 void Op::set_fadvise_dontneed() {
418 reinterpret_cast<OpImpl
*>(&impl
)->op
.set_last_op_flags(
419 CEPH_OSD_OP_FLAG_FADVISE_DONTNEED
);
421 void Op::set_fadvise_nocache() {
422 reinterpret_cast<OpImpl
*>(&impl
)->op
.set_last_op_flags(
423 CEPH_OSD_OP_FLAG_FADVISE_NOCACHE
);
426 void Op::cmpext(uint64_t off
, bufferlist
&& cmp_bl
, std::size_t* s
) {
427 reinterpret_cast<OpImpl
*>(&impl
)->op
.cmpext(off
, std::move(cmp_bl
), nullptr,
430 void Op::cmpxattr(std::string_view name
, cmpxattr_op op
, const bufferlist
& val
) {
431 reinterpret_cast<OpImpl
*>(&impl
)->
432 op
.cmpxattr(name
, std::uint8_t(op
), CEPH_OSD_CMPXATTR_MODE_STRING
, val
);
434 void Op::cmpxattr(std::string_view name
, cmpxattr_op op
, std::uint64_t val
) {
437 reinterpret_cast<OpImpl
*>(&impl
)->
438 op
.cmpxattr(name
, std::uint8_t(op
), CEPH_OSD_CMPXATTR_MODE_U64
, bl
);
441 void Op::assert_version(uint64_t ver
) {
442 reinterpret_cast<OpImpl
*>(&impl
)->op
.assert_version(ver
);
444 void Op::assert_exists() {
445 reinterpret_cast<OpImpl
*>(&impl
)->op
.stat(
447 static_cast<ceph::real_time
*>(nullptr),
448 static_cast<bs::error_code
*>(nullptr));
450 void Op::cmp_omap(const bc::flat_map
<
451 std::string
, std::pair
<cb::list
,
453 reinterpret_cast<OpImpl
*>(&impl
)->op
.omap_cmp(assertions
, nullptr);
456 void Op::exec(std::string_view cls
, std::string_view method
,
457 const bufferlist
& inbl
,
459 bs::error_code
* ec
) {
460 reinterpret_cast<OpImpl
*>(&impl
)->op
.call(cls
, method
, inbl
, ec
, out
);
463 void Op::exec(std::string_view cls
, std::string_view method
,
464 const bufferlist
& inbl
,
465 fu2::unique_function
<void(bs::error_code
,
466 const cb::list
&) &&> f
) {
467 reinterpret_cast<OpImpl
*>(&impl
)->op
.call(cls
, method
, inbl
, std::move(f
));
470 void Op::exec(std::string_view cls
, std::string_view method
,
471 const bufferlist
& inbl
,
472 fu2::unique_function
<void(bs::error_code
, int,
473 const cb::list
&) &&> f
) {
474 reinterpret_cast<OpImpl
*>(&impl
)->op
.call(cls
, method
, inbl
, std::move(f
));
477 void Op::exec(std::string_view cls
, std::string_view method
,
478 const bufferlist
& inbl
, bs::error_code
* ec
) {
479 reinterpret_cast<OpImpl
*>(&impl
)->op
.call(cls
, method
, inbl
, ec
);
482 void Op::balance_reads() {
483 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_BALANCE_READS
;
485 void Op::localize_reads() {
486 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_LOCALIZE_READS
;
488 void Op::order_reads_writes() {
489 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_RWORDERED
;
491 void Op::ignore_cache() {
492 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_IGNORE_CACHE
;
494 void Op::skiprwlocks() {
495 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_SKIPRWLOCKS
;
497 void Op::ignore_overlay() {
498 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_IGNORE_OVERLAY
;
500 void Op::full_try() {
501 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_FULL_TRY
;
503 void Op::full_force() {
504 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_FULL_FORCE
;
506 void Op::ignore_redirect() {
507 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_IGNORE_REDIRECT
;
509 void Op::ordersnap() {
510 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_ORDERSNAP
;
512 void Op::returnvec() {
513 reinterpret_cast<OpImpl
*>(&impl
)->op
.flags
|= CEPH_OSD_FLAG_RETURNVEC
;
516 std::size_t Op::size() const {
517 return reinterpret_cast<const OpImpl
*>(&impl
)->op
.size();
520 std::ostream
& operator <<(std::ostream
& m
, const Op
& o
) {
521 return m
<< reinterpret_cast<const OpImpl
*>(&o
.impl
)->op
;
529 void ReadOp::read(size_t off
, uint64_t len
, cb::list
* out
,
530 bs::error_code
* ec
) {
531 reinterpret_cast<OpImpl
*>(&impl
)->op
.read(off
, len
, ec
, out
);
534 void ReadOp::get_xattr(std::string_view name
, cb::list
* out
,
535 bs::error_code
* ec
) {
536 reinterpret_cast<OpImpl
*>(&impl
)->op
.getxattr(name
, ec
, out
);
539 void ReadOp::get_omap_header(cb::list
* out
,
540 bs::error_code
* ec
) {
541 reinterpret_cast<OpImpl
*>(&impl
)->op
.omap_get_header(ec
, out
);
544 void ReadOp::sparse_read(uint64_t off
, uint64_t len
, cb::list
* out
,
545 std::vector
<std::pair
<std::uint64_t,
546 std::uint64_t>>* extents
,
547 bs::error_code
* ec
) {
548 reinterpret_cast<OpImpl
*>(&impl
)->op
.sparse_read(off
, len
, ec
, extents
, out
);
551 void ReadOp::stat(std::uint64_t* size
, ceph::real_time
* mtime
,
552 bs::error_code
* ec
) {
553 reinterpret_cast<OpImpl
*>(&impl
)->op
.stat(size
, mtime
, ec
);
556 void ReadOp::get_omap_keys(std::optional
<std::string_view
> start_after
,
557 std::uint64_t max_return
,
558 bc::flat_set
<std::string
>* keys
,
560 bs::error_code
* ec
) {
561 reinterpret_cast<OpImpl
*>(&impl
)->op
.omap_get_keys(start_after
, max_return
,
565 void ReadOp::get_xattrs(bc::flat_map
<std::string
,
567 bs::error_code
* ec
) {
568 reinterpret_cast<OpImpl
*>(&impl
)->op
.getxattrs(ec
, kv
);
571 void ReadOp::get_omap_vals(std::optional
<std::string_view
> start_after
,
572 std::optional
<std::string_view
> filter_prefix
,
574 bc::flat_map
<std::string
,
577 bs::error_code
* ec
) {
578 reinterpret_cast<OpImpl
*>(&impl
)->op
.omap_get_vals(start_after
, filter_prefix
,
579 max_return
, ec
, kv
, done
);
582 void ReadOp::get_omap_vals_by_keys(
583 const bc::flat_set
<std::string
>& keys
,
584 bc::flat_map
<std::string
, cb::list
>* kv
,
585 bs::error_code
* ec
) {
586 reinterpret_cast<OpImpl
*>(&impl
)->op
.omap_get_vals_by_keys(keys
, ec
, kv
);
589 void ReadOp::list_watchers(std::vector
<ObjWatcher
>* watchers
,
590 bs::error_code
* ec
) {
591 reinterpret_cast<OpImpl
*>(&impl
)-> op
.list_watchers(watchers
, ec
);
594 void ReadOp::list_snaps(SnapSet
* snaps
,
595 bs::error_code
* ec
) {
596 reinterpret_cast<OpImpl
*>(&impl
)->op
.list_snaps(snaps
, nullptr, ec
);
601 void WriteOp::set_mtime(ceph::real_time t
) {
602 auto o
= reinterpret_cast<OpImpl
*>(&impl
);
606 void WriteOp::create(bool exclusive
) {
607 reinterpret_cast<OpImpl
*>(&impl
)->op
.create(exclusive
);
610 void WriteOp::write(uint64_t off
, bufferlist
&& bl
) {
611 reinterpret_cast<OpImpl
*>(&impl
)->op
.write(off
, bl
);
614 void WriteOp::write_full(bufferlist
&& bl
) {
615 reinterpret_cast<OpImpl
*>(&impl
)->op
.write_full(bl
);
618 void WriteOp::writesame(uint64_t off
, uint64_t write_len
, bufferlist
&& bl
) {
619 reinterpret_cast<OpImpl
*>(&impl
)->op
.writesame(off
, write_len
, bl
);
622 void WriteOp::append(bufferlist
&& bl
) {
623 reinterpret_cast<OpImpl
*>(&impl
)->op
.append(bl
);
626 void WriteOp::remove() {
627 reinterpret_cast<OpImpl
*>(&impl
)->op
.remove();
630 void WriteOp::truncate(uint64_t off
) {
631 reinterpret_cast<OpImpl
*>(&impl
)->op
.truncate(off
);
634 void WriteOp::zero(uint64_t off
, uint64_t len
) {
635 reinterpret_cast<OpImpl
*>(&impl
)->op
.zero(off
, len
);
638 void WriteOp::rmxattr(std::string_view name
) {
639 reinterpret_cast<OpImpl
*>(&impl
)->op
.rmxattr(name
);
642 void WriteOp::setxattr(std::string_view name
,
644 reinterpret_cast<OpImpl
*>(&impl
)->op
.setxattr(name
, bl
);
647 void WriteOp::rollback(uint64_t snapid
) {
648 reinterpret_cast<OpImpl
*>(&impl
)->op
.rollback(snapid
);
651 void WriteOp::set_omap(
652 const bc::flat_map
<std::string
, cb::list
>& map
) {
653 reinterpret_cast<OpImpl
*>(&impl
)->op
.omap_set(map
);
656 void WriteOp::set_omap_header(bufferlist
&& bl
) {
657 reinterpret_cast<OpImpl
*>(&impl
)->op
.omap_set_header(bl
);
660 void WriteOp::clear_omap() {
661 reinterpret_cast<OpImpl
*>(&impl
)->op
.omap_clear();
664 void WriteOp::rm_omap_keys(
665 const bc::flat_set
<std::string
>& to_rm
) {
666 reinterpret_cast<OpImpl
*>(&impl
)->op
.omap_rm_keys(to_rm
);
669 void WriteOp::set_alloc_hint(uint64_t expected_object_size
,
670 uint64_t expected_write_size
,
671 alloc_hint::alloc_hint_t flags
) {
672 using namespace alloc_hint
;
673 static_assert(sequential_write
==
674 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_WRITE
));
675 static_assert(random_write
==
676 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_WRITE
));
677 static_assert(sequential_read
==
678 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ
));
679 static_assert(random_read
==
680 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_READ
));
681 static_assert(append_only
==
682 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_APPEND_ONLY
));
683 static_assert(immutable
==
684 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_IMMUTABLE
));
685 static_assert(shortlived
==
686 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_SHORTLIVED
));
687 static_assert(longlived
==
688 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_LONGLIVED
));
689 static_assert(compressible
==
690 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_COMPRESSIBLE
));
691 static_assert(incompressible
==
692 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_INCOMPRESSIBLE
));
694 reinterpret_cast<OpImpl
*>(&impl
)->op
.set_alloc_hint(expected_object_size
,
701 RADOS::Builder
& RADOS::Builder::add_conf_file(std::string_view f
) {
703 *conf_files
+= (", " + std::string(f
));
705 conf_files
= std::string(f
);
709 void RADOS::Builder::build(boost::asio::io_context
& ioctx
,
710 std::unique_ptr
<BuildComp
> c
) {
711 constexpr auto env
= CODE_ENVIRONMENT_LIBRARY
;
712 CephInitParameters
ci(env
);
714 ci
.name
.set(CEPH_ENTITY_TYPE_CLIENT
, *name
);
716 ci
.name
.set(CEPH_ENTITY_TYPE_CLIENT
, "admin");
719 flags
|= CINIT_FLAG_NO_DEFAULT_CONFIG_FILE
;
721 flags
|= CINIT_FLAG_NO_MON_CONFIG
;
723 CephContext
*cct
= common_preinit(ci
, env
, flags
);
725 cct
->_conf
->cluster
= *cluster
;
728 cct
->_conf
->no_mon_config
= true;
730 // TODO: Come up with proper error codes here. Maybe augment the
731 // functions with a default bs::error_code* parameter to
734 std::ostringstream ss
;
735 auto r
= cct
->_conf
.parse_config_files(conf_files
? conf_files
->data() : nullptr,
738 c
->post(std::move(c
), ceph::to_error_code(r
), RADOS
{nullptr});
741 cct
->_conf
.parse_env(cct
->get_module_type());
743 for (const auto& [n
, v
] : configs
) {
744 std::stringstream ss
;
745 auto r
= cct
->_conf
.set_val(n
, v
, &ss
);
747 c
->post(std::move(c
), ceph::to_error_code(-EINVAL
), RADOS
{nullptr});
751 MonClient
mc_bootstrap(cct
, ioctx
);
752 // TODO This function should return an error code.
753 auto err
= mc_bootstrap
.get_monmap_and_config();
755 c
->post(std::move(c
), ceph::to_error_code(err
), RADOS
{nullptr});
757 if (!cct
->_log
->is_started()) {
760 common_init_finish(cct
);
762 RADOS::make_with_cct(cct
, ioctx
, std::move(c
));
765 void RADOS::make_with_cct(CephContext
* cct
,
766 boost::asio::io_context
& ioctx
,
767 std::unique_ptr
<BuildComp
> c
) {
769 auto r
= new detail::NeoClient
{std::make_unique
<detail::RADOS
>(ioctx
, cct
)};
770 r
->objecter
->wait_for_osd_map(
771 [c
= std::move(c
), r
= std::unique_ptr
<detail::Client
>(r
)]() mutable {
772 c
->dispatch(std::move(c
), bs::error_code
{},
773 RADOS
{std::move(r
)});
775 } catch (const bs::system_error
& err
) {
776 c
->post(std::move(c
), err
.code(), RADOS
{nullptr});
780 RADOS
RADOS::make_with_librados(librados::Rados
& rados
) {
781 return RADOS
{std::make_unique
<detail::RadosClient
>(rados
.client
)};
784 RADOS::RADOS() = default;
786 RADOS::RADOS(std::unique_ptr
<detail::Client
> impl
)
787 : impl(std::move(impl
)) {}
789 RADOS::RADOS(RADOS
&&) = default;
790 RADOS
& RADOS::operator =(RADOS
&&) = default;
792 RADOS::~RADOS() = default;
794 RADOS::executor_type
RADOS::get_executor() const {
795 return impl
->ioctx
.get_executor();
798 boost::asio::io_context
& RADOS::get_io_context() {
802 void RADOS::execute(const Object
& o
, const IOContext
& _ioc
, ReadOp
&& _op
,
804 std::unique_ptr
<ReadOp::Completion
> c
, version_t
* objver
,
805 const blkin_trace_info
*trace_info
) {
806 auto oid
= reinterpret_cast<const object_t
*>(&o
.impl
);
807 auto ioc
= reinterpret_cast<const IOContextImpl
*>(&_ioc
.impl
);
808 auto op
= reinterpret_cast<OpImpl
*>(&_op
.impl
);
809 auto flags
= op
->op
.flags
| ioc
->extra_op_flags
;
811 ZTracer::Trace trace
;
813 ZTracer::Trace
parent_trace("", nullptr, trace_info
);
814 trace
.init("rados execute", &impl
->objecter
->trace_endpoint
, &parent_trace
);
818 impl
->objecter
->read(
819 *oid
, ioc
->oloc
, std::move(op
->op
), ioc
->snap_seq
, bl
, flags
,
820 std::move(c
), objver
, nullptr /* data_offset */, 0 /* features */, &trace
);
822 trace
.event("submitted");
825 void RADOS::execute(const Object
& o
, const IOContext
& _ioc
, WriteOp
&& _op
,
826 std::unique_ptr
<WriteOp::Completion
> c
, version_t
* objver
,
827 const blkin_trace_info
*trace_info
) {
828 auto oid
= reinterpret_cast<const object_t
*>(&o
.impl
);
829 auto ioc
= reinterpret_cast<const IOContextImpl
*>(&_ioc
.impl
);
830 auto op
= reinterpret_cast<OpImpl
*>(&_op
.impl
);
831 auto flags
= op
->op
.flags
| ioc
->extra_op_flags
;
832 ceph::real_time mtime
;
836 mtime
= ceph::real_clock::now();
838 ZTracer::Trace trace
;
840 ZTracer::Trace
parent_trace("", nullptr, trace_info
);
841 trace
.init("rados execute", &impl
->objecter
->trace_endpoint
, &parent_trace
);
845 impl
->objecter
->mutate(
846 *oid
, ioc
->oloc
, std::move(op
->op
), ioc
->snapc
,
848 std::move(c
), objver
, osd_reqid_t
{}, &trace
);
849 trace
.event("submitted");
852 void RADOS::execute(const Object
& o
, std::int64_t pool
, ReadOp
&& _op
,
854 std::unique_ptr
<ReadOp::Completion
> c
,
855 std::optional
<std::string_view
> ns
,
856 std::optional
<std::string_view
> key
,
858 auto oid
= reinterpret_cast<const object_t
*>(&o
.impl
);
859 auto op
= reinterpret_cast<OpImpl
*>(&_op
.impl
);
860 auto flags
= op
->op
.flags
;
861 object_locator_t oloc
;
868 impl
->objecter
->read(
869 *oid
, oloc
, std::move(op
->op
), CEPH_NOSNAP
, bl
, flags
,
870 std::move(c
), objver
);
873 void RADOS::execute(const Object
& o
, std::int64_t pool
, WriteOp
&& _op
,
874 std::unique_ptr
<WriteOp::Completion
> c
,
875 std::optional
<std::string_view
> ns
,
876 std::optional
<std::string_view
> key
,
878 auto oid
= reinterpret_cast<const object_t
*>(&o
.impl
);
879 auto op
= reinterpret_cast<OpImpl
*>(&_op
.impl
);
880 auto flags
= op
->op
.flags
;
881 object_locator_t oloc
;
888 ceph::real_time mtime
;
892 mtime
= ceph::real_clock::now();
894 impl
->objecter
->mutate(
895 *oid
, oloc
, std::move(op
->op
), {},
897 std::move(c
), objver
);
900 boost::uuids::uuid
RADOS::get_fsid() const noexcept
{
901 return impl
->monclient
.get_fsid().uuid
;
905 void RADOS::lookup_pool(std::string_view name
,
906 std::unique_ptr
<LookupPoolComp
> c
)
908 // I kind of want to make lookup_pg_pool return
909 // std::optional<int64_t> since it can only return one error code.
910 int64_t ret
= impl
->objecter
->with_osdmap(
911 std::mem_fn(&OSDMap::lookup_pg_pool_name
),
914 impl
->objecter
->wait_for_latest_osdmap(
915 [name
= std::string(name
), c
= std::move(c
),
916 objecter
= impl
->objecter
]
917 (bs::error_code ec
) mutable {
919 objecter
->with_osdmap([&](const OSDMap
&osdmap
) {
920 return osdmap
.lookup_pg_pool_name(name
);
923 ca::dispatch(std::move(c
), osdc_errc::pool_dne
,
926 ca::dispatch(std::move(c
), bs::error_code
{}, ret
);
928 } else if (ret
< 0) {
929 ca::post(std::move(c
), osdc_errc::pool_dne
,
932 ca::post(std::move(c
), bs::error_code
{}, ret
);
937 std::optional
<uint64_t> RADOS::get_pool_alignment(int64_t pool_id
)
939 return impl
->objecter
->with_osdmap(
940 [pool_id
](const OSDMap
&o
) -> std::optional
<uint64_t> {
941 if (!o
.have_pg_pool(pool_id
)) {
942 throw bs::system_error(
943 ENOENT
, bs::system_category(),
944 "Cannot find pool in OSDMap.");
945 } else if (o
.get_pg_pool(pool_id
)->requires_aligned_append()) {
946 return o
.get_pg_pool(pool_id
)->required_alignment();
953 void RADOS::list_pools(std::unique_ptr
<LSPoolsComp
> c
) {
954 impl
->objecter
->with_osdmap(
956 std::vector
<std::pair
<std::int64_t, std::string
>> v
;
957 for (auto p
: o
.get_pools())
958 v
.push_back(std::make_pair(p
.first
, o
.get_pool_name(p
.first
)));
959 ca::dispatch(std::move(c
), std::move(v
));
963 void RADOS::create_pool_snap(std::int64_t pool
,
964 std::string_view snapName
,
965 std::unique_ptr
<SimpleOpComp
> c
)
967 impl
->objecter
->create_pool_snap(
969 Objecter::PoolOp::OpComp::create(
971 [c
= std::move(c
)](bs::error_code e
, const bufferlist
&) mutable {
972 ca::dispatch(std::move(c
), e
);
976 void RADOS::allocate_selfmanaged_snap(int64_t pool
,
977 std::unique_ptr
<SMSnapComp
> c
) {
978 impl
->objecter
->allocate_selfmanaged_snap(
980 ca::Completion
<void(bs::error_code
, snapid_t
)>::create(
982 [c
= std::move(c
)](bs::error_code e
, snapid_t snap
) mutable {
983 ca::dispatch(std::move(c
), e
, snap
);
987 void RADOS::delete_pool_snap(std::int64_t pool
,
988 std::string_view snapName
,
989 std::unique_ptr
<SimpleOpComp
> c
)
991 impl
->objecter
->delete_pool_snap(
993 Objecter::PoolOp::OpComp::create(
995 [c
= std::move(c
)](bs::error_code e
, const bufferlist
&) mutable {
996 ca::dispatch(std::move(c
), e
);
1000 void RADOS::delete_selfmanaged_snap(std::int64_t pool
,
1002 std::unique_ptr
<SimpleOpComp
> c
)
1004 impl
->objecter
->delete_selfmanaged_snap(
1006 Objecter::PoolOp::OpComp::create(
1008 [c
= std::move(c
)](bs::error_code e
, const bufferlist
&) mutable {
1009 ca::dispatch(std::move(c
), e
);
1013 void RADOS::create_pool(std::string_view name
,
1014 std::optional
<int> crush_rule
,
1015 std::unique_ptr
<SimpleOpComp
> c
)
1017 impl
->objecter
->create_pool(
1019 Objecter::PoolOp::OpComp::create(
1021 [c
= std::move(c
)](bs::error_code e
, const bufferlist
&) mutable {
1022 ca::dispatch(std::move(c
), e
);
1024 crush_rule
.value_or(-1));
1027 void RADOS::delete_pool(std::string_view name
,
1028 std::unique_ptr
<SimpleOpComp
> c
)
1030 impl
->objecter
->delete_pool(
1032 Objecter::PoolOp::OpComp::create(
1034 [c
= std::move(c
)](bs::error_code e
, const bufferlist
&) mutable {
1035 ca::dispatch(std::move(c
), e
);
1039 void RADOS::delete_pool(std::int64_t pool
,
1040 std::unique_ptr
<SimpleOpComp
> c
)
1042 impl
->objecter
->delete_pool(
1044 Objecter::PoolOp::OpComp::create(
1046 [c
= std::move(c
)](bs::error_code e
, const bufferlist
&) mutable {
1047 ca::dispatch(std::move(c
), e
);
1051 void RADOS::stat_pools(const std::vector
<std::string
>& pools
,
1052 std::unique_ptr
<PoolStatComp
> c
) {
1053 impl
->objecter
->get_pool_stats(
1057 bc::flat_map
<std::string
, pool_stat_t
> rawresult
,
1058 bool per_pool
) mutable {
1059 bc::flat_map
<std::string
, PoolStats
> result
;
1060 for (auto p
= rawresult
.begin(); p
!= rawresult
.end(); ++p
) {
1061 auto& pv
= result
[p
->first
];
1062 auto& pstat
= p
->second
;
1063 store_statfs_t
&statfs
= pstat
.store_stats
;
1064 uint64_t allocated_bytes
= pstat
.get_allocated_data_bytes(per_pool
) +
1065 pstat
.get_allocated_omap_bytes(per_pool
);
1066 // FIXME: raw_used_rate is unknown hence use 1.0 here
1067 // meaning we keep net amount aggregated over all replicas
1068 // Not a big deal so far since this field isn't exposed
1069 uint64_t user_bytes
= pstat
.get_user_data_bytes(1.0, per_pool
) +
1070 pstat
.get_user_omap_bytes(1.0, per_pool
);
1072 object_stat_sum_t
*sum
= &p
->second
.stats
.sum
;
1073 pv
.num_kb
= shift_round_up(allocated_bytes
, 10);
1074 pv
.num_bytes
= allocated_bytes
;
1075 pv
.num_objects
= sum
->num_objects
;
1076 pv
.num_object_clones
= sum
->num_object_clones
;
1077 pv
.num_object_copies
= sum
->num_object_copies
;
1078 pv
.num_objects_missing_on_primary
= sum
->num_objects_missing_on_primary
;
1079 pv
.num_objects_unfound
= sum
->num_objects_unfound
;
1080 pv
.num_objects_degraded
= sum
->num_objects_degraded
;
1081 pv
.num_rd
= sum
->num_rd
;
1082 pv
.num_rd_kb
= sum
->num_rd_kb
;
1083 pv
.num_wr
= sum
->num_wr
;
1084 pv
.num_wr_kb
= sum
->num_wr_kb
;
1085 pv
.num_user_bytes
= user_bytes
;
1086 pv
.compressed_bytes_orig
= statfs
.data_compressed_original
;
1087 pv
.compressed_bytes
= statfs
.data_compressed
;
1088 pv
.compressed_bytes_alloc
= statfs
.data_compressed_allocated
;
1091 ca::dispatch(std::move(c
), ec
, std::move(result
), per_pool
);
1095 void RADOS::stat_fs(std::optional
<std::int64_t> _pool
,
1096 std::unique_ptr
<StatFSComp
> c
) {
1097 std::optional
<int64_t> pool
;
1100 impl
->objecter
->get_fs_stats(
1102 [c
= std::move(c
)](bs::error_code ec
, const struct ceph_statfs s
) mutable {
1103 FSStats fso
{s
.kb
, s
.kb_used
, s
.kb_avail
, s
.num_objects
};
1104 c
->dispatch(std::move(c
), ec
, std::move(fso
));
1110 void RADOS::watch(const Object
& o
, const IOContext
& _ioc
,
1111 std::optional
<std::chrono::seconds
> timeout
, WatchCB
&& cb
,
1112 std::unique_ptr
<WatchComp
> c
) {
1113 auto oid
= reinterpret_cast<const object_t
*>(&o
.impl
);
1114 auto ioc
= reinterpret_cast<const IOContextImpl
*>(&_ioc
.impl
);
1118 auto linger_op
= impl
->objecter
->linger_register(*oid
, ioc
->oloc
,
1119 ioc
->extra_op_flags
);
1120 uint64_t cookie
= linger_op
->get_cookie();
1121 linger_op
->handle
= std::move(cb
);
1122 op
.watch(cookie
, CEPH_OSD_WATCH_OP_WATCH
, timeout
.value_or(0s
).count());
1124 impl
->objecter
->linger_watch(
1125 linger_op
, op
, ioc
->snapc
, ceph::real_clock::now(), bl
,
1126 Objecter::LingerOp::OpComp::create(
1128 [c
= std::move(c
), cookie
](bs::error_code e
, cb::list
) mutable {
1129 ca::dispatch(std::move(c
), e
, cookie
);
1133 void RADOS::watch(const Object
& o
, std::int64_t pool
,
1134 std::optional
<std::chrono::seconds
> timeout
, WatchCB
&& cb
,
1135 std::unique_ptr
<WatchComp
> c
,
1136 std::optional
<std::string_view
> ns
,
1137 std::optional
<std::string_view
> key
) {
1138 auto oid
= reinterpret_cast<const object_t
*>(&o
.impl
);
1139 object_locator_t oloc
;
1148 Objecter::LingerOp
*linger_op
= impl
->objecter
->linger_register(*oid
, oloc
, 0);
1149 uint64_t cookie
= linger_op
->get_cookie();
1150 linger_op
->handle
= std::move(cb
);
1151 op
.watch(cookie
, CEPH_OSD_WATCH_OP_WATCH
, timeout
.value_or(0s
).count());
1153 impl
->objecter
->linger_watch(
1154 linger_op
, op
, {}, ceph::real_clock::now(), bl
,
1155 Objecter::LingerOp::OpComp::create(
1157 [c
= std::move(c
), cookie
](bs::error_code e
, bufferlist
) mutable {
1158 ca::dispatch(std::move(c
), e
, cookie
);
1162 void RADOS::notify_ack(const Object
& o
,
1163 const IOContext
& _ioc
,
1167 std::unique_ptr
<SimpleOpComp
> c
)
1169 auto oid
= reinterpret_cast<const object_t
*>(&o
.impl
);
1170 auto ioc
= reinterpret_cast<const IOContextImpl
*>(&_ioc
.impl
);
1173 op
.notify_ack(notify_id
, cookie
, bl
);
1175 impl
->objecter
->read(*oid
, ioc
->oloc
, std::move(op
), ioc
->snap_seq
,
1176 nullptr, ioc
->extra_op_flags
, std::move(c
));
1179 void RADOS::notify_ack(const Object
& o
,
1184 std::unique_ptr
<SimpleOpComp
> c
,
1185 std::optional
<std::string_view
> ns
,
1186 std::optional
<std::string_view
> key
) {
1187 auto oid
= reinterpret_cast<const object_t
*>(&o
.impl
);
1188 object_locator_t oloc
;
1196 op
.notify_ack(notify_id
, cookie
, bl
);
1197 impl
->objecter
->read(*oid
, oloc
, std::move(op
), CEPH_NOSNAP
, nullptr, 0,
1201 tl::expected
<ceph::timespan
, bs::error_code
> RADOS::watch_check(uint64_t cookie
)
1203 Objecter::LingerOp
*linger_op
= reinterpret_cast<Objecter::LingerOp
*>(cookie
);
1204 return impl
->objecter
->linger_check(linger_op
);
1207 void RADOS::unwatch(uint64_t cookie
, const IOContext
& _ioc
,
1208 std::unique_ptr
<SimpleOpComp
> c
)
1210 auto ioc
= reinterpret_cast<const IOContextImpl
*>(&_ioc
.impl
);
1212 Objecter::LingerOp
*linger_op
= reinterpret_cast<Objecter::LingerOp
*>(cookie
);
1215 op
.watch(cookie
, CEPH_OSD_WATCH_OP_UNWATCH
);
1216 impl
->objecter
->mutate(linger_op
->target
.base_oid
, ioc
->oloc
, std::move(op
),
1217 ioc
->snapc
, ceph::real_clock::now(), ioc
->extra_op_flags
,
1218 Objecter::Op::OpComp::create(
1220 [objecter
= impl
->objecter
,
1221 linger_op
, c
= std::move(c
)]
1222 (bs::error_code ec
) mutable {
1223 objecter
->linger_cancel(linger_op
);
1224 ca::dispatch(std::move(c
), ec
);
1228 void RADOS::unwatch(uint64_t cookie
, std::int64_t pool
,
1229 std::unique_ptr
<SimpleOpComp
> c
,
1230 std::optional
<std::string_view
> ns
,
1231 std::optional
<std::string_view
> key
)
1233 object_locator_t oloc
;
1240 Objecter::LingerOp
*linger_op
= reinterpret_cast<Objecter::LingerOp
*>(cookie
);
1243 op
.watch(cookie
, CEPH_OSD_WATCH_OP_UNWATCH
);
1244 impl
->objecter
->mutate(linger_op
->target
.base_oid
, oloc
, std::move(op
),
1245 {}, ceph::real_clock::now(), 0,
1246 Objecter::Op::OpComp::create(
1248 [objecter
= impl
->objecter
,
1249 linger_op
, c
= std::move(c
)]
1250 (bs::error_code ec
) mutable {
1251 objecter
->linger_cancel(linger_op
);
1252 ca::dispatch(std::move(c
), ec
);
1256 void RADOS::flush_watch(std::unique_ptr
<VoidOpComp
> c
)
1258 impl
->objecter
->linger_callback_flush([c
= std::move(c
)]() mutable {
1259 ca::post(std::move(c
));
1263 struct NotifyHandler
: std::enable_shared_from_this
<NotifyHandler
> {
1264 boost::asio::io_context
& ioc
;
1265 boost::asio::io_context::strand strand
;
1267 Objecter::LingerOp
* op
;
1268 std::unique_ptr
<RADOS::NotifyComp
> c
;
1271 bool finished
= false;
1275 NotifyHandler(boost::asio::io_context
& ioc
,
1277 Objecter::LingerOp
* op
,
1278 std::unique_ptr
<RADOS::NotifyComp
> c
)
1279 : ioc(ioc
), strand(ioc
), objecter(objecter
), op(op
), c(std::move(c
)) {}
1281 // Use bind or a lambda to pass this in.
1282 void handle_ack(bs::error_code ec
,
1286 [this, ec
, p
= shared_from_this()]() mutable {
1292 // Notify finish callback. It can actually own the object's storage.
1294 void operator()(bs::error_code ec
,
1298 [this, ec
, p
= shared_from_this()]() mutable {
1304 // Should be called from strand.
1305 void maybe_cleanup(bs::error_code ec
) {
1308 if ((acked
&& finished
) || res
) {
1309 objecter
->linger_cancel(op
);
1311 ca::dispatch(std::move(c
), res
, std::move(rbl
));
1316 void RADOS::notify(const Object
& o
, const IOContext
& _ioc
, bufferlist
&& bl
,
1317 std::optional
<std::chrono::milliseconds
> timeout
,
1318 std::unique_ptr
<NotifyComp
> c
)
1320 auto oid
= reinterpret_cast<const object_t
*>(&o
.impl
);
1321 auto ioc
= reinterpret_cast<const IOContextImpl
*>(&_ioc
.impl
);
1322 auto linger_op
= impl
->objecter
->linger_register(*oid
, ioc
->oloc
,
1323 ioc
->extra_op_flags
);
1325 auto cb
= std::make_shared
<NotifyHandler
>(impl
->ioctx
, impl
->objecter
,
1326 linger_op
, std::move(c
));
1327 linger_op
->on_notify_finish
=
1328 Objecter::LingerOp::OpComp::create(
1330 [cb
](bs::error_code ec
, ceph::bufferlist bl
) mutable {
1331 (*cb
)(ec
, std::move(bl
));
1336 linger_op
->get_cookie(), 1,
1337 timeout
? timeout
->count() : impl
->cct
->_conf
->client_notify_timeout
,
1340 impl
->objecter
->linger_notify(
1341 linger_op
, rd
, ioc
->snap_seq
, inbl
,
1342 Objecter::LingerOp::OpComp::create(
1344 [cb
](bs::error_code ec
, ceph::bufferlist bl
) mutable {
1345 cb
->handle_ack(ec
, std::move(bl
));
1349 void RADOS::notify(const Object
& o
, std::int64_t pool
, bufferlist
&& bl
,
1350 std::optional
<std::chrono::milliseconds
> timeout
,
1351 std::unique_ptr
<NotifyComp
> c
,
1352 std::optional
<std::string_view
> ns
,
1353 std::optional
<std::string_view
> key
)
1355 auto oid
= reinterpret_cast<const object_t
*>(&o
.impl
);
1356 object_locator_t oloc
;
1362 auto linger_op
= impl
->objecter
->linger_register(*oid
, oloc
, 0);
1364 auto cb
= std::make_shared
<NotifyHandler
>(impl
->ioctx
, impl
->objecter
,
1365 linger_op
, std::move(c
));
1366 linger_op
->on_notify_finish
=
1367 Objecter::LingerOp::OpComp::create(
1369 [cb
](bs::error_code ec
, ceph::bufferlist
&& bl
) mutable {
1370 (*cb
)(ec
, std::move(bl
));
1375 linger_op
->get_cookie(), 1,
1376 timeout
? timeout
->count() : impl
->cct
->_conf
->client_notify_timeout
,
1379 impl
->objecter
->linger_notify(
1380 linger_op
, rd
, CEPH_NOSNAP
, inbl
,
1381 Objecter::LingerOp::OpComp::create(
1383 [cb
](bs::error_code ec
, bufferlist
&& bl
) mutable {
1384 cb
->handle_ack(ec
, std::move(bl
));
1391 static_assert(impl_size
>= sizeof(hobject_t
));
1392 new (&impl
) hobject_t();
1395 Cursor::Cursor(end_magic_t
) {
1396 static_assert(impl_size
>= sizeof(hobject_t
));
1397 new (&impl
) hobject_t(hobject_t::get_max());
1400 Cursor::Cursor(void* p
) {
1401 static_assert(impl_size
>= sizeof(hobject_t
));
1402 new (&impl
) hobject_t(std::move(*reinterpret_cast<hobject_t
*>(p
)));
1405 Cursor
Cursor::begin() {
1410 Cursor
Cursor::end() {
1411 Cursor
e(end_magic_t
{});
1415 Cursor::Cursor(const Cursor
& rhs
) {
1416 static_assert(impl_size
>= sizeof(hobject_t
));
1417 new (&impl
) hobject_t(*reinterpret_cast<const hobject_t
*>(&rhs
.impl
));
1420 Cursor
& Cursor::operator =(const Cursor
& rhs
) {
1421 static_assert(impl_size
>= sizeof(hobject_t
));
1422 reinterpret_cast<hobject_t
*>(&impl
)->~hobject_t();
1423 new (&impl
) hobject_t(*reinterpret_cast<const hobject_t
*>(&rhs
.impl
));
1427 Cursor::Cursor(Cursor
&& rhs
) {
1428 static_assert(impl_size
>= sizeof(hobject_t
));
1429 new (&impl
) hobject_t(std::move(*reinterpret_cast<hobject_t
*>(&rhs
.impl
)));
1432 Cursor
& Cursor::operator =(Cursor
&& rhs
) {
1433 static_assert(impl_size
>= sizeof(hobject_t
));
1434 reinterpret_cast<hobject_t
*>(&impl
)->~hobject_t();
1435 new (&impl
) hobject_t(std::move(*reinterpret_cast<hobject_t
*>(&rhs
.impl
)));
1439 reinterpret_cast<hobject_t
*>(&impl
)->~hobject_t();
1442 bool operator ==(const Cursor
& lhs
, const Cursor
& rhs
) {
1443 return (*reinterpret_cast<const hobject_t
*>(&lhs
.impl
) ==
1444 *reinterpret_cast<const hobject_t
*>(&rhs
.impl
));
1447 bool operator !=(const Cursor
& lhs
, const Cursor
& rhs
) {
1448 return (*reinterpret_cast<const hobject_t
*>(&lhs
.impl
) !=
1449 *reinterpret_cast<const hobject_t
*>(&rhs
.impl
));
1452 bool operator <(const Cursor
& lhs
, const Cursor
& rhs
) {
1453 return (*reinterpret_cast<const hobject_t
*>(&lhs
.impl
) <
1454 *reinterpret_cast<const hobject_t
*>(&rhs
.impl
));
1457 bool operator <=(const Cursor
& lhs
, const Cursor
& rhs
) {
1458 return (*reinterpret_cast<const hobject_t
*>(&lhs
.impl
) <=
1459 *reinterpret_cast<const hobject_t
*>(&rhs
.impl
));
1462 bool operator >=(const Cursor
& lhs
, const Cursor
& rhs
) {
1463 return (*reinterpret_cast<const hobject_t
*>(&lhs
.impl
) >=
1464 *reinterpret_cast<const hobject_t
*>(&rhs
.impl
));
1467 bool operator >(const Cursor
& lhs
, const Cursor
& rhs
) {
1468 return (*reinterpret_cast<const hobject_t
*>(&lhs
.impl
) >
1469 *reinterpret_cast<const hobject_t
*>(&rhs
.impl
));
1472 std::string
Cursor::to_str() const {
1473 using namespace std::literals
;
1474 auto& h
= *reinterpret_cast<const hobject_t
*>(&impl
);
1476 return h
.is_max() ? "MAX"s
: h
.to_str();
1479 std::optional
<Cursor
>
1480 Cursor::from_str(const std::string
& s
) {
1482 auto& h
= *reinterpret_cast<hobject_t
*>(&e
.impl
);
1484 return std::nullopt
;
1489 void RADOS::enumerate_objects(const IOContext
& _ioc
,
1490 const Cursor
& begin
,
1492 const std::uint32_t max
,
1493 const bufferlist
& filter
,
1494 std::unique_ptr
<EnumerateComp
> c
) {
1495 auto ioc
= reinterpret_cast<const IOContextImpl
*>(&_ioc
.impl
);
1497 impl
->objecter
->enumerate_objects
<Entry
>(
1500 *reinterpret_cast<const hobject_t
*>(&begin
.impl
),
1501 *reinterpret_cast<const hobject_t
*>(&end
.impl
),
1505 (bs::error_code ec
, std::vector
<Entry
>&& v
,
1506 hobject_t
&& n
) mutable {
1507 ca::dispatch(std::move(c
), ec
, std::move(v
),
1508 Cursor(static_cast<void*>(&n
)));
1512 void RADOS::enumerate_objects(std::int64_t pool
,
1513 const Cursor
& begin
,
1515 const std::uint32_t max
,
1516 const bufferlist
& filter
,
1517 std::unique_ptr
<EnumerateComp
> c
,
1518 std::optional
<std::string_view
> ns
,
1519 std::optional
<std::string_view
> key
) {
1520 impl
->objecter
->enumerate_objects
<Entry
>(
1522 ns
? *ns
: std::string_view
{},
1523 *reinterpret_cast<const hobject_t
*>(&begin
.impl
),
1524 *reinterpret_cast<const hobject_t
*>(&end
.impl
),
1528 (bs::error_code ec
, std::vector
<Entry
>&& v
,
1529 hobject_t
&& n
) mutable {
1530 ca::dispatch(std::move(c
), ec
, std::move(v
),
1531 Cursor(static_cast<void*>(&n
)));
1536 void RADOS::osd_command(int osd
, std::vector
<std::string
>&& cmd
,
1537 ceph::bufferlist
&& in
, std::unique_ptr
<CommandComp
> c
) {
1538 impl
->objecter
->osd_command(osd
, std::move(cmd
), std::move(in
), nullptr,
1542 ceph::bufferlist
&& b
) mutable {
1543 ca::dispatch(std::move(c
), ec
,
1548 void RADOS::pg_command(PG pg
, std::vector
<std::string
>&& cmd
,
1549 ceph::bufferlist
&& in
, std::unique_ptr
<CommandComp
> c
) {
1550 impl
->objecter
->pg_command(pg_t
{pg
.seed
, pg
.pool
}, std::move(cmd
), std::move(in
), nullptr,
1554 ceph::bufferlist
&& b
) mutable {
1555 ca::dispatch(std::move(c
), ec
,
1561 void RADOS::enable_application(std::string_view pool
, std::string_view app_name
,
1562 bool force
, std::unique_ptr
<SimpleOpComp
> c
) {
1563 // pre-Luminous clusters will return -EINVAL and application won't be
1564 // preserved until Luminous is configured as minimum version.
1565 if (!impl
->get_required_monitor_features().contains_all(
1566 ceph::features::mon::FEATURE_LUMINOUS
)) {
1567 ca::post(std::move(c
), ceph::to_error_code(-EOPNOTSUPP
));
1569 impl
->monclient
.start_mon_command(
1570 { fmt::format("{{ \"prefix\": \"osd pool application enable\","
1571 "\"pool\": \"{}\", \"app\": \"{}\"{}}}",
1573 force
? " ,\"yes_i_really_mean_it\": true" : "")},
1574 {}, [c
= std::move(c
)](bs::error_code e
,
1575 std::string
, cb::list
) mutable {
1576 ca::post(std::move(c
), e
);
1581 void RADOS::blocklist_add(std::string_view client_address
,
1582 std::optional
<std::chrono::seconds
> expire
,
1583 std::unique_ptr
<SimpleOpComp
> c
) {
1584 auto expire_arg
= (expire
?
1585 fmt::format(", \"expire\": \"{}.0\"", expire
->count()) : std::string
{});
1586 impl
->monclient
.start_mon_command(
1588 "\"prefix\": \"osd blocklist\", "
1589 "\"blocklistop\": \"add\", "
1590 "\"addr\": \"{}\"{}}}",
1591 client_address
, expire_arg
) },
1593 [this, client_address
= std::string(client_address
), expire_arg
,
1594 c
= std::move(c
)](bs::error_code ec
, std::string
, cb::list
) mutable {
1595 if (ec
!= bs::errc::invalid_argument
) {
1596 ca::post(std::move(c
), ec
);
1600 // retry using the legacy command
1601 impl
->monclient
.start_mon_command(
1603 "\"prefix\": \"osd blacklist\", "
1604 "\"blacklistop\": \"add\", "
1605 "\"addr\": \"{}\"{}}}",
1606 client_address
, expire_arg
) },
1608 [c
= std::move(c
)](bs::error_code ec
, std::string
, cb::list
) mutable {
1609 ca::post(std::move(c
), ec
);
1614 void RADOS::wait_for_latest_osd_map(std::unique_ptr
<SimpleOpComp
> c
) {
1615 impl
->objecter
->wait_for_latest_osdmap(std::move(c
));
1618 void RADOS::mon_command(std::vector
<std::string
> command
,
1620 std::string
* outs
, cb::list
* outbl
,
1621 std::unique_ptr
<SimpleOpComp
> c
) {
1623 impl
->monclient
.start_mon_command(
1625 [c
= std::move(c
), outs
, outbl
](bs::error_code e
,
1626 std::string s
, cb::list bl
) mutable {
1628 *outs
= std::move(s
);
1630 *outbl
= std::move(bl
);
1631 ca::post(std::move(c
), e
);
1635 uint64_t RADOS::instance_id() const {
1636 return impl
->get_instance_id();
1639 #pragma GCC diagnostic push
1640 #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
1641 #pragma clang diagnostic push
1642 #pragma clang diagnostic ignored "-Wnon-virtual-dtor"
1643 class category
: public ceph::converting_category
{
1646 const char* name() const noexcept override
;
1647 const char* message(int ev
, char*, std::size_t) const noexcept override
;
1648 std::string
message(int ev
) const override
;
1649 bs::error_condition
default_error_condition(int ev
) const noexcept
1651 bool equivalent(int ev
, const bs::error_condition
& c
) const
1653 using ceph::converting_category::equivalent
;
1654 int from_code(int ev
) const noexcept override
;
1656 #pragma GCC diagnostic pop
1657 #pragma clang diagnostic pop
1659 const char* category::name() const noexcept
{
1663 const char* category::message(int ev
, char*,
1664 std::size_t) const noexcept
{
1668 switch (static_cast<errc
>(ev
)) {
1669 case errc::pool_dne
:
1670 return "Pool does not exist";
1672 case errc::invalid_snapcontext
:
1673 return "Invalid snapcontext";
1676 return "Unknown error";
1679 std::string
category::message(int ev
) const {
1680 return message(ev
, nullptr, 0);
1683 bs::error_condition
category::default_error_condition(int ev
) const noexcept
{
1684 switch (static_cast<errc
>(ev
)) {
1685 case errc::pool_dne
:
1686 return ceph::errc::does_not_exist
;
1687 case errc::invalid_snapcontext
:
1688 return bs::errc::invalid_argument
;
1691 return { ev
, *this };
1694 bool category::equivalent(int ev
, const bs::error_condition
& c
) const noexcept
{
1695 if (static_cast<errc
>(ev
) == errc::pool_dne
) {
1696 if (c
== bs::errc::no_such_file_or_directory
) {
1701 return default_error_condition(ev
) == c
;
1704 int category::from_code(int ev
) const noexcept
{
1705 switch (static_cast<errc
>(ev
)) {
1706 case errc::pool_dne
:
1708 case errc::invalid_snapcontext
:
1714 const bs::error_category
& error_category() noexcept
{
1715 static const class category c
;
1719 CephContext
* RADOS::cct() {
1720 return impl
->cct
.get();
1725 size_t hash
<neorados::Object
>::operator ()(
1726 const neorados::Object
& r
) const {
1727 static constexpr const hash
<object_t
> H
;
1728 return H(*reinterpret_cast<const object_t
*>(&r
.impl
));
1731 size_t hash
<neorados::IOContext
>::operator ()(
1732 const neorados::IOContext
& r
) const {
1733 static constexpr const hash
<int64_t> H
;
1734 static constexpr const hash
<std::string
> G
;
1735 const auto l
= reinterpret_cast<const neorados::IOContextImpl
*>(&r
.impl
);
1736 return H(l
->oloc
.pool
) ^ (G(l
->oloc
.nspace
) << 1) ^ (G(l
->oloc
.key
) << 2);