]> git.proxmox.com Git - ceph.git/blame - ceph/src/include/neorados/RADOS.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / include / neorados / RADOS.hpp
CommitLineData
f67539c2
TL
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 * Author: Adam C. Emerson
8 *
9 * This is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License version 2.1, as published by the Free Software
12 * Foundation. See file COPYING.
13 *
14 */
15
16#ifndef NEORADOS_RADOS_HPP
17#define NEORADOS_RADOS_HPP
18
19#include <cstddef>
20#include <memory>
21#include <tuple>
22#include <string>
23#include <string_view>
24#include <type_traits>
25#include <variant>
26
27#include <boost/asio.hpp>
28
29#include <boost/container/flat_map.hpp>
30#include <boost/container/flat_set.hpp>
31#include <boost/uuid/uuid.hpp>
32
33#include <boost/system/error_code.hpp>
34
35// Will be in C++20!
36
37#include "include/expected.hpp"
38
39// Had better be in C++20. Why is this not in Boost?
40
41#include "include/function2.hpp"
42
43// Things broken out so we can decode them in Objecter.
44
45#include "include/neorados/RADOS_Decodable.hpp"
46
47// Needed for type erasure and template support. We can't really avoid
48// it.
49
50#include "common/async/completion.h"
51
52// These are needed for RGW, but in general as a 'shiny new interface'
53// we should try to use forward declarations and provide standard alternatives.
54
55#include "include/common_fwd.h"
56
57#include "include/buffer.h"
58#include "include/rados/librados_fwd.hpp"
59
60#include "common/ceph_time.h"
61
62namespace neorados {
f67539c2
TL
63class Object;
64class IOContext;
65}
66namespace std {
67template<>
68struct hash<neorados::Object>;
69template<>
70struct hash<neorados::IOContext>;
71}
72
73namespace neorados {
74namespace detail {
75class Client;
76}
77
78class RADOS;
79
80// Exists mostly so that repeated operations on the same object don't
81// have to pay for the string copy to construct an object_t.
82
83class Object final {
84 friend RADOS;
85 friend std::hash<Object>;
86
87public:
88 Object();
89 Object(const char* s);
90 Object(std::string_view s);
91 Object(std::string&& s);
92 Object(const std::string& s);
93 ~Object();
94
95 Object(const Object& o);
96 Object& operator =(const Object& o);
97
98 Object(Object&& o);
99 Object& operator =(Object&& o);
100
101 operator std::string_view() const;
102
103 friend std::ostream& operator <<(std::ostream& m, const Object& o);
104 friend bool operator <(const Object& lhs, const Object& rhs);
105 friend bool operator <=(const Object& lhs, const Object& rhs);
106 friend bool operator >=(const Object& lhs, const Object& rhs);
107 friend bool operator >(const Object& lhs, const Object& rhs);
108
109 friend bool operator ==(const Object& lhs, const Object& rhs);
110 friend bool operator !=(const Object& lhs, const Object& rhs);
111
112private:
113
114 static constexpr std::size_t impl_size = 4 * 8;
115 std::aligned_storage_t<impl_size> impl;
116};
117
118// Not the same as the librados::IoCtx, but it does gather together
119// some of the same metadata. Since we're likely to do multiple
120// operations in the same pool or namespace, it doesn't make sense to
121// redo a bunch of lookups and string copies.
122
123class IOContext final {
124 friend RADOS;
125 friend std::hash<IOContext>;
126
127public:
128
129 IOContext();
130 explicit IOContext(std::int64_t pool);
131 IOContext(std::int64_t _pool, std::string_view _ns);
132 IOContext(std::int64_t _pool, std::string&& _ns);
133 ~IOContext();
134
135 IOContext(const IOContext& rhs);
136 IOContext& operator =(const IOContext& rhs);
137
138 IOContext(IOContext&& rhs);
139 IOContext& operator =(IOContext&& rhs);
140
141 std::int64_t pool() const;
142 void pool(std::int64_t _pool);
143
144 std::string_view ns() const;
145 void ns(std::string_view _ns);
146 void ns(std::string&& _ns);
147
148 std::optional<std::string_view> key() const;
149 void key(std::string_view _key);
150 void key(std::string&& _key);
151 void clear_key();
152
153 std::optional<std::int64_t> hash() const;
154 void hash(std::int64_t _hash);
155 void clear_hash();
156
157 std::optional<std::uint64_t> read_snap() const;
158 void read_snap(std::optional<std::uint64_t> _snapid);
159
160 // I can't actually move-construct here since snapid_t is its own
161 // separate class type, not an alias.
162 std::optional<
163 std::pair<std::uint64_t,
164 std::vector<std::uint64_t>>> write_snap_context() const;
165 void write_snap_context(std::optional<
166 std::pair<std::uint64_t,
167 std::vector<std::uint64_t>>> snapc);
168
20effc67
TL
169 bool full_try() const;
170 void full_try(bool _full_try);
171
f67539c2
TL
172 friend std::ostream& operator <<(std::ostream& m, const IOContext& o);
173 friend bool operator <(const IOContext& lhs, const IOContext& rhs);
174 friend bool operator <=(const IOContext& lhs, const IOContext& rhs);
175 friend bool operator >=(const IOContext& lhs, const IOContext& rhs);
176 friend bool operator >(const IOContext& lhs, const IOContext& rhs);
177
178 friend bool operator ==(const IOContext& lhs, const IOContext& rhs);
179 friend bool operator !=(const IOContext& lhs, const IOContext& rhs);
180
181private:
182
183 static constexpr std::size_t impl_size = 16 * 8;
184 std::aligned_storage_t<impl_size> impl;
185};
186
1e59de90 187inline constexpr std::string_view all_nspaces("\001");
f67539c2
TL
188
189enum class cmpxattr_op : std::uint8_t {
190 eq = 1,
191 ne = 2,
192 gt = 3,
193 gte = 4,
194 lt = 5,
195 lte = 6
196};
197
198namespace alloc_hint {
199enum alloc_hint_t {
200 sequential_write = 1,
201 random_write = 2,
202 sequential_read = 4,
203 random_read = 8,
204 append_only = 16,
205 immutable = 32,
206 shortlived = 64,
207 longlived = 128,
208 compressible = 256,
209 incompressible = 512
210};
211}
212
213class Op {
214 friend RADOS;
215
216public:
217
218 Op(const Op&) = delete;
219 Op& operator =(const Op&) = delete;
220 Op(Op&&);
221 Op& operator =(Op&&);
222 ~Op();
223
224 void set_excl();
225 void set_failok();
226 void set_fadvise_random();
227 void set_fadvise_sequential();
228 void set_fadvise_willneed();
229 void set_fadvise_dontneed();
230 void set_fadvise_nocache();
231
232 void cmpext(uint64_t off, ceph::buffer::list&& cmp_bl, std::size_t* s);
233 void cmpxattr(std::string_view name, cmpxattr_op op,
234 const ceph::buffer::list& val);
235 void cmpxattr(std::string_view name, cmpxattr_op op, std::uint64_t val);
236 void assert_version(uint64_t ver);
237 void assert_exists();
238 void cmp_omap(const boost::container::flat_map<
239 std::string,
240 std::pair<ceph::buffer::list, int>>& assertions);
241
242 void exec(std::string_view cls, std::string_view method,
243 const ceph::buffer::list& inbl,
244 ceph::buffer::list* out,
245 boost::system::error_code* ec = nullptr);
246 void exec(std::string_view cls, std::string_view method,
247 const ceph::buffer::list& inbl,
248 fu2::unique_function<void(boost::system::error_code,
249 const ceph::buffer::list&) &&> f);
250 void exec(std::string_view cls, std::string_view method,
251 const ceph::buffer::list& inbl,
252 fu2::unique_function<void(boost::system::error_code, int,
253 const ceph::buffer::list&) &&> f);
254 void exec(std::string_view cls, std::string_view method,
255 const ceph::buffer::list& inbl,
256 boost::system::error_code* ec = nullptr);
257
258
259 // Flags that apply to all ops in the operation vector
260 void balance_reads();
261 void localize_reads();
262 void order_reads_writes();
263 void ignore_cache();
264 void skiprwlocks();
265 void ignore_overlay();
266 void full_try();
267 void full_force();
268 void ignore_redirect();
269 void ordersnap();
270 void returnvec();
271
272 std::size_t size() const;
273 using Signature = void(boost::system::error_code);
274 using Completion = ceph::async::Completion<Signature>;
275
276 friend std::ostream& operator <<(std::ostream& m, const Op& o);
277protected:
278 Op();
279 static constexpr std::size_t impl_size = 85 * 8;
280 std::aligned_storage_t<impl_size> impl;
281};
282
283// This class is /not/ thread-safe. If you want you can wrap it in
284// something that locks it.
285
286class ReadOp final : public Op {
287 friend RADOS;
288
289public:
290
291 ReadOp() = default;
292 ReadOp(const ReadOp&) = delete;
293 ReadOp(ReadOp&&) = default;
294
295 ReadOp& operator =(const ReadOp&) = delete;
296 ReadOp& operator =(ReadOp&&) = default;
297
298 void read(size_t off, uint64_t len, ceph::buffer::list* out,
299 boost::system::error_code* ec = nullptr);
300 void get_xattr(std::string_view name, ceph::buffer::list* out,
301 boost::system::error_code* ec = nullptr);
302 void get_omap_header(ceph::buffer::list*,
303 boost::system::error_code* ec = nullptr);
304
305 void sparse_read(uint64_t off, uint64_t len,
306 ceph::buffer::list* out,
307 std::vector<std::pair<std::uint64_t, std::uint64_t>>* extents,
308 boost::system::error_code* ec = nullptr);
309
310 void stat(std::uint64_t* size, ceph::real_time* mtime,
311 boost::system::error_code* ec = nullptr);
312
313 void get_omap_keys(std::optional<std::string_view> start_after,
314 std::uint64_t max_return,
315 boost::container::flat_set<std::string>* keys,
316 bool* truncated,
317 boost::system::error_code* ec = nullptr);
318
319
320 void get_xattrs(boost::container::flat_map<std::string,
321 ceph::buffer::list>* kv,
322 boost::system::error_code* ec = nullptr);
323
324 void get_omap_vals(std::optional<std::string_view> start_after,
325 std::optional<std::string_view> filter_prefix,
326 uint64_t max_return,
327 boost::container::flat_map<std::string,
328 ceph::buffer::list>* kv,
329 bool* truncated,
330 boost::system::error_code* ec = nullptr);
331
332
333 void get_omap_vals_by_keys(const boost::container::flat_set<std::string>& keys,
334 boost::container::flat_map<std::string,
335 ceph::buffer::list>* kv,
336 boost::system::error_code* ec = nullptr);
337
338 void list_watchers(std::vector<struct ObjWatcher>* watchers,
339 boost::system::error_code* ec = nullptr);
340
341 void list_snaps(struct SnapSet* snaps,
342 boost::system::error_code* ec = nullptr);
343};
344
345class WriteOp final : public Op {
346 friend RADOS;
347public:
348
349 WriteOp() = default;
350 WriteOp(const WriteOp&) = delete;
351 WriteOp(WriteOp&&) = default;
352
353 WriteOp& operator =(const WriteOp&) = delete;
354 WriteOp& operator =(WriteOp&&) = default;
355
356 void set_mtime(ceph::real_time t);
357 void create(bool exclusive);
358 void write(uint64_t off, ceph::buffer::list&& bl);
359 void write_full(ceph::buffer::list&& bl);
360 void writesame(std::uint64_t off, std::uint64_t write_len,
361 ceph::buffer::list&& bl);
362 void append(ceph::buffer::list&& bl);
363 void remove();
364 void truncate(uint64_t off);
365 void zero(uint64_t off, uint64_t len);
366 void rmxattr(std::string_view name);
367 void setxattr(std::string_view name,
368 ceph::buffer::list&& bl);
369 void rollback(uint64_t snapid);
370 void set_omap(const boost::container::flat_map<std::string,
371 ceph::buffer::list>& map);
372 void set_omap_header(ceph::buffer::list&& bl);
373 void clear_omap();
374 void rm_omap_keys(const boost::container::flat_set<std::string>& to_rm);
375 void set_alloc_hint(uint64_t expected_object_size,
376 uint64_t expected_write_size,
377 alloc_hint::alloc_hint_t flags);
378};
379
380
381struct FSStats {
382 uint64_t kb;
383 uint64_t kb_used;
384 uint64_t kb_avail;
385 uint64_t num_objects;
386};
387
388// From librados.h, maybe move into a common file. But I want to see
389// if we need/want to amend/add/remove anything first.
390struct PoolStats {
391 /// space used in bytes
392 uint64_t num_bytes;
393 /// space used in KB
394 uint64_t num_kb;
395 /// number of objects in the pool
396 uint64_t num_objects;
397 /// number of clones of objects
398 uint64_t num_object_clones;
399 /// num_objects * num_replicas
400 uint64_t num_object_copies;
401 /// number of objects missing on primary
402 uint64_t num_objects_missing_on_primary;
403 /// number of objects found on no OSDs
404 uint64_t num_objects_unfound;
405 /// number of objects replicated fewer times than they should be
406 /// (but found on at least one OSD)
407 uint64_t num_objects_degraded;
408 /// number of objects read
409 uint64_t num_rd;
410 /// objects read in KB
411 uint64_t num_rd_kb;
412 /// number of objects written
413 uint64_t num_wr;
414 /// objects written in KB
415 uint64_t num_wr_kb;
416 /// bytes originally provided by user
417 uint64_t num_user_bytes;
418 /// bytes passed compression
419 uint64_t compressed_bytes_orig;
420 /// bytes resulted after compression
421 uint64_t compressed_bytes;
422 /// bytes allocated at storage
423 uint64_t compressed_bytes_alloc;
424};
425
426// Placement group, for PG commands
427struct PG {
428 uint64_t pool;
429 uint32_t seed;
430};
431
432class Cursor final {
433public:
434 static Cursor begin();
435 static Cursor end();
436
437 Cursor();
438 Cursor(const Cursor&);
439 Cursor& operator =(const Cursor&);
440 Cursor(Cursor&&);
441 Cursor& operator =(Cursor&&);
442 ~Cursor();
443
444 friend bool operator ==(const Cursor& lhs,
445 const Cursor& rhs);
446 friend bool operator !=(const Cursor& lhs,
447 const Cursor& rhs);
448 friend bool operator <(const Cursor& lhs,
449 const Cursor& rhs);
450 friend bool operator <=(const Cursor& lhs,
451 const Cursor& rhs);
452 friend bool operator >=(const Cursor& lhs,
453 const Cursor& rhs);
454 friend bool operator >(const Cursor& lhs,
455 const Cursor& rhs);
456
457 std::string to_str() const;
458 static std::optional<Cursor> from_str(const std::string& s);
459
460private:
461 struct end_magic_t {};
462 Cursor(end_magic_t);
463 Cursor(void*);
464 friend RADOS;
465 static constexpr std::size_t impl_size = 16 * 8;
466 std::aligned_storage_t<impl_size> impl;
467};
468
469class RADOS final
470{
471public:
472 static constexpr std::tuple<uint32_t, uint32_t, uint32_t> version() {
473 return {0, 0, 1};
474 }
475
476 using BuildSig = void(boost::system::error_code, RADOS);
477 using BuildComp = ceph::async::Completion<BuildSig>;
478 class Builder {
479 std::optional<std::string> conf_files;
480 std::optional<std::string> cluster;
481 std::optional<std::string> name;
482 std::vector<std::pair<std::string, std::string>> configs;
483 bool no_default_conf = false;
484 bool no_mon_conf = false;
485
486 public:
487 Builder() = default;
488 Builder& add_conf_file(std::string_view v);
489 Builder& set_cluster(std::string_view c) {
490 cluster = std::string(c);
491 return *this;
492 }
493 Builder& set_name(std::string_view n) {
494 name = std::string(n);
495 return *this;
496 }
497 Builder& set_no_default_conf() {
498 no_default_conf = true;
499 return *this;
500 }
501 Builder& set_no_mon_conf() {
502 no_mon_conf = true;
503 return *this;
504 }
505 Builder& set_conf_option(std::string_view opt, std::string_view val) {
506 configs.emplace_back(std::string(opt), std::string(val));
507 return *this;
508 }
509
510 template<typename CompletionToken>
511 auto build(boost::asio::io_context& ioctx, CompletionToken&& token) {
512 boost::asio::async_completion<CompletionToken, BuildSig> init(token);
513 build(ioctx,
514 BuildComp::create(ioctx.get_executor(),
515 std::move(init.completion_handler)));
516 return init.result.get();
517 }
518
519 private:
520 void build(boost::asio::io_context& ioctx,
521 std::unique_ptr<BuildComp> c);
522 };
523
524
525 template<typename CompletionToken>
526 static auto make_with_cct(CephContext* cct,
527 boost::asio::io_context& ioctx,
528 CompletionToken&& token) {
529 boost::asio::async_completion<CompletionToken, BuildSig> init(token);
530 make_with_cct(cct, ioctx,
531 BuildComp::create(ioctx.get_executor(),
532 std::move(init.completion_handler)));
533 return init.result.get();
534 }
535
536 static RADOS make_with_librados(librados::Rados& rados);
537
538 RADOS(const RADOS&) = delete;
539 RADOS& operator =(const RADOS&) = delete;
540
541 RADOS(RADOS&&);
542 RADOS& operator =(RADOS&&);
543
544 ~RADOS();
545
546 CephContext* cct();
547
548 using executor_type = boost::asio::io_context::executor_type;
549 executor_type get_executor() const;
550 boost::asio::io_context& get_io_context();
551
552 template<typename CompletionToken>
553 auto execute(const Object& o, const IOContext& ioc, ReadOp&& op,
554 ceph::buffer::list* bl,
555 CompletionToken&& token, uint64_t* objver = nullptr,
556 const blkin_trace_info* trace_info = nullptr) {
557 boost::asio::async_completion<CompletionToken, Op::Signature> init(token);
558 execute(o, ioc, std::move(op), bl,
559 ReadOp::Completion::create(get_executor(),
560 std::move(init.completion_handler)),
561 objver, trace_info);
562 return init.result.get();
563 }
564
565 template<typename CompletionToken>
566 auto execute(const Object& o, const IOContext& ioc, WriteOp&& op,
567 CompletionToken&& token, uint64_t* objver = nullptr,
568 const blkin_trace_info* trace_info = nullptr) {
569 boost::asio::async_completion<CompletionToken, Op::Signature> init(token);
570 execute(o, ioc, std::move(op),
571 Op::Completion::create(get_executor(),
572 std::move(init.completion_handler)),
573 objver, trace_info);
574 return init.result.get();
575 }
576
577 template<typename CompletionToken>
578 auto execute(const Object& o, std::int64_t pool,
579 ReadOp&& op,
580 ceph::buffer::list* bl,
581 CompletionToken&& token,
582 std::optional<std::string_view> ns = {},
583 std::optional<std::string_view> key = {},
584 uint64_t* objver = nullptr) {
585 boost::asio::async_completion<CompletionToken, Op::Signature> init(token);
586 execute(o, pool, std::move(op), bl,
587 ReadOp::Completion::create(get_executor(),
588 std::move(init.completion_handler)),
589 ns, key, objver);
590 return init.result.get();
591 }
592
593 template<typename CompletionToken>
594 auto execute(const Object& o, std::int64_t pool, WriteOp&& op,
595 CompletionToken&& token,
596 std::optional<std::string_view> ns = {},
597 std::optional<std::string_view> key = {},
598 uint64_t* objver = nullptr) {
599 boost::asio::async_completion<CompletionToken, Op::Signature> init(token);
600 execute(o, pool, std::move(op),
601 Op::Completion::create(get_executor(),
602 std::move(init.completion_handler)),
603 ns, key, objver);
604 return init.result.get();
605 }
606
607 boost::uuids::uuid get_fsid() const noexcept;
608
609 using LookupPoolSig = void(boost::system::error_code,
610 std::int64_t);
611 using LookupPoolComp = ceph::async::Completion<LookupPoolSig>;
612 template<typename CompletionToken>
613 auto lookup_pool(std::string_view name,
614 CompletionToken&& token) {
615 boost::asio::async_completion<CompletionToken, LookupPoolSig> init(token);
616 lookup_pool(name,
617 LookupPoolComp::create(get_executor(),
618 std::move(init.completion_handler)));
619 return init.result.get();
620 }
621
622 std::optional<uint64_t> get_pool_alignment(int64_t pool_id);
623
624 using LSPoolsSig = void(std::vector<std::pair<std::int64_t, std::string>>);
625 using LSPoolsComp = ceph::async::Completion<LSPoolsSig>;
626 template<typename CompletionToken>
627 auto list_pools(CompletionToken&& token) {
628 boost::asio::async_completion<CompletionToken, LSPoolsSig> init(token);
629 list_pools(LSPoolsComp::create(get_executor(),
630 std::move(init.completion_handler)));
631 return init.result.get();
632 }
633
634
635
636 using SimpleOpSig = void(boost::system::error_code);
637 using SimpleOpComp = ceph::async::Completion<SimpleOpSig>;
638 template<typename CompletionToken>
639 auto create_pool_snap(int64_t pool, std::string_view snapName,
640 CompletionToken&& token) {
641 boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token);
642 create_pool_snap(pool, snapName,
643 SimpleOpComp::create(get_executor(),
644 std::move(init.completion_handler)));
645 return init.result.get();
646 }
647
648 using SMSnapSig = void(boost::system::error_code, std::uint64_t);
649 using SMSnapComp = ceph::async::Completion<SMSnapSig>;
650 template<typename CompletionToken>
651 auto allocate_selfmanaged_snap(int64_t pool,
652 CompletionToken&& token) {
653 boost::asio::async_completion<CompletionToken, SMSnapSig> init(token);
654 allocate_selfmanaged_snap(pool,
655 SMSnapComp::create(
656 get_executor(),
657 std::move(init.completion_handler)));
658 return init.result.get();
659 }
660
661 template<typename CompletionToken>
662 auto delete_pool_snap(int64_t pool, std::string_view snapName,
663 CompletionToken&& token) {
664 boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token);
665 delete_pool_snap(pool, snapName,
666 SimpleOpComp::create(get_executor(),
667 std::move(init.completion_handler)));
668 return init.result.get();
669 }
670
671 template<typename CompletionToken>
672 auto delete_selfmanaged_snap(int64_t pool, std::string_view snapName,
673 CompletionToken&& token) {
674 boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token);
675 delete_selfmanaged_snap(pool, snapName,
676 SimpleOpComp::create(
677 get_executor(),
678 std::move(init.completion_handler)));
679 return init.result.get();
680 }
681
682 template<typename CompletionToken>
683 auto create_pool(std::string_view name, std::optional<int> crush_rule,
684 CompletionToken&& token) {
685 boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token);
686 create_pool(name, crush_rule,
687 SimpleOpComp::create(get_executor(),
688 std::move(init.completion_handler)));
689 return init.result.get();
690 }
691
692 template<typename CompletionToken>
693 auto delete_pool(std::string_view name,
694 CompletionToken&& token) {
695 boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token);
696 delete_pool(name,
697 SimpleOpComp::create(get_executor(),
698 std::move(init.completion_handler)));
699 return init.result.get();
700 }
701
702 template<typename CompletionToken>
703 auto delete_pool(int64_t pool,
704 CompletionToken&& token) {
705 boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token);
706 delete_pool(pool,
707 SimpleOpComp::create(get_executor(),
708 std::move(init.completion_handler)));
709 return init.result.get();
710 }
711
712 using PoolStatSig = void(boost::system::error_code,
713 boost::container::flat_map<std::string,
714 PoolStats>, bool);
715 using PoolStatComp = ceph::async::Completion<PoolStatSig>;
716 template<typename CompletionToken>
717 auto stat_pools(const std::vector<std::string>& pools,
718 CompletionToken&& token) {
719 boost::asio::async_completion<CompletionToken, PoolStatSig> init(token);
720 stat_pools(pools,
721 PoolStatComp::create(get_executor(),
722 std::move(init.completion_handler)));
723 return init.result.get();
724 }
725
726 using StatFSSig = void(boost::system::error_code,
727 FSStats);
728 using StatFSComp = ceph::async::Completion<StatFSSig>;
729 template<typename CompletionToken>
730 auto statfs(std::optional<int64_t> pool,
731 CompletionToken&& token) {
732 boost::asio::async_completion<CompletionToken, StatFSSig> init(token);
733 ceph_statfs(pool, StatFSComp::create(get_executor(),
734 std::move(init.completion_handler)));
735 return init.result.get();
736 }
737
738 using WatchCB = fu2::unique_function<void(boost::system::error_code,
739 uint64_t notify_id,
740 uint64_t cookie,
741 uint64_t notifier_id,
742 ceph::buffer::list&& bl)>;
743
744 using WatchSig = void(boost::system::error_code ec,
745 uint64_t cookie);
746 using WatchComp = ceph::async::Completion<WatchSig>;
747 template<typename CompletionToken>
748 auto watch(const Object& o, const IOContext& ioc,
749 std::optional<std::chrono::seconds> timeout,
750 WatchCB&& cb, CompletionToken&& token) {
751 boost::asio::async_completion<CompletionToken, WatchSig> init(token);
752 watch(o, ioc, timeout, std::move(cb),
753 WatchComp::create(get_executor(),
754 std::move(init.completion_handler)));
755 return init.result.get();
756 }
757
758 template<typename CompletionToken>
759 auto watch(const Object& o, std::int64_t pool,
760 std::optional<std::chrono::seconds> timeout,
761 WatchCB&& cb, CompletionToken&& token,
762 std::optional<std::string_view> ns = {},
763 std::optional<std::string_view> key = {}) {
764 boost::asio::async_completion<CompletionToken, WatchSig> init(token);
765 watch(o, pool, timeout, std::move(cb),
766 WatchComp::create(get_executor(),
767 std::move(init.completion_handler)),
768 ns, key);
769 return init.result.get();
770 }
771
772 template<typename CompletionToken>
773 auto notify_ack(const Object& o,
774 const IOContext& ioc,
775 uint64_t notify_id,
776 uint64_t cookie,
777 ceph::buffer::list&& bl,
778 CompletionToken&& token) {
779 boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token);
780 notify_ack(o, ioc, notify_id, cookie, std::move(bl),
781 SimpleOpComp::create(get_executor(),
782 std::move(init.completion_handler)));
783 return init.result.get();
784 }
785
786 template<typename CompletionToken>
787 auto notify_ack(const Object& o,
788 std::int64_t pool,
789 uint64_t notify_id,
790 uint64_t cookie,
791 ceph::buffer::list&& bl,
792 CompletionToken&& token,
793 std::optional<std::string_view> ns = {},
794 std::optional<std::string_view> key = {}) {
795 boost::asio::async_completion<CompletionToken, WatchSig> init(token);
796 notify_ack(o, pool, notify_id, cookie, std::move(bl),
797 SimpleOpComp::create(get_executor(),
798 std::move(init.completion_handler)),
799 ns, key);
800 return init.result.get();
801 }
802
803 template<typename CompletionToken>
804 auto unwatch(uint64_t cookie, const IOContext& ioc,
805 CompletionToken&& token) {
806 boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token);
807 unwatch(cookie, ioc,
808 SimpleOpComp::create(get_executor(),
809 std::move(init.completion_handler)));
810 return init.result.get();
811 }
812
813 template<typename CompletionToken>
814 auto unwatch(uint64_t cookie, std::int64_t pool,
815 CompletionToken&& token,
816 std::optional<std::string_view> ns = {},
817 std::optional<std::string_view> key = {}) {
818 boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token);
819 unwatch(cookie, pool,
820 SimpleOpComp::create(get_executor(),
821 std::move(init.completion_handler)),
822 ns, key);
823 return init.result.get();
824 }
825
826 // This is one of those places where having to force everything into
827 // a .cc file is really infuriating. If we had modules, that would
828 // let us separate out the implementation details without
829 // sacrificing all the benefits of templates.
830 using VoidOpSig = void();
831 using VoidOpComp = ceph::async::Completion<VoidOpSig>;
832 template<typename CompletionToken>
833 auto flush_watch(CompletionToken&& token) {
834 boost::asio::async_completion<CompletionToken, VoidOpSig> init(token);
835 flush_watch(VoidOpComp::create(get_executor(),
836 std::move(init.completion_handler)));
837 return init.result.get();
838 }
839
840 using NotifySig = void(boost::system::error_code, ceph::buffer::list);
841 using NotifyComp = ceph::async::Completion<NotifySig>;
842 template<typename CompletionToken>
843 auto notify(const Object& oid, const IOContext& ioc, ceph::buffer::list&& bl,
844 std::optional<std::chrono::milliseconds> timeout,
845 CompletionToken&& token) {
846 boost::asio::async_completion<CompletionToken, NotifySig> init(token);
847 notify(oid, ioc, std::move(bl), timeout,
848 NotifyComp::create(get_executor(),
849 std::move(init.completion_handler)));
850
851 return init.result.get();
852 }
853
854 template<typename CompletionToken>
855 auto notify(const Object& oid, std::int64_t pool, ceph::buffer::list&& bl,
856 std::optional<std::chrono::milliseconds> timeout,
857 CompletionToken&& token,
858 std::optional<std::string_view> ns = {},
859 std::optional<std::string_view> key = {}) {
860 boost::asio::async_completion<CompletionToken, NotifySig> init(token);
861 notify(oid, pool, bl, timeout,
862 NotifyComp::create(get_executor(),
863 std::move(init.completion_handler)),
864 ns, key);
865
866 return init.result.get();
867 }
868
869 // The versions with pointers are fine for coroutines, but
870 // extraordinarily unappealing for callback-oriented programming.
871 using EnumerateSig = void(boost::system::error_code,
872 std::vector<Entry>,
873 Cursor);
874 using EnumerateComp = ceph::async::Completion<EnumerateSig>;
875 template<typename CompletionToken>
876 auto enumerate_objects(const IOContext& ioc, const Cursor& begin,
877 const Cursor& end, const std::uint32_t max,
878 const ceph::buffer::list& filter,
879 CompletionToken&& token) {
880 boost::asio::async_completion<CompletionToken, EnumerateSig> init(token);
881 enumerate_objects(ioc, begin, end, max, filter,
882 EnumerateComp::create(get_executor(),
883 std::move(init.completion_handler)));
884 return init.result.get();
885 }
886
887 template<typename CompletionToken>
888 auto enumerate_objects(std::int64_t pool, const Cursor& begin,
889 const Cursor& end, const std::uint32_t max,
890 const ceph::buffer::list& filter,
891 CompletionToken&& token,
892 std::optional<std::string_view> ns = {},
893 std::optional<std::string_view> key = {}) {
894 boost::asio::async_completion<CompletionToken, EnumerateSig> init(token);
895 enumerate_objects(pool, begin, end, max, filter,
896 EnumerateComp::create(get_executor(),
897 std::move(init.completion_handler)),
898 ns, key);
899 return init.result.get();
900 }
901
902 using CommandSig = void(boost::system::error_code,
903 std::string, ceph::buffer::list);
904 using CommandComp = ceph::async::Completion<CommandSig>;
905 template<typename CompletionToken>
906 auto osd_command(int osd, std::vector<std::string>&& cmd,
907 ceph::buffer::list&& in, CompletionToken&& token) {
908 boost::asio::async_completion<CompletionToken, CommandSig> init(token);
909 osd_command(osd, std::move(cmd), std::move(in),
910 CommandComp::create(get_executor(),
911 std::move(init.completion_handler)));
912 return init.result.get();
913 }
914 template<typename CompletionToken>
915 auto pg_command(PG pg, std::vector<std::string>&& cmd,
916 ceph::buffer::list&& in, CompletionToken&& token) {
917 boost::asio::async_completion<CompletionToken, CommandSig> init(token);
918 pg_command(pg, std::move(cmd), std::move(in),
919 CommandComp::create(get_executor(),
920 std::move(init.completion_handler)));
921 return init.result.get();
922 }
923
924 template<typename CompletionToken>
925 auto mon_command(std::vector<std::string> command,
926 const ceph::buffer::list& bl,
927 std::string* outs, ceph::buffer::list* outbl,
928 CompletionToken&& token) {
929 boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token);
930 mon_command(command, bl, outs, outbl,
931 SimpleOpComp::create(get_executor(),
932 std::move(init.completion_handler)));
933 return init.result.get();
934 }
935
936 template<typename CompletionToken>
937 auto enable_application(std::string_view pool, std::string_view app_name,
938 bool force, CompletionToken&& token) {
939 boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token);
940 enable_application(pool, app_name, force,
941 SimpleOpComp::create(get_executor(),
942 std::move(init.completion_handler)));
943 return init.result.get();
944 }
945
946 template<typename CompletionToken>
947 auto blocklist_add(std::string_view client_address,
948 std::optional<std::chrono::seconds> expire,
949 CompletionToken&& token) {
950 boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token);
951 blocklist_add(client_address, expire,
952 SimpleOpComp::create(get_executor(),
953 std::move(init.completion_handler)));
954 return init.result.get();
955 }
956
957 template<typename CompletionToken>
958 auto wait_for_latest_osd_map(CompletionToken&& token) {
959 boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token);
960 wait_for_latest_osd_map(
961 SimpleOpComp::create(get_executor(), std::move(init.completion_handler)));
962 return init.result.get();
963 }
964
965 uint64_t instance_id() const;
966
967private:
968
969 RADOS();
970
971 friend Builder;
972
973 RADOS(std::unique_ptr<detail::Client> impl);
974 static void make_with_cct(CephContext* cct,
975 boost::asio::io_context& ioctx,
976 std::unique_ptr<BuildComp> c);
977
978 void execute(const Object& o, const IOContext& ioc, ReadOp&& op,
979 ceph::buffer::list* bl, std::unique_ptr<Op::Completion> c,
980 uint64_t* objver, const blkin_trace_info* trace_info);
981
982 void execute(const Object& o, const IOContext& ioc, WriteOp&& op,
983 std::unique_ptr<Op::Completion> c, uint64_t* objver,
984 const blkin_trace_info* trace_info);
985
986 void execute(const Object& o, std::int64_t pool, ReadOp&& op,
987 ceph::buffer::list* bl, std::unique_ptr<Op::Completion> c,
988 std::optional<std::string_view> ns,
989 std::optional<std::string_view> key,
990 uint64_t* objver);
991
992 void execute(const Object& o, std::int64_t pool, WriteOp&& op,
993 std::unique_ptr<Op::Completion> c,
994 std::optional<std::string_view> ns,
995 std::optional<std::string_view> key,
996 uint64_t* objver);
997
998 void lookup_pool(std::string_view name, std::unique_ptr<LookupPoolComp> c);
999 void list_pools(std::unique_ptr<LSPoolsComp> c);
1000 void create_pool_snap(int64_t pool, std::string_view snapName,
1001 std::unique_ptr<SimpleOpComp> c);
1002 void allocate_selfmanaged_snap(int64_t pool, std::unique_ptr<SMSnapComp> c);
1003 void delete_pool_snap(int64_t pool, std::string_view snapName,
1004 std::unique_ptr<SimpleOpComp> c);
1005 void delete_selfmanaged_snap(int64_t pool, std::uint64_t snap,
1006 std::unique_ptr<SimpleOpComp> c);
1007 void create_pool(std::string_view name, std::optional<int> crush_rule,
1008 std::unique_ptr<SimpleOpComp> c);
1009 void delete_pool(std::string_view name,
1010 std::unique_ptr<SimpleOpComp> c);
1011 void delete_pool(int64_t pool,
1012 std::unique_ptr<SimpleOpComp> c);
1013 void stat_pools(const std::vector<std::string>& pools,
1014 std::unique_ptr<PoolStatComp> c);
1015 void stat_fs(std::optional<std::int64_t> pool,
1016 std::unique_ptr<StatFSComp> c);
1017
1018 void watch(const Object& o, const IOContext& ioc,
1019 std::optional<std::chrono::seconds> timeout,
1020 WatchCB&& cb, std::unique_ptr<WatchComp> c);
1021 void watch(const Object& o, std::int64_t pool,
1022 std::optional<std::chrono::seconds> timeout,
1023 WatchCB&& cb, std::unique_ptr<WatchComp> c,
1024 std::optional<std::string_view> ns,
1025 std::optional<std::string_view> key);
1026 tl::expected<ceph::timespan, boost::system::error_code>
1027 watch_check(uint64_t cookie);
1028 void notify_ack(const Object& o,
1029 const IOContext& _ioc,
1030 uint64_t notify_id,
1031 uint64_t cookie,
1032 ceph::buffer::list&& bl,
1033 std::unique_ptr<SimpleOpComp>);
1034 void notify_ack(const Object& o,
1035 std::int64_t pool,
1036 uint64_t notify_id,
1037 uint64_t cookie,
1038 ceph::buffer::list&& bl,
1039 std::unique_ptr<SimpleOpComp>,
1040 std::optional<std::string_view> ns,
1041 std::optional<std::string_view> key);
1042 void unwatch(uint64_t cookie, const IOContext& ioc,
1043 std::unique_ptr<SimpleOpComp>);
1044 void unwatch(uint64_t cookie, std::int64_t pool,
1045 std::unique_ptr<SimpleOpComp>,
1046 std::optional<std::string_view> ns,
1047 std::optional<std::string_view> key);
1048 void notify(const Object& oid, const IOContext& ioctx,
1049 ceph::buffer::list&& bl,
1050 std::optional<std::chrono::milliseconds> timeout,
1051 std::unique_ptr<NotifyComp> c);
1052 void notify(const Object& oid, std::int64_t pool,
1053 ceph::buffer::list&& bl,
1054 std::optional<std::chrono::milliseconds> timeout,
1055 std::unique_ptr<NotifyComp> c,
1056 std::optional<std::string_view> ns,
1057 std::optional<std::string_view> key);
1058 void flush_watch(std::unique_ptr<VoidOpComp>);
1059
1060 void enumerate_objects(const IOContext& ioc, const Cursor& begin,
1061 const Cursor& end, const std::uint32_t max,
1062 const ceph::buffer::list& filter,
1063 std::vector<Entry>* ls,
1064 Cursor* cursor,
1065 std::unique_ptr<SimpleOpComp> c);
1066 void enumerate_objects(std::int64_t pool, const Cursor& begin,
1067 const Cursor& end, const std::uint32_t max,
1068 const ceph::buffer::list& filter,
1069 std::vector<Entry>* ls,
1070 Cursor* cursor,
1071 std::unique_ptr<SimpleOpComp> c,
1072 std::optional<std::string_view> ns,
1073 std::optional<std::string_view> key);
1074 void enumerate_objects(const IOContext& ioc, const Cursor& begin,
1075 const Cursor& end, const std::uint32_t max,
1076 const ceph::buffer::list& filter,
1077 std::unique_ptr<EnumerateComp> c);
1078 void enumerate_objects(std::int64_t pool, const Cursor& begin,
1079 const Cursor& end, const std::uint32_t max,
1080 const ceph::buffer::list& filter,
1081 std::unique_ptr<EnumerateComp> c,
1082 std::optional<std::string_view> ns,
1083 std::optional<std::string_view> key);
1084 void osd_command(int osd, std::vector<std::string>&& cmd,
1085 ceph::buffer::list&& in, std::unique_ptr<CommandComp> c);
1086 void pg_command(PG pg, std::vector<std::string>&& cmd,
1087 ceph::buffer::list&& in, std::unique_ptr<CommandComp> c);
1088
1089 void mon_command(std::vector<std::string> command,
1090 const ceph::buffer::list& bl,
1091 std::string* outs, ceph::buffer::list* outbl,
1092 std::unique_ptr<SimpleOpComp> c);
1093
1094 void enable_application(std::string_view pool, std::string_view app_name,
1095 bool force, std::unique_ptr<SimpleOpComp> c);
1096
1097 void blocklist_add(std::string_view client_address,
1098 std::optional<std::chrono::seconds> expire,
1099 std::unique_ptr<SimpleOpComp> c);
1100
1101 void wait_for_latest_osd_map(std::unique_ptr<SimpleOpComp> c);
1102
1103 // Proxy object to provide access to low-level RADOS messaging clients
1104 std::unique_ptr<detail::Client> impl;
1105};
1106
1107enum class errc {
1108 pool_dne = 1,
1109 invalid_snapcontext
1110};
1111
1112const boost::system::error_category& error_category() noexcept;
1113}
1114
1115namespace boost::system {
1116template<>
1117struct is_error_code_enum<::neorados::errc> {
1118 static const bool value = true;
1119};
1120
1121template<>
1122struct is_error_condition_enum<::neorados::errc> {
1123 static const bool value = false;
1124};
1125}
1126
1127namespace neorados {
1128// explicit conversion:
1129inline boost::system::error_code make_error_code(errc e) noexcept {
1130 return { static_cast<int>(e), error_category() };
1131}
1132
1133// implicit conversion:
1134inline boost::system::error_condition make_error_condition(errc e) noexcept {
1135 return { static_cast<int>(e), error_category() };
1136}
1137}
1138
1139namespace std {
1140template<>
1141struct hash<neorados::Object> {
1142 size_t operator ()(const neorados::Object& r) const;
1143};
1144template<>
1145struct hash<neorados::IOContext> {
1146 size_t operator ()(const neorados::IOContext& r) const;
1147};
1148} // namespace std
1149
1150#endif // NEORADOS_RADOS_HPP