]> git.proxmox.com Git - ceph.git/blob - ceph/src/neorados/RADOS.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / neorados / RADOS.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2018 Red Hat <contact@redhat.com>
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15 #define BOOST_BIND_NO_PLACEHOLDERS
16
17 #include <optional>
18 #include <string_view>
19
20 #include <boost/intrusive_ptr.hpp>
21
22 #include <fmt/format.h>
23
24 #include "include/ceph_fs.h"
25
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"
31
32 #include "global/global_init.h"
33
34 #include "osd/osd_types.h"
35 #include "osdc/error_code.h"
36
37 #include "neorados/RADOSImpl.h"
38 #include "include/neorados/RADOS.hpp"
39
40 using namespace std::literals;
41
42 namespace bc = boost::container;
43 namespace bs = boost::system;
44 namespace ca = ceph::async;
45 namespace cb = ceph::buffer;
46
47 namespace neorados {
48 // Object
49
50 Object::Object() {
51 static_assert(impl_size >= sizeof(object_t));
52 new (&impl) object_t();
53 }
54
55 Object::Object(const char* s) {
56 static_assert(impl_size >= sizeof(object_t));
57 new (&impl) object_t(s);
58 }
59
60 Object::Object(std::string_view s) {
61 static_assert(impl_size >= sizeof(object_t));
62 new (&impl) object_t(s);
63 }
64
65 Object::Object(std::string&& s) {
66 static_assert(impl_size >= sizeof(object_t));
67 new (&impl) object_t(std::move(s));
68 }
69
70 Object::Object(const std::string& s) {
71 static_assert(impl_size >= sizeof(object_t));
72 new (&impl) object_t(s);
73 }
74
75 Object::~Object() {
76 reinterpret_cast<object_t*>(&impl)->~object_t();
77 }
78
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));
82 }
83 Object& Object::operator =(const Object& o) {
84 *reinterpret_cast<object_t*>(&impl) =
85 *reinterpret_cast<const object_t*>(&o.impl);
86 return *this;
87 }
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)));
91 }
92 Object& Object::operator =(Object&& o) {
93 *reinterpret_cast<object_t*>(&impl) =
94 std::move(*reinterpret_cast<object_t*>(&o.impl));
95 return *this;
96 }
97
98 Object::operator std::string_view() const {
99 return std::string_view(reinterpret_cast<const object_t*>(&impl)->name);
100 }
101
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));
105 }
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));
109 }
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));
113 }
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));
117 }
118
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));
122 }
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));
126 }
127
128 std::ostream& operator <<(std::ostream& m, const Object& o) {
129 return (m << *reinterpret_cast<const object_t*>(&o.impl));
130 }
131
132 // IOContext
133
134 struct IOContextImpl {
135 object_locator_t oloc;
136 snapid_t snap_seq = CEPH_NOSNAP;
137 SnapContext snapc;
138 int extra_op_flags = 0;
139 };
140
141 IOContext::IOContext() {
142 static_assert(impl_size >= sizeof(IOContextImpl));
143 new (&impl) IOContextImpl();
144 }
145
146 IOContext::IOContext(std::int64_t _pool) : IOContext() {
147 pool(_pool);
148 }
149
150 IOContext::IOContext(std::int64_t _pool, std::string_view _ns)
151 : IOContext() {
152 pool(_pool);
153 ns(_ns);
154 }
155
156 IOContext::IOContext(std::int64_t _pool, std::string&& _ns)
157 : IOContext() {
158 pool(_pool);
159 ns(std::move(_ns));
160 }
161
162 IOContext::~IOContext() {
163 reinterpret_cast<IOContextImpl*>(&impl)->~IOContextImpl();
164 }
165
166 IOContext::IOContext(const IOContext& rhs) {
167 static_assert(impl_size >= sizeof(IOContextImpl));
168 new (&impl) IOContextImpl(*reinterpret_cast<const IOContextImpl*>(&rhs.impl));
169 }
170
171 IOContext& IOContext::operator =(const IOContext& rhs) {
172 *reinterpret_cast<IOContextImpl*>(&impl) =
173 *reinterpret_cast<const IOContextImpl*>(&rhs.impl);
174 return *this;
175 }
176
177 IOContext::IOContext(IOContext&& rhs) {
178 static_assert(impl_size >= sizeof(IOContextImpl));
179 new (&impl) IOContextImpl(
180 std::move(*reinterpret_cast<IOContextImpl*>(&rhs.impl)));
181 }
182
183 IOContext& IOContext::operator =(IOContext&& rhs) {
184 *reinterpret_cast<IOContextImpl*>(&impl) =
185 std::move(*reinterpret_cast<IOContextImpl*>(&rhs.impl));
186 return *this;
187 }
188
189 std::int64_t IOContext::pool() const {
190 return reinterpret_cast<const IOContextImpl*>(&impl)->oloc.pool;
191 }
192
193 void IOContext::pool(std::int64_t _pool) {
194 reinterpret_cast<IOContextImpl*>(&impl)->oloc.pool = _pool;
195 }
196
197 std::string_view IOContext::ns() const {
198 return reinterpret_cast<const IOContextImpl*>(&impl)->oloc.nspace;
199 }
200
201 void IOContext::ns(std::string_view _ns) {
202 reinterpret_cast<IOContextImpl*>(&impl)->oloc.nspace = _ns;
203 }
204
205 void IOContext::ns(std::string&& _ns) {
206 reinterpret_cast<IOContextImpl*>(&impl)->oloc.nspace = std::move(_ns);
207 }
208
209 std::optional<std::string_view> IOContext::key() const {
210 auto& oloc = reinterpret_cast<const IOContextImpl*>(&impl)->oloc;
211 if (oloc.key.empty())
212 return std::nullopt;
213 else
214 return std::string_view(oloc.key);
215 }
216
217 void IOContext::key(std::string_view _key) {
218 auto& oloc = reinterpret_cast<IOContextImpl*>(&impl)->oloc;
219 oloc.hash = -1;
220 oloc.key = _key;
221 }
222
223 void IOContext::key(std::string&&_key) {
224 auto& oloc = reinterpret_cast<IOContextImpl*>(&impl)->oloc;
225 oloc.hash = -1;
226 oloc.key = std::move(_key);
227 }
228
229 void IOContext::clear_key() {
230 auto& oloc = reinterpret_cast<IOContextImpl*>(&impl)->oloc;
231 oloc.hash = -1;
232 oloc.key.clear();
233 }
234
235 std::optional<std::int64_t> IOContext::hash() const {
236 auto& oloc = reinterpret_cast<const IOContextImpl*>(&impl)->oloc;
237 if (oloc.hash < 0)
238 return std::nullopt;
239 else
240 return oloc.hash;
241 }
242
243 void IOContext::hash(std::int64_t _hash) {
244 auto& oloc = reinterpret_cast<IOContextImpl*>(&impl)->oloc;
245 oloc.hash = _hash;
246 oloc.key.clear();
247 }
248
249 void IOContext::clear_hash() {
250 auto& oloc = reinterpret_cast<IOContextImpl*>(&impl)->oloc;
251 oloc.hash = -1;
252 oloc.key.clear();
253 }
254
255
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)
259 return std::nullopt;
260 else
261 return snap_seq;
262 }
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);
266 }
267
268 std::optional<
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;
272 if (snapc.empty()) {
273 return std::nullopt;
274 } else {
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));
277 }
278 }
279
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;
283 if (!_snapc) {
284 snapc.clear();
285 } else {
286 SnapContext n(_snapc->first, { _snapc->second.begin(), _snapc->second.end()});
287 if (!n.is_valid()) {
288 throw bs::system_error(EINVAL,
289 bs::system_category(),
290 "Invalid snap context.");
291
292 } else {
293 snapc = n;
294 }
295 }
296 }
297
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;
301 }
302
303 void IOContext::full_try(bool _full_try) {
304 auto ioc = reinterpret_cast<IOContextImpl*>(&impl);
305 if (_full_try) {
306 ioc->extra_op_flags |= CEPH_OSD_FLAG_FULL_TRY;
307 } else {
308 ioc->extra_op_flags &= ~CEPH_OSD_FLAG_FULL_TRY;
309 }
310 }
311
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);
315
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));
318 }
319
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);
323
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));
326 }
327
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);
331
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));
334 }
335
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);
339
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));
342 }
343
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);
347
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));
350 }
351
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);
355
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));
358 }
359
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);
363 }
364
365
366 // Op
367
368 struct OpImpl {
369 ObjectOperation op;
370 std::optional<ceph::real_time> mtime;
371
372 OpImpl() = default;
373
374 OpImpl(const OpImpl& rhs) = delete;
375 OpImpl(OpImpl&& rhs) = default;
376
377 OpImpl& operator =(const OpImpl& rhs) = delete;
378 OpImpl& operator =(OpImpl&& rhs) = default;
379 };
380
381 Op::Op() {
382 static_assert(Op::impl_size >= sizeof(OpImpl));
383 new (&impl) OpImpl;
384 }
385
386 Op::Op(Op&& rhs) {
387 new (&impl) OpImpl(std::move(*reinterpret_cast<OpImpl*>(&rhs.impl)));
388 }
389 Op& Op::operator =(Op&& rhs) {
390 reinterpret_cast<OpImpl*>(&impl)->~OpImpl();
391 new (&impl) OpImpl(std::move(*reinterpret_cast<OpImpl*>(&rhs.impl)));
392 return *this;
393 }
394 Op::~Op() {
395 reinterpret_cast<OpImpl*>(&impl)->~OpImpl();
396 }
397
398 void Op::set_excl() {
399 reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags(CEPH_OSD_OP_FLAG_EXCL);
400 }
401 void Op::set_failok() {
402 reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags(
403 CEPH_OSD_OP_FLAG_FAILOK);
404 }
405 void Op::set_fadvise_random() {
406 reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags(
407 CEPH_OSD_OP_FLAG_FADVISE_RANDOM);
408 }
409 void Op::set_fadvise_sequential() {
410 reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags(
411 CEPH_OSD_OP_FLAG_FADVISE_SEQUENTIAL);
412 }
413 void Op::set_fadvise_willneed() {
414 reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags(
415 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
416 }
417 void Op::set_fadvise_dontneed() {
418 reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags(
419 CEPH_OSD_OP_FLAG_FADVISE_DONTNEED);
420 }
421 void Op::set_fadvise_nocache() {
422 reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags(
423 CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
424 }
425
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,
428 s);
429 }
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);
433 }
434 void Op::cmpxattr(std::string_view name, cmpxattr_op op, std::uint64_t val) {
435 bufferlist bl;
436 encode(val, bl);
437 reinterpret_cast<OpImpl*>(&impl)->
438 op.cmpxattr(name, std::uint8_t(op), CEPH_OSD_CMPXATTR_MODE_U64, bl);
439 }
440
441 void Op::assert_version(uint64_t ver) {
442 reinterpret_cast<OpImpl*>(&impl)->op.assert_version(ver);
443 }
444 void Op::assert_exists() {
445 reinterpret_cast<OpImpl*>(&impl)->op.stat(
446 nullptr,
447 static_cast<ceph::real_time*>(nullptr),
448 static_cast<bs::error_code*>(nullptr));
449 }
450 void Op::cmp_omap(const bc::flat_map<
451 std::string, std::pair<cb::list,
452 int>>& assertions) {
453 reinterpret_cast<OpImpl*>(&impl)->op.omap_cmp(assertions, nullptr);
454 }
455
456 void Op::exec(std::string_view cls, std::string_view method,
457 const bufferlist& inbl,
458 cb::list* out,
459 bs::error_code* ec) {
460 reinterpret_cast<OpImpl*>(&impl)->op.call(cls, method, inbl, ec, out);
461 }
462
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));
468 }
469
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));
475 }
476
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);
480 }
481
482 void Op::balance_reads() {
483 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_BALANCE_READS;
484 }
485 void Op::localize_reads() {
486 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_LOCALIZE_READS;
487 }
488 void Op::order_reads_writes() {
489 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_RWORDERED;
490 }
491 void Op::ignore_cache() {
492 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_IGNORE_CACHE;
493 }
494 void Op::skiprwlocks() {
495 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_SKIPRWLOCKS;
496 }
497 void Op::ignore_overlay() {
498 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_IGNORE_OVERLAY;
499 }
500 void Op::full_try() {
501 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_FULL_TRY;
502 }
503 void Op::full_force() {
504 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_FULL_FORCE;
505 }
506 void Op::ignore_redirect() {
507 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_IGNORE_REDIRECT;
508 }
509 void Op::ordersnap() {
510 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_ORDERSNAP;
511 }
512 void Op::returnvec() {
513 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_RETURNVEC;
514 }
515
516 std::size_t Op::size() const {
517 return reinterpret_cast<const OpImpl*>(&impl)->op.size();
518 }
519
520 std::ostream& operator <<(std::ostream& m, const Op& o) {
521 return m << reinterpret_cast<const OpImpl*>(&o.impl)->op;
522 }
523
524
525 // ---
526
527 // ReadOp / WriteOp
528
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);
532 }
533
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);
537 }
538
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);
542 }
543
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);
549 }
550
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);
554 }
555
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,
559 bool* done,
560 bs::error_code* ec) {
561 reinterpret_cast<OpImpl*>(&impl)->op.omap_get_keys(start_after, max_return,
562 ec, keys, done);
563 }
564
565 void ReadOp::get_xattrs(bc::flat_map<std::string,
566 cb::list>* kv,
567 bs::error_code* ec) {
568 reinterpret_cast<OpImpl*>(&impl)->op.getxattrs(ec, kv);
569 }
570
571 void ReadOp::get_omap_vals(std::optional<std::string_view> start_after,
572 std::optional<std::string_view> filter_prefix,
573 uint64_t max_return,
574 bc::flat_map<std::string,
575 cb::list>* kv,
576 bool* done,
577 bs::error_code* ec) {
578 reinterpret_cast<OpImpl*>(&impl)->op.omap_get_vals(start_after, filter_prefix,
579 max_return, ec, kv, done);
580 }
581
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);
587 }
588
589 void ReadOp::list_watchers(std::vector<ObjWatcher>* watchers,
590 bs::error_code* ec) {
591 reinterpret_cast<OpImpl*>(&impl)-> op.list_watchers(watchers, ec);
592 }
593
594 void ReadOp::list_snaps(SnapSet* snaps,
595 bs::error_code* ec) {
596 reinterpret_cast<OpImpl*>(&impl)->op.list_snaps(snaps, nullptr, ec);
597 }
598
599 // WriteOp
600
601 void WriteOp::set_mtime(ceph::real_time t) {
602 auto o = reinterpret_cast<OpImpl*>(&impl);
603 o->mtime = t;
604 }
605
606 void WriteOp::create(bool exclusive) {
607 reinterpret_cast<OpImpl*>(&impl)->op.create(exclusive);
608 }
609
610 void WriteOp::write(uint64_t off, bufferlist&& bl) {
611 reinterpret_cast<OpImpl*>(&impl)->op.write(off, bl);
612 }
613
614 void WriteOp::write_full(bufferlist&& bl) {
615 reinterpret_cast<OpImpl*>(&impl)->op.write_full(bl);
616 }
617
618 void WriteOp::writesame(uint64_t off, uint64_t write_len, bufferlist&& bl) {
619 reinterpret_cast<OpImpl*>(&impl)->op.writesame(off, write_len, bl);
620 }
621
622 void WriteOp::append(bufferlist&& bl) {
623 reinterpret_cast<OpImpl*>(&impl)->op.append(bl);
624 }
625
626 void WriteOp::remove() {
627 reinterpret_cast<OpImpl*>(&impl)->op.remove();
628 }
629
630 void WriteOp::truncate(uint64_t off) {
631 reinterpret_cast<OpImpl*>(&impl)->op.truncate(off);
632 }
633
634 void WriteOp::zero(uint64_t off, uint64_t len) {
635 reinterpret_cast<OpImpl*>(&impl)->op.zero(off, len);
636 }
637
638 void WriteOp::rmxattr(std::string_view name) {
639 reinterpret_cast<OpImpl*>(&impl)->op.rmxattr(name);
640 }
641
642 void WriteOp::setxattr(std::string_view name,
643 bufferlist&& bl) {
644 reinterpret_cast<OpImpl*>(&impl)->op.setxattr(name, bl);
645 }
646
647 void WriteOp::rollback(uint64_t snapid) {
648 reinterpret_cast<OpImpl*>(&impl)->op.rollback(snapid);
649 }
650
651 void WriteOp::set_omap(
652 const bc::flat_map<std::string, cb::list>& map) {
653 reinterpret_cast<OpImpl*>(&impl)->op.omap_set(map);
654 }
655
656 void WriteOp::set_omap_header(bufferlist&& bl) {
657 reinterpret_cast<OpImpl*>(&impl)->op.omap_set_header(bl);
658 }
659
660 void WriteOp::clear_omap() {
661 reinterpret_cast<OpImpl*>(&impl)->op.omap_clear();
662 }
663
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);
667 }
668
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));
693
694 reinterpret_cast<OpImpl*>(&impl)->op.set_alloc_hint(expected_object_size,
695 expected_write_size,
696 flags);
697 }
698
699 // RADOS
700
701 RADOS::Builder& RADOS::Builder::add_conf_file(std::string_view f) {
702 if (conf_files)
703 *conf_files += (", " + std::string(f));
704 else
705 conf_files = std::string(f);
706 return *this;
707 }
708
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);
713 if (name)
714 ci.name.set(CEPH_ENTITY_TYPE_CLIENT, *name);
715 else
716 ci.name.set(CEPH_ENTITY_TYPE_CLIENT, "admin");
717 uint32_t flags = 0;
718 if (no_default_conf)
719 flags |= CINIT_FLAG_NO_DEFAULT_CONFIG_FILE;
720 if (no_mon_conf)
721 flags |= CINIT_FLAG_NO_MON_CONFIG;
722
723 CephContext *cct = common_preinit(ci, env, flags);
724 if (cluster)
725 cct->_conf->cluster = *cluster;
726
727 if (no_mon_conf)
728 cct->_conf->no_mon_config = true;
729
730 // TODO: Come up with proper error codes here. Maybe augment the
731 // functions with a default bs::error_code* parameter to
732 // pass back.
733 {
734 std::ostringstream ss;
735 auto r = cct->_conf.parse_config_files(conf_files ? conf_files->data() : nullptr,
736 &ss, flags);
737 if (r < 0)
738 c->post(std::move(c), ceph::to_error_code(r), RADOS{nullptr});
739 }
740
741 cct->_conf.parse_env(cct->get_module_type());
742
743 for (const auto& [n, v] : configs) {
744 std::stringstream ss;
745 auto r = cct->_conf.set_val(n, v, &ss);
746 if (r < 0)
747 c->post(std::move(c), ceph::to_error_code(-EINVAL), RADOS{nullptr});
748 }
749
750 if (!no_mon_conf) {
751 MonClient mc_bootstrap(cct, ioctx);
752 // TODO This function should return an error code.
753 auto err = mc_bootstrap.get_monmap_and_config();
754 if (err < 0)
755 c->post(std::move(c), ceph::to_error_code(err), RADOS{nullptr});
756 }
757 if (!cct->_log->is_started()) {
758 cct->_log->start();
759 }
760 common_init_finish(cct);
761
762 RADOS::make_with_cct(cct, ioctx, std::move(c));
763 }
764
765 void RADOS::make_with_cct(CephContext* cct,
766 boost::asio::io_context& ioctx,
767 std::unique_ptr<BuildComp> c) {
768 try {
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)});
774 });
775 } catch (const bs::system_error& err) {
776 c->post(std::move(c), err.code(), RADOS{nullptr});
777 }
778 }
779
780 RADOS RADOS::make_with_librados(librados::Rados& rados) {
781 return RADOS{std::make_unique<detail::RadosClient>(rados.client)};
782 }
783
784 RADOS::RADOS() = default;
785
786 RADOS::RADOS(std::unique_ptr<detail::Client> impl)
787 : impl(std::move(impl)) {}
788
789 RADOS::RADOS(RADOS&&) = default;
790 RADOS& RADOS::operator =(RADOS&&) = default;
791
792 RADOS::~RADOS() = default;
793
794 RADOS::executor_type RADOS::get_executor() const {
795 return impl->ioctx.get_executor();
796 }
797
798 boost::asio::io_context& RADOS::get_io_context() {
799 return impl->ioctx;
800 }
801
802 void RADOS::execute(const Object& o, const IOContext& _ioc, ReadOp&& _op,
803 cb::list* bl,
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;
810
811 ZTracer::Trace trace;
812 if (trace_info) {
813 ZTracer::Trace parent_trace("", nullptr, trace_info);
814 trace.init("rados execute", &impl->objecter->trace_endpoint, &parent_trace);
815 }
816
817 trace.event("init");
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);
821
822 trace.event("submitted");
823 }
824
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;
833 if (op->mtime)
834 mtime = *op->mtime;
835 else
836 mtime = ceph::real_clock::now();
837
838 ZTracer::Trace trace;
839 if (trace_info) {
840 ZTracer::Trace parent_trace("", nullptr, trace_info);
841 trace.init("rados execute", &impl->objecter->trace_endpoint, &parent_trace);
842 }
843
844 trace.event("init");
845 impl->objecter->mutate(
846 *oid, ioc->oloc, std::move(op->op), ioc->snapc,
847 mtime, flags,
848 std::move(c), objver, osd_reqid_t{}, &trace);
849 trace.event("submitted");
850 }
851
852 void RADOS::execute(const Object& o, std::int64_t pool, ReadOp&& _op,
853 cb::list* bl,
854 std::unique_ptr<ReadOp::Completion> c,
855 std::optional<std::string_view> ns,
856 std::optional<std::string_view> key,
857 version_t* objver) {
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;
862 oloc.pool = pool;
863 if (ns)
864 oloc.nspace = *ns;
865 if (key)
866 oloc.key = *key;
867
868 impl->objecter->read(
869 *oid, oloc, std::move(op->op), CEPH_NOSNAP, bl, flags,
870 std::move(c), objver);
871 }
872
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,
877 version_t* objver) {
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;
882 oloc.pool = pool;
883 if (ns)
884 oloc.nspace = *ns;
885 if (key)
886 oloc.key = *key;
887
888 ceph::real_time mtime;
889 if (op->mtime)
890 mtime = *op->mtime;
891 else
892 mtime = ceph::real_clock::now();
893
894 impl->objecter->mutate(
895 *oid, oloc, std::move(op->op), {},
896 mtime, flags,
897 std::move(c), objver);
898 }
899
900 boost::uuids::uuid RADOS::get_fsid() const noexcept {
901 return impl->monclient.get_fsid().uuid;
902 }
903
904
905 void RADOS::lookup_pool(std::string_view name,
906 std::unique_ptr<LookupPoolComp> c)
907 {
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),
912 name);
913 if (ret < 0) {
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 {
918 int64_t ret =
919 objecter->with_osdmap([&](const OSDMap &osdmap) {
920 return osdmap.lookup_pg_pool_name(name);
921 });
922 if (ret < 0)
923 ca::dispatch(std::move(c), osdc_errc::pool_dne,
924 std::int64_t(0));
925 else
926 ca::dispatch(std::move(c), bs::error_code{}, ret);
927 });
928 } else if (ret < 0) {
929 ca::post(std::move(c), osdc_errc::pool_dne,
930 std::int64_t(0));
931 } else {
932 ca::post(std::move(c), bs::error_code{}, ret);
933 }
934 }
935
936
937 std::optional<uint64_t> RADOS::get_pool_alignment(int64_t pool_id)
938 {
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();
947 } else {
948 return std::nullopt;
949 }
950 });
951 }
952
953 void RADOS::list_pools(std::unique_ptr<LSPoolsComp> c) {
954 impl->objecter->with_osdmap(
955 [&](OSDMap& o) {
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));
960 });
961 }
962
963 void RADOS::create_pool_snap(std::int64_t pool,
964 std::string_view snapName,
965 std::unique_ptr<SimpleOpComp> c)
966 {
967 impl->objecter->create_pool_snap(
968 pool, snapName,
969 Objecter::PoolOp::OpComp::create(
970 get_executor(),
971 [c = std::move(c)](bs::error_code e, const bufferlist&) mutable {
972 ca::dispatch(std::move(c), e);
973 }));
974 }
975
976 void RADOS::allocate_selfmanaged_snap(int64_t pool,
977 std::unique_ptr<SMSnapComp> c) {
978 impl->objecter->allocate_selfmanaged_snap(
979 pool,
980 ca::Completion<void(bs::error_code, snapid_t)>::create(
981 get_executor(),
982 [c = std::move(c)](bs::error_code e, snapid_t snap) mutable {
983 ca::dispatch(std::move(c), e, snap);
984 }));
985 }
986
987 void RADOS::delete_pool_snap(std::int64_t pool,
988 std::string_view snapName,
989 std::unique_ptr<SimpleOpComp> c)
990 {
991 impl->objecter->delete_pool_snap(
992 pool, snapName,
993 Objecter::PoolOp::OpComp::create(
994 get_executor(),
995 [c = std::move(c)](bs::error_code e, const bufferlist&) mutable {
996 ca::dispatch(std::move(c), e);
997 }));
998 }
999
1000 void RADOS::delete_selfmanaged_snap(std::int64_t pool,
1001 std::uint64_t snap,
1002 std::unique_ptr<SimpleOpComp> c)
1003 {
1004 impl->objecter->delete_selfmanaged_snap(
1005 pool, snap,
1006 Objecter::PoolOp::OpComp::create(
1007 get_executor(),
1008 [c = std::move(c)](bs::error_code e, const bufferlist&) mutable {
1009 ca::dispatch(std::move(c), e);
1010 }));
1011 }
1012
1013 void RADOS::create_pool(std::string_view name,
1014 std::optional<int> crush_rule,
1015 std::unique_ptr<SimpleOpComp> c)
1016 {
1017 impl->objecter->create_pool(
1018 name,
1019 Objecter::PoolOp::OpComp::create(
1020 get_executor(),
1021 [c = std::move(c)](bs::error_code e, const bufferlist&) mutable {
1022 ca::dispatch(std::move(c), e);
1023 }),
1024 crush_rule.value_or(-1));
1025 }
1026
1027 void RADOS::delete_pool(std::string_view name,
1028 std::unique_ptr<SimpleOpComp> c)
1029 {
1030 impl->objecter->delete_pool(
1031 name,
1032 Objecter::PoolOp::OpComp::create(
1033 get_executor(),
1034 [c = std::move(c)](bs::error_code e, const bufferlist&) mutable {
1035 ca::dispatch(std::move(c), e);
1036 }));
1037 }
1038
1039 void RADOS::delete_pool(std::int64_t pool,
1040 std::unique_ptr<SimpleOpComp> c)
1041 {
1042 impl->objecter->delete_pool(
1043 pool,
1044 Objecter::PoolOp::OpComp::create(
1045 get_executor(),
1046 [c = std::move(c)](bs::error_code e, const bufferlist&) mutable {
1047 ca::dispatch(std::move(c), e);
1048 }));
1049 }
1050
1051 void RADOS::stat_pools(const std::vector<std::string>& pools,
1052 std::unique_ptr<PoolStatComp> c) {
1053 impl->objecter->get_pool_stats(
1054 pools,
1055 [c = std::move(c)]
1056 (bs::error_code ec,
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);
1071
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;
1089 }
1090
1091 ca::dispatch(std::move(c), ec, std::move(result), per_pool);
1092 });
1093 }
1094
1095 void RADOS::stat_fs(std::optional<std::int64_t> _pool,
1096 std::unique_ptr<StatFSComp> c) {
1097 std::optional<int64_t> pool;
1098 if (_pool)
1099 pool = *pool;
1100 impl->objecter->get_fs_stats(
1101 pool,
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));
1105 });
1106 }
1107
1108 // --- Watch/Notify
1109
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);
1115
1116 ObjectOperation op;
1117
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());
1123 bufferlist bl;
1124 impl->objecter->linger_watch(
1125 linger_op, op, ioc->snapc, ceph::real_clock::now(), bl,
1126 Objecter::LingerOp::OpComp::create(
1127 get_executor(),
1128 [c = std::move(c), cookie](bs::error_code e, cb::list) mutable {
1129 ca::dispatch(std::move(c), e, cookie);
1130 }), nullptr);
1131 }
1132
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;
1140 oloc.pool = pool;
1141 if (ns)
1142 oloc.nspace = *ns;
1143 if (key)
1144 oloc.key = *key;
1145
1146 ObjectOperation op;
1147
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());
1152 bufferlist bl;
1153 impl->objecter->linger_watch(
1154 linger_op, op, {}, ceph::real_clock::now(), bl,
1155 Objecter::LingerOp::OpComp::create(
1156 get_executor(),
1157 [c = std::move(c), cookie](bs::error_code e, bufferlist) mutable {
1158 ca::dispatch(std::move(c), e, cookie);
1159 }), nullptr);
1160 }
1161
1162 void RADOS::notify_ack(const Object& o,
1163 const IOContext& _ioc,
1164 uint64_t notify_id,
1165 uint64_t cookie,
1166 bufferlist&& bl,
1167 std::unique_ptr<SimpleOpComp> c)
1168 {
1169 auto oid = reinterpret_cast<const object_t*>(&o.impl);
1170 auto ioc = reinterpret_cast<const IOContextImpl*>(&_ioc.impl);
1171
1172 ObjectOperation op;
1173 op.notify_ack(notify_id, cookie, bl);
1174
1175 impl->objecter->read(*oid, ioc->oloc, std::move(op), ioc->snap_seq,
1176 nullptr, ioc->extra_op_flags, std::move(c));
1177 }
1178
1179 void RADOS::notify_ack(const Object& o,
1180 std::int64_t pool,
1181 uint64_t notify_id,
1182 uint64_t cookie,
1183 bufferlist&& bl,
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;
1189 oloc.pool = pool;
1190 if (ns)
1191 oloc.nspace = *ns;
1192 if (key)
1193 oloc.key = *key;
1194
1195 ObjectOperation op;
1196 op.notify_ack(notify_id, cookie, bl);
1197 impl->objecter->read(*oid, oloc, std::move(op), CEPH_NOSNAP, nullptr, 0,
1198 std::move(c));
1199 }
1200
1201 tl::expected<ceph::timespan, bs::error_code> RADOS::watch_check(uint64_t cookie)
1202 {
1203 Objecter::LingerOp *linger_op = reinterpret_cast<Objecter::LingerOp*>(cookie);
1204 return impl->objecter->linger_check(linger_op);
1205 }
1206
1207 void RADOS::unwatch(uint64_t cookie, const IOContext& _ioc,
1208 std::unique_ptr<SimpleOpComp> c)
1209 {
1210 auto ioc = reinterpret_cast<const IOContextImpl*>(&_ioc.impl);
1211
1212 Objecter::LingerOp *linger_op = reinterpret_cast<Objecter::LingerOp*>(cookie);
1213
1214 ObjectOperation op;
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(
1219 get_executor(),
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);
1225 }));
1226 }
1227
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)
1232 {
1233 object_locator_t oloc;
1234 oloc.pool = pool;
1235 if (ns)
1236 oloc.nspace = *ns;
1237 if (key)
1238 oloc.key = *key;
1239
1240 Objecter::LingerOp *linger_op = reinterpret_cast<Objecter::LingerOp*>(cookie);
1241
1242 ObjectOperation op;
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(
1247 get_executor(),
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);
1253 }));
1254 }
1255
1256 void RADOS::flush_watch(std::unique_ptr<VoidOpComp> c)
1257 {
1258 impl->objecter->linger_callback_flush([c = std::move(c)]() mutable {
1259 ca::post(std::move(c));
1260 });
1261 }
1262
1263 struct NotifyHandler : std::enable_shared_from_this<NotifyHandler> {
1264 boost::asio::io_context& ioc;
1265 boost::asio::io_context::strand strand;
1266 Objecter* objecter;
1267 Objecter::LingerOp* op;
1268 std::unique_ptr<RADOS::NotifyComp> c;
1269
1270 bool acked = false;
1271 bool finished = false;
1272 bs::error_code res;
1273 bufferlist rbl;
1274
1275 NotifyHandler(boost::asio::io_context& ioc,
1276 Objecter* objecter,
1277 Objecter::LingerOp* op,
1278 std::unique_ptr<RADOS::NotifyComp> c)
1279 : ioc(ioc), strand(ioc), objecter(objecter), op(op), c(std::move(c)) {}
1280
1281 // Use bind or a lambda to pass this in.
1282 void handle_ack(bs::error_code ec,
1283 bufferlist&&) {
1284 boost::asio::post(
1285 strand,
1286 [this, ec, p = shared_from_this()]() mutable {
1287 acked = true;
1288 maybe_cleanup(ec);
1289 });
1290 }
1291
1292 // Notify finish callback. It can actually own the object's storage.
1293
1294 void operator()(bs::error_code ec,
1295 bufferlist&& bl) {
1296 boost::asio::post(
1297 strand,
1298 [this, ec, p = shared_from_this()]() mutable {
1299 finished = true;
1300 maybe_cleanup(ec);
1301 });
1302 }
1303
1304 // Should be called from strand.
1305 void maybe_cleanup(bs::error_code ec) {
1306 if (!res && ec)
1307 res = ec;
1308 if ((acked && finished) || res) {
1309 objecter->linger_cancel(op);
1310 ceph_assert(c);
1311 ca::dispatch(std::move(c), res, std::move(rbl));
1312 }
1313 }
1314 };
1315
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)
1319 {
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);
1324
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(
1329 get_executor(),
1330 [cb](bs::error_code ec, ceph::bufferlist bl) mutable {
1331 (*cb)(ec, std::move(bl));
1332 });
1333 ObjectOperation rd;
1334 bufferlist inbl;
1335 rd.notify(
1336 linger_op->get_cookie(), 1,
1337 timeout ? timeout->count() : impl->cct->_conf->client_notify_timeout,
1338 bl, &inbl);
1339
1340 impl->objecter->linger_notify(
1341 linger_op, rd, ioc->snap_seq, inbl,
1342 Objecter::LingerOp::OpComp::create(
1343 get_executor(),
1344 [cb](bs::error_code ec, ceph::bufferlist bl) mutable {
1345 cb->handle_ack(ec, std::move(bl));
1346 }), nullptr);
1347 }
1348
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)
1354 {
1355 auto oid = reinterpret_cast<const object_t*>(&o.impl);
1356 object_locator_t oloc;
1357 oloc.pool = pool;
1358 if (ns)
1359 oloc.nspace = *ns;
1360 if (key)
1361 oloc.key = *key;
1362 auto linger_op = impl->objecter->linger_register(*oid, oloc, 0);
1363
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(
1368 get_executor(),
1369 [cb](bs::error_code ec, ceph::bufferlist&& bl) mutable {
1370 (*cb)(ec, std::move(bl));
1371 });
1372 ObjectOperation rd;
1373 bufferlist inbl;
1374 rd.notify(
1375 linger_op->get_cookie(), 1,
1376 timeout ? timeout->count() : impl->cct->_conf->client_notify_timeout,
1377 bl, &inbl);
1378
1379 impl->objecter->linger_notify(
1380 linger_op, rd, CEPH_NOSNAP, inbl,
1381 Objecter::LingerOp::OpComp::create(
1382 get_executor(),
1383 [cb](bs::error_code ec, bufferlist&& bl) mutable {
1384 cb->handle_ack(ec, std::move(bl));
1385 }), nullptr);
1386 }
1387
1388 // Enumeration
1389
1390 Cursor::Cursor() {
1391 static_assert(impl_size >= sizeof(hobject_t));
1392 new (&impl) hobject_t();
1393 };
1394
1395 Cursor::Cursor(end_magic_t) {
1396 static_assert(impl_size >= sizeof(hobject_t));
1397 new (&impl) hobject_t(hobject_t::get_max());
1398 }
1399
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)));
1403 }
1404
1405 Cursor Cursor::begin() {
1406 Cursor e;
1407 return e;
1408 }
1409
1410 Cursor Cursor::end() {
1411 Cursor e(end_magic_t{});
1412 return e;
1413 }
1414
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));
1418 }
1419
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));
1424 return *this;
1425 }
1426
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)));
1430 }
1431
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)));
1436 return *this;
1437 }
1438 Cursor::~Cursor() {
1439 reinterpret_cast<hobject_t*>(&impl)->~hobject_t();
1440 }
1441
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));
1445 }
1446
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));
1450 }
1451
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));
1455 }
1456
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));
1460 }
1461
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));
1465 }
1466
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));
1470 }
1471
1472 std::string Cursor::to_str() const {
1473 using namespace std::literals;
1474 auto& h = *reinterpret_cast<const hobject_t*>(&impl);
1475
1476 return h.is_max() ? "MAX"s : h.to_str();
1477 }
1478
1479 std::optional<Cursor>
1480 Cursor::from_str(const std::string& s) {
1481 Cursor e;
1482 auto& h = *reinterpret_cast<hobject_t*>(&e.impl);
1483 if (!h.parse(s))
1484 return std::nullopt;
1485
1486 return e;
1487 }
1488
1489 void RADOS::enumerate_objects(const IOContext& _ioc,
1490 const Cursor& begin,
1491 const Cursor& end,
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);
1496
1497 impl->objecter->enumerate_objects<Entry>(
1498 ioc->oloc.pool,
1499 ioc->oloc.nspace,
1500 *reinterpret_cast<const hobject_t*>(&begin.impl),
1501 *reinterpret_cast<const hobject_t*>(&end.impl),
1502 max,
1503 filter,
1504 [c = std::move(c)]
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)));
1509 });
1510 }
1511
1512 void RADOS::enumerate_objects(std::int64_t pool,
1513 const Cursor& begin,
1514 const Cursor& end,
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>(
1521 pool,
1522 ns ? *ns : std::string_view{},
1523 *reinterpret_cast<const hobject_t*>(&begin.impl),
1524 *reinterpret_cast<const hobject_t*>(&end.impl),
1525 max,
1526 filter,
1527 [c = std::move(c)]
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)));
1532 });
1533 }
1534
1535
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,
1539 [c = std::move(c)]
1540 (bs::error_code ec,
1541 std::string&& s,
1542 ceph::bufferlist&& b) mutable {
1543 ca::dispatch(std::move(c), ec,
1544 std::move(s),
1545 std::move(b));
1546 });
1547 }
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,
1551 [c = std::move(c)]
1552 (bs::error_code ec,
1553 std::string&& s,
1554 ceph::bufferlist&& b) mutable {
1555 ca::dispatch(std::move(c), ec,
1556 std::move(s),
1557 std::move(b));
1558 });
1559 }
1560
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));
1568 } else {
1569 impl->monclient.start_mon_command(
1570 { fmt::format("{{ \"prefix\": \"osd pool application enable\","
1571 "\"pool\": \"{}\", \"app\": \"{}\"{}}}",
1572 pool, app_name,
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);
1577 });
1578 }
1579 }
1580
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(
1587 { fmt::format("{{"
1588 "\"prefix\": \"osd blocklist\", "
1589 "\"blocklistop\": \"add\", "
1590 "\"addr\": \"{}\"{}}}",
1591 client_address, expire_arg) },
1592 {},
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);
1597 return;
1598 }
1599
1600 // retry using the legacy command
1601 impl->monclient.start_mon_command(
1602 { fmt::format("{{"
1603 "\"prefix\": \"osd blacklist\", "
1604 "\"blacklistop\": \"add\", "
1605 "\"addr\": \"{}\"{}}}",
1606 client_address, expire_arg) },
1607 {},
1608 [c = std::move(c)](bs::error_code ec, std::string, cb::list) mutable {
1609 ca::post(std::move(c), ec);
1610 });
1611 });
1612 }
1613
1614 void RADOS::wait_for_latest_osd_map(std::unique_ptr<SimpleOpComp> c) {
1615 impl->objecter->wait_for_latest_osdmap(std::move(c));
1616 }
1617
1618 void RADOS::mon_command(std::vector<std::string> command,
1619 const cb::list& bl,
1620 std::string* outs, cb::list* outbl,
1621 std::unique_ptr<SimpleOpComp> c) {
1622
1623 impl->monclient.start_mon_command(
1624 command, bl,
1625 [c = std::move(c), outs, outbl](bs::error_code e,
1626 std::string s, cb::list bl) mutable {
1627 if (outs)
1628 *outs = std::move(s);
1629 if (outbl)
1630 *outbl = std::move(bl);
1631 ca::post(std::move(c), e);
1632 });
1633 }
1634
1635 uint64_t RADOS::instance_id() const {
1636 return impl->get_instance_id();
1637 }
1638
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 {
1644 public:
1645 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
1650 override;
1651 bool equivalent(int ev, const bs::error_condition& c) const
1652 noexcept override;
1653 using ceph::converting_category::equivalent;
1654 int from_code(int ev) const noexcept override;
1655 };
1656 #pragma GCC diagnostic pop
1657 #pragma clang diagnostic pop
1658
1659 const char* category::name() const noexcept {
1660 return "RADOS";
1661 }
1662
1663 const char* category::message(int ev, char*,
1664 std::size_t) const noexcept {
1665 if (ev == 0)
1666 return "No error";
1667
1668 switch (static_cast<errc>(ev)) {
1669 case errc::pool_dne:
1670 return "Pool does not exist";
1671
1672 case errc::invalid_snapcontext:
1673 return "Invalid snapcontext";
1674 }
1675
1676 return "Unknown error";
1677 }
1678
1679 std::string category::message(int ev) const {
1680 return message(ev, nullptr, 0);
1681 }
1682
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;
1689 }
1690
1691 return { ev, *this };
1692 }
1693
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) {
1697 return true;
1698 }
1699 }
1700
1701 return default_error_condition(ev) == c;
1702 }
1703
1704 int category::from_code(int ev) const noexcept {
1705 switch (static_cast<errc>(ev)) {
1706 case errc::pool_dne:
1707 return -ENOENT;
1708 case errc::invalid_snapcontext:
1709 return -EINVAL;
1710 }
1711 return -EDOM;
1712 }
1713
1714 const bs::error_category& error_category() noexcept {
1715 static const class category c;
1716 return c;
1717 }
1718
1719 CephContext* RADOS::cct() {
1720 return impl->cct.get();
1721 }
1722 }
1723
1724 namespace std {
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));
1729 }
1730
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);
1737 }
1738 }