]> git.proxmox.com Git - ceph.git/blob - ceph/src/neorados/RADOS.cc
import quincy beta 17.1.0
[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 namespace bc = boost::container;
41 namespace bs = boost::system;
42 namespace ca = ceph::async;
43 namespace cb = ceph::buffer;
44
45 namespace neorados {
46 // Object
47
48 Object::Object() {
49 static_assert(impl_size >= sizeof(object_t));
50 new (&impl) object_t();
51 }
52
53 Object::Object(const char* s) {
54 static_assert(impl_size >= sizeof(object_t));
55 new (&impl) object_t(s);
56 }
57
58 Object::Object(std::string_view s) {
59 static_assert(impl_size >= sizeof(object_t));
60 new (&impl) object_t(s);
61 }
62
63 Object::Object(std::string&& s) {
64 static_assert(impl_size >= sizeof(object_t));
65 new (&impl) object_t(std::move(s));
66 }
67
68 Object::Object(const std::string& s) {
69 static_assert(impl_size >= sizeof(object_t));
70 new (&impl) object_t(s);
71 }
72
73 Object::~Object() {
74 reinterpret_cast<object_t*>(&impl)->~object_t();
75 }
76
77 Object::Object(const Object& o) {
78 static_assert(impl_size >= sizeof(object_t));
79 new (&impl) object_t(*reinterpret_cast<const object_t*>(&o.impl));
80 }
81 Object& Object::operator =(const Object& o) {
82 *reinterpret_cast<object_t*>(&impl) =
83 *reinterpret_cast<const object_t*>(&o.impl);
84 return *this;
85 }
86 Object::Object(Object&& o) {
87 static_assert(impl_size >= sizeof(object_t));
88 new (&impl) object_t(std::move(*reinterpret_cast<object_t*>(&o.impl)));
89 }
90 Object& Object::operator =(Object&& o) {
91 *reinterpret_cast<object_t*>(&impl) =
92 std::move(*reinterpret_cast<object_t*>(&o.impl));
93 return *this;
94 }
95
96 Object::operator std::string_view() const {
97 return std::string_view(reinterpret_cast<const object_t*>(&impl)->name);
98 }
99
100 bool operator <(const Object& lhs, const Object& rhs) {
101 return (*reinterpret_cast<const object_t*>(&lhs.impl) <
102 *reinterpret_cast<const object_t*>(&rhs.impl));
103 }
104 bool operator <=(const Object& lhs, const Object& rhs) {
105 return (*reinterpret_cast<const object_t*>(&lhs.impl) <=
106 *reinterpret_cast<const object_t*>(&rhs.impl));
107 }
108 bool operator >=(const Object& lhs, const Object& rhs) {
109 return (*reinterpret_cast<const object_t*>(&lhs.impl) >=
110 *reinterpret_cast<const object_t*>(&rhs.impl));
111 }
112 bool operator >(const Object& lhs, const Object& rhs) {
113 return (*reinterpret_cast<const object_t*>(&lhs.impl) >
114 *reinterpret_cast<const object_t*>(&rhs.impl));
115 }
116
117 bool operator ==(const Object& lhs, const Object& rhs) {
118 return (*reinterpret_cast<const object_t*>(&lhs.impl) ==
119 *reinterpret_cast<const object_t*>(&rhs.impl));
120 }
121 bool operator !=(const Object& lhs, const Object& rhs) {
122 return (*reinterpret_cast<const object_t*>(&lhs.impl) !=
123 *reinterpret_cast<const object_t*>(&rhs.impl));
124 }
125
126 std::ostream& operator <<(std::ostream& m, const Object& o) {
127 return (m << *reinterpret_cast<const object_t*>(&o.impl));
128 }
129
130 // IOContext
131
132 struct IOContextImpl {
133 object_locator_t oloc;
134 snapid_t snap_seq = CEPH_NOSNAP;
135 SnapContext snapc;
136 int extra_op_flags = 0;
137 };
138
139 IOContext::IOContext() {
140 static_assert(impl_size >= sizeof(IOContextImpl));
141 new (&impl) IOContextImpl();
142 }
143
144 IOContext::IOContext(std::int64_t _pool) : IOContext() {
145 pool(_pool);
146 }
147
148 IOContext::IOContext(std::int64_t _pool, std::string_view _ns)
149 : IOContext() {
150 pool(_pool);
151 ns(_ns);
152 }
153
154 IOContext::IOContext(std::int64_t _pool, std::string&& _ns)
155 : IOContext() {
156 pool(_pool);
157 ns(std::move(_ns));
158 }
159
160 IOContext::~IOContext() {
161 reinterpret_cast<IOContextImpl*>(&impl)->~IOContextImpl();
162 }
163
164 IOContext::IOContext(const IOContext& rhs) {
165 static_assert(impl_size >= sizeof(IOContextImpl));
166 new (&impl) IOContextImpl(*reinterpret_cast<const IOContextImpl*>(&rhs.impl));
167 }
168
169 IOContext& IOContext::operator =(const IOContext& rhs) {
170 *reinterpret_cast<IOContextImpl*>(&impl) =
171 *reinterpret_cast<const IOContextImpl*>(&rhs.impl);
172 return *this;
173 }
174
175 IOContext::IOContext(IOContext&& rhs) {
176 static_assert(impl_size >= sizeof(IOContextImpl));
177 new (&impl) IOContextImpl(
178 std::move(*reinterpret_cast<IOContextImpl*>(&rhs.impl)));
179 }
180
181 IOContext& IOContext::operator =(IOContext&& rhs) {
182 *reinterpret_cast<IOContextImpl*>(&impl) =
183 std::move(*reinterpret_cast<IOContextImpl*>(&rhs.impl));
184 return *this;
185 }
186
187 std::int64_t IOContext::pool() const {
188 return reinterpret_cast<const IOContextImpl*>(&impl)->oloc.pool;
189 }
190
191 void IOContext::pool(std::int64_t _pool) {
192 reinterpret_cast<IOContextImpl*>(&impl)->oloc.pool = _pool;
193 }
194
195 std::string_view IOContext::ns() const {
196 return reinterpret_cast<const IOContextImpl*>(&impl)->oloc.nspace;
197 }
198
199 void IOContext::ns(std::string_view _ns) {
200 reinterpret_cast<IOContextImpl*>(&impl)->oloc.nspace = _ns;
201 }
202
203 void IOContext::ns(std::string&& _ns) {
204 reinterpret_cast<IOContextImpl*>(&impl)->oloc.nspace = std::move(_ns);
205 }
206
207 std::optional<std::string_view> IOContext::key() const {
208 auto& oloc = reinterpret_cast<const IOContextImpl*>(&impl)->oloc;
209 if (oloc.key.empty())
210 return std::nullopt;
211 else
212 return std::string_view(oloc.key);
213 }
214
215 void IOContext::key(std::string_view _key) {
216 auto& oloc = reinterpret_cast<IOContextImpl*>(&impl)->oloc;
217 oloc.hash = -1;
218 oloc.key = _key;
219 }
220
221 void IOContext::key(std::string&&_key) {
222 auto& oloc = reinterpret_cast<IOContextImpl*>(&impl)->oloc;
223 oloc.hash = -1;
224 oloc.key = std::move(_key);
225 }
226
227 void IOContext::clear_key() {
228 auto& oloc = reinterpret_cast<IOContextImpl*>(&impl)->oloc;
229 oloc.hash = -1;
230 oloc.key.clear();
231 }
232
233 std::optional<std::int64_t> IOContext::hash() const {
234 auto& oloc = reinterpret_cast<const IOContextImpl*>(&impl)->oloc;
235 if (oloc.hash < 0)
236 return std::nullopt;
237 else
238 return oloc.hash;
239 }
240
241 void IOContext::hash(std::int64_t _hash) {
242 auto& oloc = reinterpret_cast<IOContextImpl*>(&impl)->oloc;
243 oloc.hash = _hash;
244 oloc.key.clear();
245 }
246
247 void IOContext::clear_hash() {
248 auto& oloc = reinterpret_cast<IOContextImpl*>(&impl)->oloc;
249 oloc.hash = -1;
250 oloc.key.clear();
251 }
252
253
254 std::optional<std::uint64_t> IOContext::read_snap() const {
255 auto& snap_seq = reinterpret_cast<const IOContextImpl*>(&impl)->snap_seq;
256 if (snap_seq == CEPH_NOSNAP)
257 return std::nullopt;
258 else
259 return snap_seq;
260 }
261 void IOContext::read_snap(std::optional<std::uint64_t> _snapid) {
262 auto& snap_seq = reinterpret_cast<IOContextImpl*>(&impl)->snap_seq;
263 snap_seq = _snapid.value_or(CEPH_NOSNAP);
264 }
265
266 std::optional<
267 std::pair<std::uint64_t,
268 std::vector<std::uint64_t>>> IOContext::write_snap_context() const {
269 auto& snapc = reinterpret_cast<const IOContextImpl*>(&impl)->snapc;
270 if (snapc.empty()) {
271 return std::nullopt;
272 } else {
273 std::vector<uint64_t> v(snapc.snaps.begin(), snapc.snaps.end());
274 return std::make_optional(std::make_pair(uint64_t(snapc.seq), v));
275 }
276 }
277
278 void IOContext::write_snap_context(
279 std::optional<std::pair<std::uint64_t, std::vector<std::uint64_t>>> _snapc) {
280 auto& snapc = reinterpret_cast<IOContextImpl*>(&impl)->snapc;
281 if (!_snapc) {
282 snapc.clear();
283 } else {
284 SnapContext n(_snapc->first, { _snapc->second.begin(), _snapc->second.end()});
285 if (!n.is_valid()) {
286 throw bs::system_error(EINVAL,
287 bs::system_category(),
288 "Invalid snap context.");
289
290 } else {
291 snapc = n;
292 }
293 }
294 }
295
296 bool IOContext::full_try() const {
297 const auto ioc = reinterpret_cast<const IOContextImpl*>(&impl);
298 return (ioc->extra_op_flags & CEPH_OSD_FLAG_FULL_TRY) != 0;
299 }
300
301 void IOContext::full_try(bool _full_try) {
302 auto ioc = reinterpret_cast<IOContextImpl*>(&impl);
303 if (_full_try) {
304 ioc->extra_op_flags |= CEPH_OSD_FLAG_FULL_TRY;
305 } else {
306 ioc->extra_op_flags &= ~CEPH_OSD_FLAG_FULL_TRY;
307 }
308 }
309
310 bool operator <(const IOContext& lhs, const IOContext& rhs) {
311 const auto l = reinterpret_cast<const IOContextImpl*>(&lhs.impl);
312 const auto r = reinterpret_cast<const IOContextImpl*>(&rhs.impl);
313
314 return (std::tie(l->oloc.pool, l->oloc.nspace, l->oloc.key) <
315 std::tie(r->oloc.pool, r->oloc.nspace, r->oloc.key));
316 }
317
318 bool operator <=(const IOContext& lhs, const IOContext& rhs) {
319 const auto l = reinterpret_cast<const IOContextImpl*>(&lhs.impl);
320 const auto r = reinterpret_cast<const IOContextImpl*>(&rhs.impl);
321
322 return (std::tie(l->oloc.pool, l->oloc.nspace, l->oloc.key) <=
323 std::tie(r->oloc.pool, r->oloc.nspace, r->oloc.key));
324 }
325
326 bool operator >=(const IOContext& lhs, const IOContext& rhs) {
327 const auto l = reinterpret_cast<const IOContextImpl*>(&lhs.impl);
328 const auto r = reinterpret_cast<const IOContextImpl*>(&rhs.impl);
329
330 return (std::tie(l->oloc.pool, l->oloc.nspace, l->oloc.key) >=
331 std::tie(r->oloc.pool, r->oloc.nspace, r->oloc.key));
332 }
333
334 bool operator >(const IOContext& lhs, const IOContext& rhs) {
335 const auto l = reinterpret_cast<const IOContextImpl*>(&lhs.impl);
336 const auto r = reinterpret_cast<const IOContextImpl*>(&rhs.impl);
337
338 return (std::tie(l->oloc.pool, l->oloc.nspace, l->oloc.key) >
339 std::tie(r->oloc.pool, r->oloc.nspace, r->oloc.key));
340 }
341
342 bool operator ==(const IOContext& lhs, const IOContext& rhs) {
343 const auto l = reinterpret_cast<const IOContextImpl*>(&lhs.impl);
344 const auto r = reinterpret_cast<const IOContextImpl*>(&rhs.impl);
345
346 return (std::tie(l->oloc.pool, l->oloc.nspace, l->oloc.key) ==
347 std::tie(r->oloc.pool, r->oloc.nspace, r->oloc.key));
348 }
349
350 bool operator !=(const IOContext& lhs, const IOContext& rhs) {
351 const auto l = reinterpret_cast<const IOContextImpl*>(&lhs.impl);
352 const auto r = reinterpret_cast<const IOContextImpl*>(&rhs.impl);
353
354 return (std::tie(l->oloc.pool, l->oloc.nspace, l->oloc.key) !=
355 std::tie(r->oloc.pool, r->oloc.nspace, r->oloc.key));
356 }
357
358 std::ostream& operator <<(std::ostream& m, const IOContext& o) {
359 const auto l = reinterpret_cast<const IOContextImpl*>(&o.impl);
360 return (m << l->oloc.pool << ":" << l->oloc.nspace << ":" << l->oloc.key);
361 }
362
363
364 // Op
365
366 struct OpImpl {
367 ObjectOperation op;
368 std::optional<ceph::real_time> mtime;
369
370 OpImpl() = default;
371
372 OpImpl(const OpImpl& rhs) = delete;
373 OpImpl(OpImpl&& rhs) = default;
374
375 OpImpl& operator =(const OpImpl& rhs) = delete;
376 OpImpl& operator =(OpImpl&& rhs) = default;
377 };
378
379 Op::Op() {
380 static_assert(Op::impl_size >= sizeof(OpImpl));
381 new (&impl) OpImpl;
382 }
383
384 Op::Op(Op&& rhs) {
385 new (&impl) OpImpl(std::move(*reinterpret_cast<OpImpl*>(&rhs.impl)));
386 }
387 Op& Op::operator =(Op&& rhs) {
388 reinterpret_cast<OpImpl*>(&impl)->~OpImpl();
389 new (&impl) OpImpl(std::move(*reinterpret_cast<OpImpl*>(&rhs.impl)));
390 return *this;
391 }
392 Op::~Op() {
393 reinterpret_cast<OpImpl*>(&impl)->~OpImpl();
394 }
395
396 void Op::set_excl() {
397 reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags(CEPH_OSD_OP_FLAG_EXCL);
398 }
399 void Op::set_failok() {
400 reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags(
401 CEPH_OSD_OP_FLAG_FAILOK);
402 }
403 void Op::set_fadvise_random() {
404 reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags(
405 CEPH_OSD_OP_FLAG_FADVISE_RANDOM);
406 }
407 void Op::set_fadvise_sequential() {
408 reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags(
409 CEPH_OSD_OP_FLAG_FADVISE_SEQUENTIAL);
410 }
411 void Op::set_fadvise_willneed() {
412 reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags(
413 CEPH_OSD_OP_FLAG_FADVISE_WILLNEED);
414 }
415 void Op::set_fadvise_dontneed() {
416 reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags(
417 CEPH_OSD_OP_FLAG_FADVISE_DONTNEED);
418 }
419 void Op::set_fadvise_nocache() {
420 reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags(
421 CEPH_OSD_OP_FLAG_FADVISE_NOCACHE);
422 }
423
424 void Op::cmpext(uint64_t off, bufferlist&& cmp_bl, std::size_t* s) {
425 reinterpret_cast<OpImpl*>(&impl)->op.cmpext(off, std::move(cmp_bl), nullptr,
426 s);
427 }
428 void Op::cmpxattr(std::string_view name, cmpxattr_op op, const bufferlist& val) {
429 reinterpret_cast<OpImpl*>(&impl)->
430 op.cmpxattr(name, std::uint8_t(op), CEPH_OSD_CMPXATTR_MODE_STRING, val);
431 }
432 void Op::cmpxattr(std::string_view name, cmpxattr_op op, std::uint64_t val) {
433 bufferlist bl;
434 encode(val, bl);
435 reinterpret_cast<OpImpl*>(&impl)->
436 op.cmpxattr(name, std::uint8_t(op), CEPH_OSD_CMPXATTR_MODE_U64, bl);
437 }
438
439 void Op::assert_version(uint64_t ver) {
440 reinterpret_cast<OpImpl*>(&impl)->op.assert_version(ver);
441 }
442 void Op::assert_exists() {
443 reinterpret_cast<OpImpl*>(&impl)->op.stat(
444 nullptr,
445 static_cast<ceph::real_time*>(nullptr),
446 static_cast<bs::error_code*>(nullptr));
447 }
448 void Op::cmp_omap(const bc::flat_map<
449 std::string, std::pair<cb::list,
450 int>>& assertions) {
451 reinterpret_cast<OpImpl*>(&impl)->op.omap_cmp(assertions, nullptr);
452 }
453
454 void Op::exec(std::string_view cls, std::string_view method,
455 const bufferlist& inbl,
456 cb::list* out,
457 bs::error_code* ec) {
458 reinterpret_cast<OpImpl*>(&impl)->op.call(cls, method, inbl, ec, out);
459 }
460
461 void Op::exec(std::string_view cls, std::string_view method,
462 const bufferlist& inbl,
463 fu2::unique_function<void(bs::error_code,
464 const cb::list&) &&> f) {
465 reinterpret_cast<OpImpl*>(&impl)->op.call(cls, method, inbl, std::move(f));
466 }
467
468 void Op::exec(std::string_view cls, std::string_view method,
469 const bufferlist& inbl,
470 fu2::unique_function<void(bs::error_code, int,
471 const cb::list&) &&> f) {
472 reinterpret_cast<OpImpl*>(&impl)->op.call(cls, method, inbl, std::move(f));
473 }
474
475 void Op::exec(std::string_view cls, std::string_view method,
476 const bufferlist& inbl, bs::error_code* ec) {
477 reinterpret_cast<OpImpl*>(&impl)->op.call(cls, method, inbl, ec);
478 }
479
480 void Op::balance_reads() {
481 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_BALANCE_READS;
482 }
483 void Op::localize_reads() {
484 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_LOCALIZE_READS;
485 }
486 void Op::order_reads_writes() {
487 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_RWORDERED;
488 }
489 void Op::ignore_cache() {
490 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_IGNORE_CACHE;
491 }
492 void Op::skiprwlocks() {
493 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_SKIPRWLOCKS;
494 }
495 void Op::ignore_overlay() {
496 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_IGNORE_OVERLAY;
497 }
498 void Op::full_try() {
499 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_FULL_TRY;
500 }
501 void Op::full_force() {
502 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_FULL_FORCE;
503 }
504 void Op::ignore_redirect() {
505 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_IGNORE_REDIRECT;
506 }
507 void Op::ordersnap() {
508 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_ORDERSNAP;
509 }
510 void Op::returnvec() {
511 reinterpret_cast<OpImpl*>(&impl)->op.flags |= CEPH_OSD_FLAG_RETURNVEC;
512 }
513
514 std::size_t Op::size() const {
515 return reinterpret_cast<const OpImpl*>(&impl)->op.size();
516 }
517
518 std::ostream& operator <<(std::ostream& m, const Op& o) {
519 return m << reinterpret_cast<const OpImpl*>(&o.impl)->op;
520 }
521
522
523 // ---
524
525 // ReadOp / WriteOp
526
527 void ReadOp::read(size_t off, uint64_t len, cb::list* out,
528 bs::error_code* ec) {
529 reinterpret_cast<OpImpl*>(&impl)->op.read(off, len, ec, out);
530 }
531
532 void ReadOp::get_xattr(std::string_view name, cb::list* out,
533 bs::error_code* ec) {
534 reinterpret_cast<OpImpl*>(&impl)->op.getxattr(name, ec, out);
535 }
536
537 void ReadOp::get_omap_header(cb::list* out,
538 bs::error_code* ec) {
539 reinterpret_cast<OpImpl*>(&impl)->op.omap_get_header(ec, out);
540 }
541
542 void ReadOp::sparse_read(uint64_t off, uint64_t len, cb::list* out,
543 std::vector<std::pair<std::uint64_t,
544 std::uint64_t>>* extents,
545 bs::error_code* ec) {
546 reinterpret_cast<OpImpl*>(&impl)->op.sparse_read(off, len, ec, extents, out);
547 }
548
549 void ReadOp::stat(std::uint64_t* size, ceph::real_time* mtime,
550 bs::error_code* ec) {
551 reinterpret_cast<OpImpl*>(&impl)->op.stat(size, mtime, ec);
552 }
553
554 void ReadOp::get_omap_keys(std::optional<std::string_view> start_after,
555 std::uint64_t max_return,
556 bc::flat_set<std::string>* keys,
557 bool* done,
558 bs::error_code* ec) {
559 reinterpret_cast<OpImpl*>(&impl)->op.omap_get_keys(start_after, max_return,
560 ec, keys, done);
561 }
562
563 void ReadOp::get_xattrs(bc::flat_map<std::string,
564 cb::list>* kv,
565 bs::error_code* ec) {
566 reinterpret_cast<OpImpl*>(&impl)->op.getxattrs(ec, kv);
567 }
568
569 void ReadOp::get_omap_vals(std::optional<std::string_view> start_after,
570 std::optional<std::string_view> filter_prefix,
571 uint64_t max_return,
572 bc::flat_map<std::string,
573 cb::list>* kv,
574 bool* done,
575 bs::error_code* ec) {
576 reinterpret_cast<OpImpl*>(&impl)->op.omap_get_vals(start_after, filter_prefix,
577 max_return, ec, kv, done);
578 }
579
580 void ReadOp::get_omap_vals_by_keys(
581 const bc::flat_set<std::string>& keys,
582 bc::flat_map<std::string, cb::list>* kv,
583 bs::error_code* ec) {
584 reinterpret_cast<OpImpl*>(&impl)->op.omap_get_vals_by_keys(keys, ec, kv);
585 }
586
587 void ReadOp::list_watchers(std::vector<ObjWatcher>* watchers,
588 bs::error_code* ec) {
589 reinterpret_cast<OpImpl*>(&impl)-> op.list_watchers(watchers, ec);
590 }
591
592 void ReadOp::list_snaps(SnapSet* snaps,
593 bs::error_code* ec) {
594 reinterpret_cast<OpImpl*>(&impl)->op.list_snaps(snaps, nullptr, ec);
595 }
596
597 // WriteOp
598
599 void WriteOp::set_mtime(ceph::real_time t) {
600 auto o = reinterpret_cast<OpImpl*>(&impl);
601 o->mtime = t;
602 }
603
604 void WriteOp::create(bool exclusive) {
605 reinterpret_cast<OpImpl*>(&impl)->op.create(exclusive);
606 }
607
608 void WriteOp::write(uint64_t off, bufferlist&& bl) {
609 reinterpret_cast<OpImpl*>(&impl)->op.write(off, bl);
610 }
611
612 void WriteOp::write_full(bufferlist&& bl) {
613 reinterpret_cast<OpImpl*>(&impl)->op.write_full(bl);
614 }
615
616 void WriteOp::writesame(uint64_t off, uint64_t write_len, bufferlist&& bl) {
617 reinterpret_cast<OpImpl*>(&impl)->op.writesame(off, write_len, bl);
618 }
619
620 void WriteOp::append(bufferlist&& bl) {
621 reinterpret_cast<OpImpl*>(&impl)->op.append(bl);
622 }
623
624 void WriteOp::remove() {
625 reinterpret_cast<OpImpl*>(&impl)->op.remove();
626 }
627
628 void WriteOp::truncate(uint64_t off) {
629 reinterpret_cast<OpImpl*>(&impl)->op.truncate(off);
630 }
631
632 void WriteOp::zero(uint64_t off, uint64_t len) {
633 reinterpret_cast<OpImpl*>(&impl)->op.zero(off, len);
634 }
635
636 void WriteOp::rmxattr(std::string_view name) {
637 reinterpret_cast<OpImpl*>(&impl)->op.rmxattr(name);
638 }
639
640 void WriteOp::setxattr(std::string_view name,
641 bufferlist&& bl) {
642 reinterpret_cast<OpImpl*>(&impl)->op.setxattr(name, bl);
643 }
644
645 void WriteOp::rollback(uint64_t snapid) {
646 reinterpret_cast<OpImpl*>(&impl)->op.rollback(snapid);
647 }
648
649 void WriteOp::set_omap(
650 const bc::flat_map<std::string, cb::list>& map) {
651 reinterpret_cast<OpImpl*>(&impl)->op.omap_set(map);
652 }
653
654 void WriteOp::set_omap_header(bufferlist&& bl) {
655 reinterpret_cast<OpImpl*>(&impl)->op.omap_set_header(bl);
656 }
657
658 void WriteOp::clear_omap() {
659 reinterpret_cast<OpImpl*>(&impl)->op.omap_clear();
660 }
661
662 void WriteOp::rm_omap_keys(
663 const bc::flat_set<std::string>& to_rm) {
664 reinterpret_cast<OpImpl*>(&impl)->op.omap_rm_keys(to_rm);
665 }
666
667 void WriteOp::set_alloc_hint(uint64_t expected_object_size,
668 uint64_t expected_write_size,
669 alloc_hint::alloc_hint_t flags) {
670 using namespace alloc_hint;
671 static_assert(sequential_write ==
672 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_WRITE));
673 static_assert(random_write ==
674 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_WRITE));
675 static_assert(sequential_read ==
676 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ));
677 static_assert(random_read ==
678 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_READ));
679 static_assert(append_only ==
680 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_APPEND_ONLY));
681 static_assert(immutable ==
682 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_IMMUTABLE));
683 static_assert(shortlived ==
684 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_SHORTLIVED));
685 static_assert(longlived ==
686 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_LONGLIVED));
687 static_assert(compressible ==
688 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_COMPRESSIBLE));
689 static_assert(incompressible ==
690 static_cast<int>(CEPH_OSD_ALLOC_HINT_FLAG_INCOMPRESSIBLE));
691
692 reinterpret_cast<OpImpl*>(&impl)->op.set_alloc_hint(expected_object_size,
693 expected_write_size,
694 flags);
695 }
696
697 // RADOS
698
699 RADOS::Builder& RADOS::Builder::add_conf_file(std::string_view f) {
700 if (conf_files)
701 *conf_files += (", " + std::string(f));
702 else
703 conf_files = std::string(f);
704 return *this;
705 }
706
707 void RADOS::Builder::build(boost::asio::io_context& ioctx,
708 std::unique_ptr<BuildComp> c) {
709 constexpr auto env = CODE_ENVIRONMENT_LIBRARY;
710 CephInitParameters ci(env);
711 if (name)
712 ci.name.set(CEPH_ENTITY_TYPE_CLIENT, *name);
713 else
714 ci.name.set(CEPH_ENTITY_TYPE_CLIENT, "admin");
715 uint32_t flags = 0;
716 if (no_default_conf)
717 flags |= CINIT_FLAG_NO_DEFAULT_CONFIG_FILE;
718 if (no_mon_conf)
719 flags |= CINIT_FLAG_NO_MON_CONFIG;
720
721 CephContext *cct = common_preinit(ci, env, flags);
722 if (cluster)
723 cct->_conf->cluster = *cluster;
724
725 if (no_mon_conf)
726 cct->_conf->no_mon_config = true;
727
728 // TODO: Come up with proper error codes here. Maybe augment the
729 // functions with a default bs::error_code* parameter to
730 // pass back.
731 {
732 std::ostringstream ss;
733 auto r = cct->_conf.parse_config_files(conf_files ? conf_files->data() : nullptr,
734 &ss, flags);
735 if (r < 0)
736 c->post(std::move(c), ceph::to_error_code(r), RADOS{nullptr});
737 }
738
739 cct->_conf.parse_env(cct->get_module_type());
740
741 for (const auto& [n, v] : configs) {
742 std::stringstream ss;
743 auto r = cct->_conf.set_val(n, v, &ss);
744 if (r < 0)
745 c->post(std::move(c), ceph::to_error_code(-EINVAL), RADOS{nullptr});
746 }
747
748 if (!no_mon_conf) {
749 MonClient mc_bootstrap(cct, ioctx);
750 // TODO This function should return an error code.
751 auto err = mc_bootstrap.get_monmap_and_config();
752 if (err < 0)
753 c->post(std::move(c), ceph::to_error_code(err), RADOS{nullptr});
754 }
755 if (!cct->_log->is_started()) {
756 cct->_log->start();
757 }
758 common_init_finish(cct);
759
760 RADOS::make_with_cct(cct, ioctx, std::move(c));
761 }
762
763 void RADOS::make_with_cct(CephContext* cct,
764 boost::asio::io_context& ioctx,
765 std::unique_ptr<BuildComp> c) {
766 try {
767 auto r = new detail::NeoClient{std::make_unique<detail::RADOS>(ioctx, cct)};
768 r->objecter->wait_for_osd_map(
769 [c = std::move(c), r = std::unique_ptr<detail::Client>(r)]() mutable {
770 c->dispatch(std::move(c), bs::error_code{},
771 RADOS{std::move(r)});
772 });
773 } catch (const bs::system_error& err) {
774 c->post(std::move(c), err.code(), RADOS{nullptr});
775 }
776 }
777
778 RADOS RADOS::make_with_librados(librados::Rados& rados) {
779 return RADOS{std::make_unique<detail::RadosClient>(rados.client)};
780 }
781
782 RADOS::RADOS() = default;
783
784 RADOS::RADOS(std::unique_ptr<detail::Client> impl)
785 : impl(std::move(impl)) {}
786
787 RADOS::RADOS(RADOS&&) = default;
788 RADOS& RADOS::operator =(RADOS&&) = default;
789
790 RADOS::~RADOS() = default;
791
792 RADOS::executor_type RADOS::get_executor() const {
793 return impl->ioctx.get_executor();
794 }
795
796 boost::asio::io_context& RADOS::get_io_context() {
797 return impl->ioctx;
798 }
799
800 void RADOS::execute(const Object& o, const IOContext& _ioc, ReadOp&& _op,
801 cb::list* bl,
802 std::unique_ptr<ReadOp::Completion> c, version_t* objver,
803 const blkin_trace_info *trace_info) {
804 auto oid = reinterpret_cast<const object_t*>(&o.impl);
805 auto ioc = reinterpret_cast<const IOContextImpl*>(&_ioc.impl);
806 auto op = reinterpret_cast<OpImpl*>(&_op.impl);
807 auto flags = op->op.flags | ioc->extra_op_flags;
808
809 ZTracer::Trace trace;
810 if (trace_info) {
811 ZTracer::Trace parent_trace("", nullptr, trace_info);
812 trace.init("rados execute", &impl->objecter->trace_endpoint, &parent_trace);
813 }
814
815 trace.event("init");
816 impl->objecter->read(
817 *oid, ioc->oloc, std::move(op->op), ioc->snap_seq, bl, flags,
818 std::move(c), objver, nullptr /* data_offset */, 0 /* features */, &trace);
819
820 trace.event("submitted");
821 }
822
823 void RADOS::execute(const Object& o, const IOContext& _ioc, WriteOp&& _op,
824 std::unique_ptr<WriteOp::Completion> c, version_t* objver,
825 const blkin_trace_info *trace_info) {
826 auto oid = reinterpret_cast<const object_t*>(&o.impl);
827 auto ioc = reinterpret_cast<const IOContextImpl*>(&_ioc.impl);
828 auto op = reinterpret_cast<OpImpl*>(&_op.impl);
829 auto flags = op->op.flags | ioc->extra_op_flags;
830 ceph::real_time mtime;
831 if (op->mtime)
832 mtime = *op->mtime;
833 else
834 mtime = ceph::real_clock::now();
835
836 ZTracer::Trace trace;
837 if (trace_info) {
838 ZTracer::Trace parent_trace("", nullptr, trace_info);
839 trace.init("rados execute", &impl->objecter->trace_endpoint, &parent_trace);
840 }
841
842 trace.event("init");
843 impl->objecter->mutate(
844 *oid, ioc->oloc, std::move(op->op), ioc->snapc,
845 mtime, flags,
846 std::move(c), objver, osd_reqid_t{}, &trace);
847 trace.event("submitted");
848 }
849
850 void RADOS::execute(const Object& o, std::int64_t pool, ReadOp&& _op,
851 cb::list* bl,
852 std::unique_ptr<ReadOp::Completion> c,
853 std::optional<std::string_view> ns,
854 std::optional<std::string_view> key,
855 version_t* objver) {
856 auto oid = reinterpret_cast<const object_t*>(&o.impl);
857 auto op = reinterpret_cast<OpImpl*>(&_op.impl);
858 auto flags = op->op.flags;
859 object_locator_t oloc;
860 oloc.pool = pool;
861 if (ns)
862 oloc.nspace = *ns;
863 if (key)
864 oloc.key = *key;
865
866 impl->objecter->read(
867 *oid, oloc, std::move(op->op), CEPH_NOSNAP, bl, flags,
868 std::move(c), objver);
869 }
870
871 void RADOS::execute(const Object& o, std::int64_t pool, WriteOp&& _op,
872 std::unique_ptr<WriteOp::Completion> c,
873 std::optional<std::string_view> ns,
874 std::optional<std::string_view> key,
875 version_t* objver) {
876 auto oid = reinterpret_cast<const object_t*>(&o.impl);
877 auto op = reinterpret_cast<OpImpl*>(&_op.impl);
878 auto flags = op->op.flags;
879 object_locator_t oloc;
880 oloc.pool = pool;
881 if (ns)
882 oloc.nspace = *ns;
883 if (key)
884 oloc.key = *key;
885
886 ceph::real_time mtime;
887 if (op->mtime)
888 mtime = *op->mtime;
889 else
890 mtime = ceph::real_clock::now();
891
892 impl->objecter->mutate(
893 *oid, oloc, std::move(op->op), {},
894 mtime, flags,
895 std::move(c), objver);
896 }
897
898 boost::uuids::uuid RADOS::get_fsid() const noexcept {
899 return impl->monclient.get_fsid().uuid;
900 }
901
902
903 void RADOS::lookup_pool(std::string_view name,
904 std::unique_ptr<LookupPoolComp> c)
905 {
906 // I kind of want to make lookup_pg_pool return
907 // std::optional<int64_t> since it can only return one error code.
908 int64_t ret = impl->objecter->with_osdmap(
909 std::mem_fn(&OSDMap::lookup_pg_pool_name),
910 name);
911 if (ret < 0) {
912 impl->objecter->wait_for_latest_osdmap(
913 [name = std::string(name), c = std::move(c),
914 objecter = impl->objecter]
915 (bs::error_code ec) mutable {
916 int64_t ret =
917 objecter->with_osdmap([&](const OSDMap &osdmap) {
918 return osdmap.lookup_pg_pool_name(name);
919 });
920 if (ret < 0)
921 ca::dispatch(std::move(c), osdc_errc::pool_dne,
922 std::int64_t(0));
923 else
924 ca::dispatch(std::move(c), bs::error_code{}, ret);
925 });
926 } else if (ret < 0) {
927 ca::post(std::move(c), osdc_errc::pool_dne,
928 std::int64_t(0));
929 } else {
930 ca::post(std::move(c), bs::error_code{}, ret);
931 }
932 }
933
934
935 std::optional<uint64_t> RADOS::get_pool_alignment(int64_t pool_id)
936 {
937 return impl->objecter->with_osdmap(
938 [pool_id](const OSDMap &o) -> std::optional<uint64_t> {
939 if (!o.have_pg_pool(pool_id)) {
940 throw bs::system_error(
941 ENOENT, bs::system_category(),
942 "Cannot find pool in OSDMap.");
943 } else if (o.get_pg_pool(pool_id)->requires_aligned_append()) {
944 return o.get_pg_pool(pool_id)->required_alignment();
945 } else {
946 return std::nullopt;
947 }
948 });
949 }
950
951 void RADOS::list_pools(std::unique_ptr<LSPoolsComp> c) {
952 impl->objecter->with_osdmap(
953 [&](OSDMap& o) {
954 std::vector<std::pair<std::int64_t, std::string>> v;
955 for (auto p : o.get_pools())
956 v.push_back(std::make_pair(p.first, o.get_pool_name(p.first)));
957 ca::dispatch(std::move(c), std::move(v));
958 });
959 }
960
961 void RADOS::create_pool_snap(std::int64_t pool,
962 std::string_view snapName,
963 std::unique_ptr<SimpleOpComp> c)
964 {
965 impl->objecter->create_pool_snap(
966 pool, snapName,
967 Objecter::PoolOp::OpComp::create(
968 get_executor(),
969 [c = std::move(c)](bs::error_code e, const bufferlist&) mutable {
970 ca::dispatch(std::move(c), e);
971 }));
972 }
973
974 void RADOS::allocate_selfmanaged_snap(int64_t pool,
975 std::unique_ptr<SMSnapComp> c) {
976 impl->objecter->allocate_selfmanaged_snap(
977 pool,
978 ca::Completion<void(bs::error_code, snapid_t)>::create(
979 get_executor(),
980 [c = std::move(c)](bs::error_code e, snapid_t snap) mutable {
981 ca::dispatch(std::move(c), e, snap);
982 }));
983 }
984
985 void RADOS::delete_pool_snap(std::int64_t pool,
986 std::string_view snapName,
987 std::unique_ptr<SimpleOpComp> c)
988 {
989 impl->objecter->delete_pool_snap(
990 pool, snapName,
991 Objecter::PoolOp::OpComp::create(
992 get_executor(),
993 [c = std::move(c)](bs::error_code e, const bufferlist&) mutable {
994 ca::dispatch(std::move(c), e);
995 }));
996 }
997
998 void RADOS::delete_selfmanaged_snap(std::int64_t pool,
999 std::uint64_t snap,
1000 std::unique_ptr<SimpleOpComp> c)
1001 {
1002 impl->objecter->delete_selfmanaged_snap(
1003 pool, snap,
1004 Objecter::PoolOp::OpComp::create(
1005 get_executor(),
1006 [c = std::move(c)](bs::error_code e, const bufferlist&) mutable {
1007 ca::dispatch(std::move(c), e);
1008 }));
1009 }
1010
1011 void RADOS::create_pool(std::string_view name,
1012 std::optional<int> crush_rule,
1013 std::unique_ptr<SimpleOpComp> c)
1014 {
1015 impl->objecter->create_pool(
1016 name,
1017 Objecter::PoolOp::OpComp::create(
1018 get_executor(),
1019 [c = std::move(c)](bs::error_code e, const bufferlist&) mutable {
1020 ca::dispatch(std::move(c), e);
1021 }),
1022 crush_rule.value_or(-1));
1023 }
1024
1025 void RADOS::delete_pool(std::string_view name,
1026 std::unique_ptr<SimpleOpComp> c)
1027 {
1028 impl->objecter->delete_pool(
1029 name,
1030 Objecter::PoolOp::OpComp::create(
1031 get_executor(),
1032 [c = std::move(c)](bs::error_code e, const bufferlist&) mutable {
1033 ca::dispatch(std::move(c), e);
1034 }));
1035 }
1036
1037 void RADOS::delete_pool(std::int64_t pool,
1038 std::unique_ptr<SimpleOpComp> c)
1039 {
1040 impl->objecter->delete_pool(
1041 pool,
1042 Objecter::PoolOp::OpComp::create(
1043 get_executor(),
1044 [c = std::move(c)](bs::error_code e, const bufferlist&) mutable {
1045 ca::dispatch(std::move(c), e);
1046 }));
1047 }
1048
1049 void RADOS::stat_pools(const std::vector<std::string>& pools,
1050 std::unique_ptr<PoolStatComp> c) {
1051 impl->objecter->get_pool_stats(
1052 pools,
1053 [c = std::move(c)]
1054 (bs::error_code ec,
1055 bc::flat_map<std::string, pool_stat_t> rawresult,
1056 bool per_pool) mutable {
1057 bc::flat_map<std::string, PoolStats> result;
1058 for (auto p = rawresult.begin(); p != rawresult.end(); ++p) {
1059 auto& pv = result[p->first];
1060 auto& pstat = p->second;
1061 store_statfs_t &statfs = pstat.store_stats;
1062 uint64_t allocated_bytes = pstat.get_allocated_data_bytes(per_pool) +
1063 pstat.get_allocated_omap_bytes(per_pool);
1064 // FIXME: raw_used_rate is unknown hence use 1.0 here
1065 // meaning we keep net amount aggregated over all replicas
1066 // Not a big deal so far since this field isn't exposed
1067 uint64_t user_bytes = pstat.get_user_data_bytes(1.0, per_pool) +
1068 pstat.get_user_omap_bytes(1.0, per_pool);
1069
1070 object_stat_sum_t *sum = &p->second.stats.sum;
1071 pv.num_kb = shift_round_up(allocated_bytes, 10);
1072 pv.num_bytes = allocated_bytes;
1073 pv.num_objects = sum->num_objects;
1074 pv.num_object_clones = sum->num_object_clones;
1075 pv.num_object_copies = sum->num_object_copies;
1076 pv.num_objects_missing_on_primary = sum->num_objects_missing_on_primary;
1077 pv.num_objects_unfound = sum->num_objects_unfound;
1078 pv.num_objects_degraded = sum->num_objects_degraded;
1079 pv.num_rd = sum->num_rd;
1080 pv.num_rd_kb = sum->num_rd_kb;
1081 pv.num_wr = sum->num_wr;
1082 pv.num_wr_kb = sum->num_wr_kb;
1083 pv.num_user_bytes = user_bytes;
1084 pv.compressed_bytes_orig = statfs.data_compressed_original;
1085 pv.compressed_bytes = statfs.data_compressed;
1086 pv.compressed_bytes_alloc = statfs.data_compressed_allocated;
1087 }
1088
1089 ca::dispatch(std::move(c), ec, std::move(result), per_pool);
1090 });
1091 }
1092
1093 void RADOS::stat_fs(std::optional<std::int64_t> _pool,
1094 std::unique_ptr<StatFSComp> c) {
1095 std::optional<int64_t> pool;
1096 if (_pool)
1097 pool = *pool;
1098 impl->objecter->get_fs_stats(
1099 pool,
1100 [c = std::move(c)](bs::error_code ec, const struct ceph_statfs s) mutable {
1101 FSStats fso{s.kb, s.kb_used, s.kb_avail, s.num_objects};
1102 c->dispatch(std::move(c), ec, std::move(fso));
1103 });
1104 }
1105
1106 // --- Watch/Notify
1107
1108 void RADOS::watch(const Object& o, const IOContext& _ioc,
1109 std::optional<std::chrono::seconds> timeout, WatchCB&& cb,
1110 std::unique_ptr<WatchComp> c) {
1111 auto oid = reinterpret_cast<const object_t*>(&o.impl);
1112 auto ioc = reinterpret_cast<const IOContextImpl*>(&_ioc.impl);
1113
1114 ObjectOperation op;
1115
1116 auto linger_op = impl->objecter->linger_register(*oid, ioc->oloc,
1117 ioc->extra_op_flags);
1118 uint64_t cookie = linger_op->get_cookie();
1119 linger_op->handle = std::move(cb);
1120 op.watch(cookie, CEPH_OSD_WATCH_OP_WATCH, timeout.value_or(0s).count());
1121 bufferlist bl;
1122 impl->objecter->linger_watch(
1123 linger_op, op, ioc->snapc, ceph::real_clock::now(), bl,
1124 Objecter::LingerOp::OpComp::create(
1125 get_executor(),
1126 [c = std::move(c), cookie](bs::error_code e, cb::list) mutable {
1127 ca::dispatch(std::move(c), e, cookie);
1128 }), nullptr);
1129 }
1130
1131 void RADOS::watch(const Object& o, std::int64_t pool,
1132 std::optional<std::chrono::seconds> timeout, WatchCB&& cb,
1133 std::unique_ptr<WatchComp> c,
1134 std::optional<std::string_view> ns,
1135 std::optional<std::string_view> key) {
1136 auto oid = reinterpret_cast<const object_t*>(&o.impl);
1137 object_locator_t oloc;
1138 oloc.pool = pool;
1139 if (ns)
1140 oloc.nspace = *ns;
1141 if (key)
1142 oloc.key = *key;
1143
1144 ObjectOperation op;
1145
1146 Objecter::LingerOp *linger_op = impl->objecter->linger_register(*oid, oloc, 0);
1147 uint64_t cookie = linger_op->get_cookie();
1148 linger_op->handle = std::move(cb);
1149 op.watch(cookie, CEPH_OSD_WATCH_OP_WATCH, timeout.value_or(0s).count());
1150 bufferlist bl;
1151 impl->objecter->linger_watch(
1152 linger_op, op, {}, ceph::real_clock::now(), bl,
1153 Objecter::LingerOp::OpComp::create(
1154 get_executor(),
1155 [c = std::move(c), cookie](bs::error_code e, bufferlist) mutable {
1156 ca::dispatch(std::move(c), e, cookie);
1157 }), nullptr);
1158 }
1159
1160 void RADOS::notify_ack(const Object& o,
1161 const IOContext& _ioc,
1162 uint64_t notify_id,
1163 uint64_t cookie,
1164 bufferlist&& bl,
1165 std::unique_ptr<SimpleOpComp> c)
1166 {
1167 auto oid = reinterpret_cast<const object_t*>(&o.impl);
1168 auto ioc = reinterpret_cast<const IOContextImpl*>(&_ioc.impl);
1169
1170 ObjectOperation op;
1171 op.notify_ack(notify_id, cookie, bl);
1172
1173 impl->objecter->read(*oid, ioc->oloc, std::move(op), ioc->snap_seq,
1174 nullptr, ioc->extra_op_flags, std::move(c));
1175 }
1176
1177 void RADOS::notify_ack(const Object& o,
1178 std::int64_t pool,
1179 uint64_t notify_id,
1180 uint64_t cookie,
1181 bufferlist&& bl,
1182 std::unique_ptr<SimpleOpComp> c,
1183 std::optional<std::string_view> ns,
1184 std::optional<std::string_view> key) {
1185 auto oid = reinterpret_cast<const object_t*>(&o.impl);
1186 object_locator_t oloc;
1187 oloc.pool = pool;
1188 if (ns)
1189 oloc.nspace = *ns;
1190 if (key)
1191 oloc.key = *key;
1192
1193 ObjectOperation op;
1194 op.notify_ack(notify_id, cookie, bl);
1195 impl->objecter->read(*oid, oloc, std::move(op), CEPH_NOSNAP, nullptr, 0,
1196 std::move(c));
1197 }
1198
1199 tl::expected<ceph::timespan, bs::error_code> RADOS::watch_check(uint64_t cookie)
1200 {
1201 Objecter::LingerOp *linger_op = reinterpret_cast<Objecter::LingerOp*>(cookie);
1202 return impl->objecter->linger_check(linger_op);
1203 }
1204
1205 void RADOS::unwatch(uint64_t cookie, const IOContext& _ioc,
1206 std::unique_ptr<SimpleOpComp> c)
1207 {
1208 auto ioc = reinterpret_cast<const IOContextImpl*>(&_ioc.impl);
1209
1210 Objecter::LingerOp *linger_op = reinterpret_cast<Objecter::LingerOp*>(cookie);
1211
1212 ObjectOperation op;
1213 op.watch(cookie, CEPH_OSD_WATCH_OP_UNWATCH);
1214 impl->objecter->mutate(linger_op->target.base_oid, ioc->oloc, std::move(op),
1215 ioc->snapc, ceph::real_clock::now(), ioc->extra_op_flags,
1216 Objecter::Op::OpComp::create(
1217 get_executor(),
1218 [objecter = impl->objecter,
1219 linger_op, c = std::move(c)]
1220 (bs::error_code ec) mutable {
1221 objecter->linger_cancel(linger_op);
1222 ca::dispatch(std::move(c), ec);
1223 }));
1224 }
1225
1226 void RADOS::unwatch(uint64_t cookie, std::int64_t pool,
1227 std::unique_ptr<SimpleOpComp> c,
1228 std::optional<std::string_view> ns,
1229 std::optional<std::string_view> key)
1230 {
1231 object_locator_t oloc;
1232 oloc.pool = pool;
1233 if (ns)
1234 oloc.nspace = *ns;
1235 if (key)
1236 oloc.key = *key;
1237
1238 Objecter::LingerOp *linger_op = reinterpret_cast<Objecter::LingerOp*>(cookie);
1239
1240 ObjectOperation op;
1241 op.watch(cookie, CEPH_OSD_WATCH_OP_UNWATCH);
1242 impl->objecter->mutate(linger_op->target.base_oid, oloc, std::move(op),
1243 {}, ceph::real_clock::now(), 0,
1244 Objecter::Op::OpComp::create(
1245 get_executor(),
1246 [objecter = impl->objecter,
1247 linger_op, c = std::move(c)]
1248 (bs::error_code ec) mutable {
1249 objecter->linger_cancel(linger_op);
1250 ca::dispatch(std::move(c), ec);
1251 }));
1252 }
1253
1254 void RADOS::flush_watch(std::unique_ptr<VoidOpComp> c)
1255 {
1256 impl->objecter->linger_callback_flush([c = std::move(c)]() mutable {
1257 ca::post(std::move(c));
1258 });
1259 }
1260
1261 struct NotifyHandler : std::enable_shared_from_this<NotifyHandler> {
1262 boost::asio::io_context& ioc;
1263 boost::asio::io_context::strand strand;
1264 Objecter* objecter;
1265 Objecter::LingerOp* op;
1266 std::unique_ptr<RADOS::NotifyComp> c;
1267
1268 bool acked = false;
1269 bool finished = false;
1270 bs::error_code res;
1271 bufferlist rbl;
1272
1273 NotifyHandler(boost::asio::io_context& ioc,
1274 Objecter* objecter,
1275 Objecter::LingerOp* op,
1276 std::unique_ptr<RADOS::NotifyComp> c)
1277 : ioc(ioc), strand(ioc), objecter(objecter), op(op), c(std::move(c)) {}
1278
1279 // Use bind or a lambda to pass this in.
1280 void handle_ack(bs::error_code ec,
1281 bufferlist&&) {
1282 boost::asio::post(
1283 strand,
1284 [this, ec, p = shared_from_this()]() mutable {
1285 acked = true;
1286 maybe_cleanup(ec);
1287 });
1288 }
1289
1290 // Notify finish callback. It can actually own the object's storage.
1291
1292 void operator()(bs::error_code ec,
1293 bufferlist&& bl) {
1294 boost::asio::post(
1295 strand,
1296 [this, ec, p = shared_from_this()]() mutable {
1297 finished = true;
1298 maybe_cleanup(ec);
1299 });
1300 }
1301
1302 // Should be called from strand.
1303 void maybe_cleanup(bs::error_code ec) {
1304 if (!res && ec)
1305 res = ec;
1306 if ((acked && finished) || res) {
1307 objecter->linger_cancel(op);
1308 ceph_assert(c);
1309 ca::dispatch(std::move(c), res, std::move(rbl));
1310 }
1311 }
1312 };
1313
1314 void RADOS::notify(const Object& o, const IOContext& _ioc, bufferlist&& bl,
1315 std::optional<std::chrono::milliseconds> timeout,
1316 std::unique_ptr<NotifyComp> c)
1317 {
1318 auto oid = reinterpret_cast<const object_t*>(&o.impl);
1319 auto ioc = reinterpret_cast<const IOContextImpl*>(&_ioc.impl);
1320 auto linger_op = impl->objecter->linger_register(*oid, ioc->oloc,
1321 ioc->extra_op_flags);
1322
1323 auto cb = std::make_shared<NotifyHandler>(impl->ioctx, impl->objecter,
1324 linger_op, std::move(c));
1325 linger_op->on_notify_finish =
1326 Objecter::LingerOp::OpComp::create(
1327 get_executor(),
1328 [cb](bs::error_code ec, ceph::bufferlist bl) mutable {
1329 (*cb)(ec, std::move(bl));
1330 });
1331 ObjectOperation rd;
1332 bufferlist inbl;
1333 rd.notify(
1334 linger_op->get_cookie(), 1,
1335 timeout ? timeout->count() : impl->cct->_conf->client_notify_timeout,
1336 bl, &inbl);
1337
1338 impl->objecter->linger_notify(
1339 linger_op, rd, ioc->snap_seq, inbl,
1340 Objecter::LingerOp::OpComp::create(
1341 get_executor(),
1342 [cb](bs::error_code ec, ceph::bufferlist bl) mutable {
1343 cb->handle_ack(ec, std::move(bl));
1344 }), nullptr);
1345 }
1346
1347 void RADOS::notify(const Object& o, std::int64_t pool, bufferlist&& bl,
1348 std::optional<std::chrono::milliseconds> timeout,
1349 std::unique_ptr<NotifyComp> c,
1350 std::optional<std::string_view> ns,
1351 std::optional<std::string_view> key)
1352 {
1353 auto oid = reinterpret_cast<const object_t*>(&o.impl);
1354 object_locator_t oloc;
1355 oloc.pool = pool;
1356 if (ns)
1357 oloc.nspace = *ns;
1358 if (key)
1359 oloc.key = *key;
1360 auto linger_op = impl->objecter->linger_register(*oid, oloc, 0);
1361
1362 auto cb = std::make_shared<NotifyHandler>(impl->ioctx, impl->objecter,
1363 linger_op, std::move(c));
1364 linger_op->on_notify_finish =
1365 Objecter::LingerOp::OpComp::create(
1366 get_executor(),
1367 [cb](bs::error_code ec, ceph::bufferlist&& bl) mutable {
1368 (*cb)(ec, std::move(bl));
1369 });
1370 ObjectOperation rd;
1371 bufferlist inbl;
1372 rd.notify(
1373 linger_op->get_cookie(), 1,
1374 timeout ? timeout->count() : impl->cct->_conf->client_notify_timeout,
1375 bl, &inbl);
1376
1377 impl->objecter->linger_notify(
1378 linger_op, rd, CEPH_NOSNAP, inbl,
1379 Objecter::LingerOp::OpComp::create(
1380 get_executor(),
1381 [cb](bs::error_code ec, bufferlist&& bl) mutable {
1382 cb->handle_ack(ec, std::move(bl));
1383 }), nullptr);
1384 }
1385
1386 // Enumeration
1387
1388 Cursor::Cursor() {
1389 static_assert(impl_size >= sizeof(hobject_t));
1390 new (&impl) hobject_t();
1391 };
1392
1393 Cursor::Cursor(end_magic_t) {
1394 static_assert(impl_size >= sizeof(hobject_t));
1395 new (&impl) hobject_t(hobject_t::get_max());
1396 }
1397
1398 Cursor::Cursor(void* p) {
1399 static_assert(impl_size >= sizeof(hobject_t));
1400 new (&impl) hobject_t(std::move(*reinterpret_cast<hobject_t*>(p)));
1401 }
1402
1403 Cursor Cursor::begin() {
1404 Cursor e;
1405 return e;
1406 }
1407
1408 Cursor Cursor::end() {
1409 Cursor e(end_magic_t{});
1410 return e;
1411 }
1412
1413 Cursor::Cursor(const Cursor& rhs) {
1414 static_assert(impl_size >= sizeof(hobject_t));
1415 new (&impl) hobject_t(*reinterpret_cast<const hobject_t*>(&rhs.impl));
1416 }
1417
1418 Cursor& Cursor::operator =(const Cursor& rhs) {
1419 static_assert(impl_size >= sizeof(hobject_t));
1420 reinterpret_cast<hobject_t*>(&impl)->~hobject_t();
1421 new (&impl) hobject_t(*reinterpret_cast<const hobject_t*>(&rhs.impl));
1422 return *this;
1423 }
1424
1425 Cursor::Cursor(Cursor&& rhs) {
1426 static_assert(impl_size >= sizeof(hobject_t));
1427 new (&impl) hobject_t(std::move(*reinterpret_cast<hobject_t*>(&rhs.impl)));
1428 }
1429
1430 Cursor& Cursor::operator =(Cursor&& rhs) {
1431 static_assert(impl_size >= sizeof(hobject_t));
1432 reinterpret_cast<hobject_t*>(&impl)->~hobject_t();
1433 new (&impl) hobject_t(std::move(*reinterpret_cast<hobject_t*>(&rhs.impl)));
1434 return *this;
1435 }
1436 Cursor::~Cursor() {
1437 reinterpret_cast<hobject_t*>(&impl)->~hobject_t();
1438 }
1439
1440 bool operator ==(const Cursor& lhs, const Cursor& rhs) {
1441 return (*reinterpret_cast<const hobject_t*>(&lhs.impl) ==
1442 *reinterpret_cast<const hobject_t*>(&rhs.impl));
1443 }
1444
1445 bool operator !=(const Cursor& lhs, const Cursor& rhs) {
1446 return (*reinterpret_cast<const hobject_t*>(&lhs.impl) !=
1447 *reinterpret_cast<const hobject_t*>(&rhs.impl));
1448 }
1449
1450 bool operator <(const Cursor& lhs, const Cursor& rhs) {
1451 return (*reinterpret_cast<const hobject_t*>(&lhs.impl) <
1452 *reinterpret_cast<const hobject_t*>(&rhs.impl));
1453 }
1454
1455 bool operator <=(const Cursor& lhs, const Cursor& rhs) {
1456 return (*reinterpret_cast<const hobject_t*>(&lhs.impl) <=
1457 *reinterpret_cast<const hobject_t*>(&rhs.impl));
1458 }
1459
1460 bool operator >=(const Cursor& lhs, const Cursor& rhs) {
1461 return (*reinterpret_cast<const hobject_t*>(&lhs.impl) >=
1462 *reinterpret_cast<const hobject_t*>(&rhs.impl));
1463 }
1464
1465 bool operator >(const Cursor& lhs, const Cursor& rhs) {
1466 return (*reinterpret_cast<const hobject_t*>(&lhs.impl) >
1467 *reinterpret_cast<const hobject_t*>(&rhs.impl));
1468 }
1469
1470 std::string Cursor::to_str() const {
1471 using namespace std::literals;
1472 auto& h = *reinterpret_cast<const hobject_t*>(&impl);
1473
1474 return h.is_max() ? "MAX"s : h.to_str();
1475 }
1476
1477 std::optional<Cursor>
1478 Cursor::from_str(const std::string& s) {
1479 Cursor e;
1480 auto& h = *reinterpret_cast<hobject_t*>(&e.impl);
1481 if (!h.parse(s))
1482 return std::nullopt;
1483
1484 return e;
1485 }
1486
1487 void RADOS::enumerate_objects(const IOContext& _ioc,
1488 const Cursor& begin,
1489 const Cursor& end,
1490 const std::uint32_t max,
1491 const bufferlist& filter,
1492 std::unique_ptr<EnumerateComp> c) {
1493 auto ioc = reinterpret_cast<const IOContextImpl*>(&_ioc.impl);
1494
1495 impl->objecter->enumerate_objects<Entry>(
1496 ioc->oloc.pool,
1497 ioc->oloc.nspace,
1498 *reinterpret_cast<const hobject_t*>(&begin.impl),
1499 *reinterpret_cast<const hobject_t*>(&end.impl),
1500 max,
1501 filter,
1502 [c = std::move(c)]
1503 (bs::error_code ec, std::vector<Entry>&& v,
1504 hobject_t&& n) mutable {
1505 ca::dispatch(std::move(c), ec, std::move(v),
1506 Cursor(static_cast<void*>(&n)));
1507 });
1508 }
1509
1510 void RADOS::enumerate_objects(std::int64_t pool,
1511 const Cursor& begin,
1512 const Cursor& end,
1513 const std::uint32_t max,
1514 const bufferlist& filter,
1515 std::unique_ptr<EnumerateComp> c,
1516 std::optional<std::string_view> ns,
1517 std::optional<std::string_view> key) {
1518 impl->objecter->enumerate_objects<Entry>(
1519 pool,
1520 ns ? *ns : std::string_view{},
1521 *reinterpret_cast<const hobject_t*>(&begin.impl),
1522 *reinterpret_cast<const hobject_t*>(&end.impl),
1523 max,
1524 filter,
1525 [c = std::move(c)]
1526 (bs::error_code ec, std::vector<Entry>&& v,
1527 hobject_t&& n) mutable {
1528 ca::dispatch(std::move(c), ec, std::move(v),
1529 Cursor(static_cast<void*>(&n)));
1530 });
1531 }
1532
1533
1534 void RADOS::osd_command(int osd, std::vector<std::string>&& cmd,
1535 ceph::bufferlist&& in, std::unique_ptr<CommandComp> c) {
1536 impl->objecter->osd_command(osd, std::move(cmd), std::move(in), nullptr,
1537 [c = std::move(c)]
1538 (bs::error_code ec,
1539 std::string&& s,
1540 ceph::bufferlist&& b) mutable {
1541 ca::dispatch(std::move(c), ec,
1542 std::move(s),
1543 std::move(b));
1544 });
1545 }
1546 void RADOS::pg_command(PG pg, std::vector<std::string>&& cmd,
1547 ceph::bufferlist&& in, std::unique_ptr<CommandComp> c) {
1548 impl->objecter->pg_command(pg_t{pg.seed, pg.pool}, std::move(cmd), std::move(in), nullptr,
1549 [c = std::move(c)]
1550 (bs::error_code ec,
1551 std::string&& s,
1552 ceph::bufferlist&& b) mutable {
1553 ca::dispatch(std::move(c), ec,
1554 std::move(s),
1555 std::move(b));
1556 });
1557 }
1558
1559 void RADOS::enable_application(std::string_view pool, std::string_view app_name,
1560 bool force, std::unique_ptr<SimpleOpComp> c) {
1561 // pre-Luminous clusters will return -EINVAL and application won't be
1562 // preserved until Luminous is configured as minimum version.
1563 if (!impl->get_required_monitor_features().contains_all(
1564 ceph::features::mon::FEATURE_LUMINOUS)) {
1565 ca::post(std::move(c), ceph::to_error_code(-EOPNOTSUPP));
1566 } else {
1567 impl->monclient.start_mon_command(
1568 { fmt::format("{{ \"prefix\": \"osd pool application enable\","
1569 "\"pool\": \"{}\", \"app\": \"{}\"{}}}",
1570 pool, app_name,
1571 force ? " ,\"yes_i_really_mean_it\": true" : "")},
1572 {}, [c = std::move(c)](bs::error_code e,
1573 std::string, cb::list) mutable {
1574 ca::post(std::move(c), e);
1575 });
1576 }
1577 }
1578
1579 void RADOS::blocklist_add(std::string_view client_address,
1580 std::optional<std::chrono::seconds> expire,
1581 std::unique_ptr<SimpleOpComp> c) {
1582 auto expire_arg = (expire ?
1583 fmt::format(", \"expire\": \"{}.0\"", expire->count()) : std::string{});
1584 impl->monclient.start_mon_command(
1585 { fmt::format("{{"
1586 "\"prefix\": \"osd blocklist\", "
1587 "\"blocklistop\": \"add\", "
1588 "\"addr\": \"{}\"{}}}",
1589 client_address, expire_arg) },
1590 {},
1591 [this, client_address = std::string(client_address), expire_arg,
1592 c = std::move(c)](bs::error_code ec, std::string, cb::list) mutable {
1593 if (ec != bs::errc::invalid_argument) {
1594 ca::post(std::move(c), ec);
1595 return;
1596 }
1597
1598 // retry using the legacy command
1599 impl->monclient.start_mon_command(
1600 { fmt::format("{{"
1601 "\"prefix\": \"osd blacklist\", "
1602 "\"blacklistop\": \"add\", "
1603 "\"addr\": \"{}\"{}}}",
1604 client_address, expire_arg) },
1605 {},
1606 [c = std::move(c)](bs::error_code ec, std::string, cb::list) mutable {
1607 ca::post(std::move(c), ec);
1608 });
1609 });
1610 }
1611
1612 void RADOS::wait_for_latest_osd_map(std::unique_ptr<SimpleOpComp> c) {
1613 impl->objecter->wait_for_latest_osdmap(std::move(c));
1614 }
1615
1616 void RADOS::mon_command(std::vector<std::string> command,
1617 const cb::list& bl,
1618 std::string* outs, cb::list* outbl,
1619 std::unique_ptr<SimpleOpComp> c) {
1620
1621 impl->monclient.start_mon_command(
1622 command, bl,
1623 [c = std::move(c), outs, outbl](bs::error_code e,
1624 std::string s, cb::list bl) mutable {
1625 if (outs)
1626 *outs = std::move(s);
1627 if (outbl)
1628 *outbl = std::move(bl);
1629 ca::post(std::move(c), e);
1630 });
1631 }
1632
1633 uint64_t RADOS::instance_id() const {
1634 return impl->get_instance_id();
1635 }
1636
1637 #pragma GCC diagnostic push
1638 #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
1639 #pragma clang diagnostic push
1640 #pragma clang diagnostic ignored "-Wnon-virtual-dtor"
1641 class category : public ceph::converting_category {
1642 public:
1643 category() {}
1644 const char* name() const noexcept override;
1645 const char* message(int ev, char*, std::size_t) const noexcept override;
1646 std::string message(int ev) const override;
1647 bs::error_condition default_error_condition(int ev) const noexcept
1648 override;
1649 bool equivalent(int ev, const bs::error_condition& c) const
1650 noexcept override;
1651 using ceph::converting_category::equivalent;
1652 int from_code(int ev) const noexcept override;
1653 };
1654 #pragma GCC diagnostic pop
1655 #pragma clang diagnostic pop
1656
1657 const char* category::name() const noexcept {
1658 return "RADOS";
1659 }
1660
1661 const char* category::message(int ev, char*,
1662 std::size_t) const noexcept {
1663 if (ev == 0)
1664 return "No error";
1665
1666 switch (static_cast<errc>(ev)) {
1667 case errc::pool_dne:
1668 return "Pool does not exist";
1669
1670 case errc::invalid_snapcontext:
1671 return "Invalid snapcontext";
1672 }
1673
1674 return "Unknown error";
1675 }
1676
1677 std::string category::message(int ev) const {
1678 return message(ev, nullptr, 0);
1679 }
1680
1681 bs::error_condition category::default_error_condition(int ev) const noexcept {
1682 switch (static_cast<errc>(ev)) {
1683 case errc::pool_dne:
1684 return ceph::errc::does_not_exist;
1685 case errc::invalid_snapcontext:
1686 return bs::errc::invalid_argument;
1687 }
1688
1689 return { ev, *this };
1690 }
1691
1692 bool category::equivalent(int ev, const bs::error_condition& c) const noexcept {
1693 if (static_cast<errc>(ev) == errc::pool_dne) {
1694 if (c == bs::errc::no_such_file_or_directory) {
1695 return true;
1696 }
1697 }
1698
1699 return default_error_condition(ev) == c;
1700 }
1701
1702 int category::from_code(int ev) const noexcept {
1703 switch (static_cast<errc>(ev)) {
1704 case errc::pool_dne:
1705 return -ENOENT;
1706 case errc::invalid_snapcontext:
1707 return -EINVAL;
1708 }
1709 return -EDOM;
1710 }
1711
1712 const bs::error_category& error_category() noexcept {
1713 static const class category c;
1714 return c;
1715 }
1716
1717 CephContext* RADOS::cct() {
1718 return impl->cct.get();
1719 }
1720 }
1721
1722 namespace std {
1723 size_t hash<neorados::Object>::operator ()(
1724 const neorados::Object& r) const {
1725 static constexpr const hash<object_t> H;
1726 return H(*reinterpret_cast<const object_t*>(&r.impl));
1727 }
1728
1729 size_t hash<neorados::IOContext>::operator ()(
1730 const neorados::IOContext& r) const {
1731 static constexpr const hash<int64_t> H;
1732 static constexpr const hash<std::string> G;
1733 const auto l = reinterpret_cast<const neorados::IOContextImpl*>(&r.impl);
1734 return H(l->oloc.pool) ^ (G(l->oloc.nspace) << 1) ^ (G(l->oloc.key) << 2);
1735 }
1736 }