diff options
author | Sage Weil <sage@redhat.com> | 2019-11-22 16:24:11 +0100 |
---|---|---|
committer | Sage Weil <sage@redhat.com> | 2019-11-22 16:24:25 +0100 |
commit | 54ddf2c8973663f04a820937001e248dda5b58e1 (patch) | |
tree | 61b3c94ad11a7cff7eb09af347495a9f6868f554 | |
parent | Merge PR #31798 into master (diff) | |
download | ceph-54ddf2c8973663f04a820937001e248dda5b58e1.tar.xz ceph-54ddf2c8973663f04a820937001e248dda5b58e1.zip |
Revert "Merge pull request #16715 from adamemerson/wip-I-Object!"
This reverts commit 669453138d89e0f797a1bd37f38a2d68e6aac366, reversing
changes made to 36f5fcbb97eb2b1bceb526331eb3464f460fc701.
Signed-off-by: Sage Weil <sage@redhat.com>
- conflicts due to code rearrangement in 14b0db908f652032c358e419ffa90f5676698d0e
120 files changed, 2177 insertions, 10233 deletions
diff --git a/.gitignore b/.gitignore index 2600c2c614e..a04d59a632e 100644 --- a/.gitignore +++ b/.gitignore @@ -73,6 +73,3 @@ GTAGS /src/pybind/mgr/dashboard/frontend/src/environments/environment.ts /src/pybind/mgr/dashboard/frontend/src/environments/environment.prod.ts /src/pybind/mgr/dashboard/frontend/src/locale/messages.xlf - -# Python building things where it shouldn't -/src/python-common/build/ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ca1631c2e20..5b89d039374 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -297,7 +297,6 @@ if(NOT fmt_FOUND) message(STATUS "Could not find fmt, will build it") add_subdirectory(fmt) endif() -include_directories(SYSTEM "${CMAKE_SOURCE_DIR}/src/fmt/include") if(WITH_SEASTAR) find_package(c-ares 1.13.0 QUIET) @@ -332,13 +331,11 @@ set(libcommon_files ${CMAKE_BINARY_DIR}/src/include/ceph_ver.h ceph_ver.c xxHash/xxhash.c - common/error_code.cc log/Log.cc mon/MonCap.cc mon/MonClient.cc mon/MonMap.cc mon/MonSub.cc - mon/error_code.cc mgr/MgrClient.cc mon/PGMap.cc mgr/ServiceMap.cc @@ -347,12 +344,10 @@ set(libcommon_files osd/OSDMap.cc osd/OSDMapMapping.cc osd/osd_types.cc - osd/error_code.cc osd/PGPeeringEvent.cc osd/OpRequest.cc osdc/Striper.cc osdc/Objecter.cc - osdc/error_code.cc librbd/Features.cc ${mds_files}) set_source_files_properties(ceph_ver.c @@ -480,7 +475,6 @@ option(WITH_LIBRADOSSTRIPER "build with libradosstriper support" ON) add_subdirectory(include) add_subdirectory(librados) -add_subdirectory(RADOS) if(WITH_LIBRADOSSTRIPER) add_subdirectory(libradosstriper) diff --git a/src/RADOS/CMakeLists.txt b/src/RADOS/CMakeLists.txt deleted file mode 100644 index c8d4f1bb2e0..00000000000 --- a/src/RADOS/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -add_library(RADOS_objs OBJECT - RADOSImpl.cc) -add_library(RADOS_api_obj OBJECT - RADOS.cc) - -add_library(libRADOS STATIC - $<TARGET_OBJECTS:RADOS_api_obj> - $<TARGET_OBJECTS:RADOS_objs>) -target_link_libraries(libRADOS PRIVATE - osdc ceph-common cls_lock_client fmt::fmt - ${BLKID_LIBRARIES} ${CRYPTO_LIBS} ${EXTRALIBS}) - -# if(ENABLE_SHARED) -# add_library(libRADOS ${CEPH_SHARED} -# $<TARGET_OBJECTS:RADOS_api_obj> -# $<TARGET_OBJECTS:RADOS_objs> -# $<TARGET_OBJECTS:common_buffer_obj>) -# set_target_properties(libRADOS PROPERTIES -# OUTPUT_NAME RADOS -# VERSION 0.0.1 -# SOVERSION 1 -# CXX_VISIBILITY_PRESET hidden -# VISIBILITY_INLINES_HIDDEN ON) -# if(NOT APPLE) -# set_property(TARGET libRADOS APPEND_STRING PROPERTY -# LINK_FLAGS " -Wl,--exclude-libs,ALL") -# endif() -# else(ENABLE_SHARED) -# add_library(libRADOS STATIC -# $<TARGET_OBJECTS:RADOS_api_obj> -# $<TARGET_OBJECTS:RADOS_objs>) -# endif(ENABLE_SHARED) -# target_link_libraries(libRADOS PRIVATE -# osdc ceph-common cls_lock_client -# ${BLKID_LIBRARIES} ${CRYPTO_LIBS} ${EXTRALIBS}) -# target_link_libraries(libRADOS ${rados_libs}) -# install(TARGETS libRADOS DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/src/RADOS/RADOS.cc b/src/RADOS/RADOS.cc deleted file mode 100644 index e0a900fa8e2..00000000000 --- a/src/RADOS/RADOS.cc +++ /dev/null @@ -1,1475 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2018 Red Hat <contact@redhat.com> - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#define BOOST_BIND_NO_PLACEHOLDERS - -#include <optional> -#include <string_view> - -#include <boost/intrusive_ptr.hpp> - -#include <fmt/format.h> - -#include "include/ceph_fs.h" -#include "common/ceph_context.h" -#include "common/ceph_argparse.h" -#include "common/common_init.h" -#include "common/hobject.h" - -#include "global/global_init.h" - -#include "osd/osd_types.h" -#include "osdc/error_code.h" - -#include "RADOS/RADOSImpl.h" -#include "include/RADOS/RADOS.hpp" - -namespace bc = boost::container; -namespace bs = boost::system; -namespace ca = ceph::async; -namespace cb = ceph::buffer; - -namespace RADOS { -// Object - -Object::Object(std::string_view s) { - static_assert(impl_size >= sizeof(object_t)); - new (&impl) object_t(s); -} - -Object::Object(std::string&& s) { - static_assert(impl_size >= sizeof(object_t)); - new (&impl) object_t(std::move(s)); -} - -Object::Object(const std::string& s) { - static_assert(impl_size >= sizeof(object_t)); - new (&impl) object_t(s); -} - -Object::~Object() { - reinterpret_cast<object_t*>(&impl)->~object_t(); -} - -Object::Object(const Object& o) { - static_assert(impl_size >= sizeof(object_t)); - new (&impl) object_t(*reinterpret_cast<const object_t*>(&o.impl)); -} -Object& Object::operator =(const Object& o) { - *reinterpret_cast<object_t*>(&impl) = - *reinterpret_cast<const object_t*>(&o.impl); - return *this; -} -Object::Object(Object&& o) { - static_assert(impl_size >= sizeof(object_t)); - new (&impl) object_t(std::move(*reinterpret_cast<object_t*>(&o.impl))); -} -Object& Object::operator =(Object&& o) { - *reinterpret_cast<object_t*>(&impl) = - std::move(*reinterpret_cast<object_t*>(&o.impl)); - return *this; -} - -Object::operator std::string_view() const { - return std::string_view(reinterpret_cast<const object_t*>(&impl)->name); -} - -bool operator <(const Object& lhs, const Object& rhs) { - return (*reinterpret_cast<const object_t*>(&lhs.impl) < - *reinterpret_cast<const object_t*>(&rhs.impl)); -} -bool operator <=(const Object& lhs, const Object& rhs) { - return (*reinterpret_cast<const object_t*>(&lhs.impl) <= - *reinterpret_cast<const object_t*>(&rhs.impl)); -} -bool operator >=(const Object& lhs, const Object& rhs) { - return (*reinterpret_cast<const object_t*>(&lhs.impl) >= - *reinterpret_cast<const object_t*>(&rhs.impl)); -} -bool operator >(const Object& lhs, const Object& rhs) { - return (*reinterpret_cast<const object_t*>(&lhs.impl) > - *reinterpret_cast<const object_t*>(&rhs.impl)); -} - -bool operator ==(const Object& lhs, const Object& rhs) { - return (*reinterpret_cast<const object_t*>(&lhs.impl) == - *reinterpret_cast<const object_t*>(&rhs.impl)); -} -bool operator !=(const Object& lhs, const Object& rhs) { - return (*reinterpret_cast<const object_t*>(&lhs.impl) != - *reinterpret_cast<const object_t*>(&rhs.impl)); -} - -std::ostream& operator <<(std::ostream& m, const Object& o) { - return (m << *reinterpret_cast<const object_t*>(&o.impl)); -} - -// IOContext - -struct IOContextImpl { - object_locator_t oloc; - snapid_t snap_seq = CEPH_NOSNAP; - SnapContext snapc; -}; - -IOContext::IOContext() { - static_assert(impl_size >= sizeof(IOContextImpl)); - new (&impl) IOContextImpl(); -} - -IOContext::IOContext(std::int64_t _pool) : IOContext() { - pool(_pool); -} - -IOContext::IOContext(std::int64_t _pool, std::string_view _ns) - : IOContext() { - pool(_pool); - ns(_ns); -} - -IOContext::IOContext(std::int64_t _pool, std::string&& _ns) - : IOContext() { - pool(_pool); - ns(std::move(_ns)); -} - -IOContext::~IOContext() { - reinterpret_cast<IOContextImpl*>(&impl)->~IOContextImpl(); -} - -IOContext::IOContext(const IOContext& rhs) { - static_assert(impl_size >= sizeof(IOContextImpl)); - new (&impl) IOContextImpl(*reinterpret_cast<const IOContextImpl*>(&rhs.impl)); -} - -IOContext& IOContext::operator =(const IOContext& rhs) { - *reinterpret_cast<IOContextImpl*>(&impl) = - *reinterpret_cast<const IOContextImpl*>(&rhs.impl); - return *this; -} - -IOContext::IOContext(IOContext&& rhs) { - static_assert(impl_size >= sizeof(IOContextImpl)); - new (&impl) IOContextImpl( - std::move(*reinterpret_cast<IOContextImpl*>(&rhs.impl))); -} - -IOContext& IOContext::operator =(IOContext&& rhs) { - *reinterpret_cast<IOContextImpl*>(&impl) = - std::move(*reinterpret_cast<IOContextImpl*>(&rhs.impl)); - return *this; -} - -std::int64_t IOContext::pool() const { - return reinterpret_cast<const IOContextImpl*>(&impl)->oloc.pool; -} - -void IOContext::pool(std::int64_t _pool) { - reinterpret_cast<IOContextImpl*>(&impl)->oloc.pool = _pool; -} - -std::string_view IOContext::ns() const { - return reinterpret_cast<const IOContextImpl*>(&impl)->oloc.nspace; -} - -void IOContext::ns(std::string_view _ns) { - reinterpret_cast<IOContextImpl*>(&impl)->oloc.nspace = _ns; -} - -void IOContext::ns(std::string&& _ns) { - reinterpret_cast<IOContextImpl*>(&impl)->oloc.nspace = std::move(_ns); -} - -std::optional<std::string_view> IOContext::key() const { - auto& oloc = reinterpret_cast<const IOContextImpl*>(&impl)->oloc; - if (oloc.key.empty()) - return std::nullopt; - else - return std::string_view(oloc.key); -} - -void IOContext::key(std::string_view _key) { - auto& oloc = reinterpret_cast<IOContextImpl*>(&impl)->oloc; - if (_key.empty()) { - throw bs::system_error(EINVAL, - bs::system_category(), - "An empty key is no key at all."); - } else { - oloc.hash = -1; - oloc.key = _key; - } -} - -void IOContext::key(std::string&&_key) { - auto& oloc = reinterpret_cast<IOContextImpl*>(&impl)->oloc; - if (_key.empty()) { - throw bs::system_error(EINVAL, - bs::system_category(), - "An empty key is no key at all."); - } else { - oloc.hash = -1; - oloc.key = std::move(_key); - } -} - -void IOContext::clear_key() { - auto& oloc = reinterpret_cast<IOContextImpl*>(&impl)->oloc; - oloc.hash = -1; - oloc.key.clear(); -} - -std::optional<std::int64_t> IOContext::hash() const { - auto& oloc = reinterpret_cast<const IOContextImpl*>(&impl)->oloc; - if (oloc.hash < 0) - return std::nullopt; - else - return oloc.hash; -} - -void IOContext::hash(std::int64_t _hash) { - auto& oloc = reinterpret_cast<IOContextImpl*>(&impl)->oloc; - if (_hash < 0) { - throw bs::system_error(EINVAL, - bs::system_category(), - "A negative hash is no hash at all."); - } else { - oloc.hash = _hash; - oloc.key.clear(); - } -} - -void IOContext::clear_hash() { - auto& oloc = reinterpret_cast<IOContextImpl*>(&impl)->oloc; - oloc.hash = -1; - oloc.key.clear(); -} - - -std::optional<std::uint64_t> IOContext::read_snap() const { - auto& snap_seq = reinterpret_cast<const IOContextImpl*>(&impl)->snap_seq; - if (snap_seq == CEPH_NOSNAP) - return std::nullopt; - else - return snap_seq; -} -void IOContext::read_snap(std::optional<std::uint64_t> _snapid) { - auto& snap_seq = reinterpret_cast<IOContextImpl*>(&impl)->snap_seq; - snap_seq = _snapid.value_or(CEPH_NOSNAP); -} - -std::optional< - std::pair<std::uint64_t, - std::vector<std::uint64_t>>> IOContext::write_snap_context() const { - auto& snapc = reinterpret_cast<const IOContextImpl*>(&impl)->snapc; - if (snapc.empty()) { - return std::nullopt; - } else { - std::vector<uint64_t> v(snapc.snaps.begin(), snapc.snaps.end()); - return std::make_optional(std::make_pair(uint64_t(snapc.seq), v)); - } -} - -void IOContext::write_snap_context( - std::optional<std::pair<std::uint64_t, std::vector<std::uint64_t>>> _snapc) { - auto& snapc = reinterpret_cast<IOContextImpl*>(&impl)->snapc; - if (!_snapc) { - snapc.clear(); - } else { - SnapContext n(_snapc->first, { _snapc->second.begin(), _snapc->second.end()}); - if (!n.is_valid()) { - throw bs::system_error(EINVAL, - bs::system_category(), - "Invalid snap context."); - - } else { - snapc = n; - } - } -} - -// Op - -struct OpImpl { - ObjectOperation op; - std::optional<ceph::real_time> mtime; - - OpImpl() = default; - - OpImpl(const OpImpl& rhs) = delete; - OpImpl(OpImpl&& rhs) = default; - - OpImpl& operator =(const OpImpl& rhs) = delete; - OpImpl& operator =(OpImpl&& rhs) = default; -}; - -Op::Op() { - static_assert(Op::impl_size >= sizeof(OpImpl)); - new (&impl) OpImpl; -} - -Op::Op(Op&& rhs) { - new (&impl) OpImpl(std::move(*reinterpret_cast<OpImpl*>(&rhs.impl))); -} -Op& Op::operator =(Op&& rhs) { - reinterpret_cast<OpImpl*>(&impl)->~OpImpl(); - new (&impl) OpImpl(std::move(*reinterpret_cast<OpImpl*>(&rhs.impl))); - return *this; -} -Op::~Op() { - reinterpret_cast<OpImpl*>(&impl)->~OpImpl(); -} - -void Op::set_excl() { - reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags(CEPH_OSD_OP_FLAG_EXCL); -} -void Op::set_failok() { - reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags( - CEPH_OSD_OP_FLAG_FAILOK); -} -void Op::set_fadvise_random() { - reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags( - CEPH_OSD_OP_FLAG_FADVISE_RANDOM); -} -void Op::set_fadvise_sequential() { - reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags( - CEPH_OSD_OP_FLAG_FADVISE_SEQUENTIAL); -} -void Op::set_fadvise_willneed() { - reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags( - CEPH_OSD_OP_FLAG_FADVISE_WILLNEED); -} -void Op::set_fadvise_dontneed() { - reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags( - CEPH_OSD_OP_FLAG_FADVISE_DONTNEED); -} -void Op::set_fadvise_nocache() { - reinterpret_cast<OpImpl*>(&impl)->op.set_last_op_flags( - CEPH_OSD_OP_FLAG_FADVISE_NOCACHE); -} - -void Op::cmpext(uint64_t off, bufferlist&& cmp_bl, std::size_t* s) { - reinterpret_cast<OpImpl*>(&impl)->op.cmpext(off, std::move(cmp_bl), nullptr, - s); -} -void Op::cmpxattr(std::string_view name, cmpxattr_op op, const bufferlist& val) { - reinterpret_cast<OpImpl*>(&impl)-> - op.cmpxattr(name, std::uint8_t(op), CEPH_OSD_CMPXATTR_MODE_STRING, val); -} -void Op::cmpxattr(std::string_view name, cmpxattr_op op, std::uint64_t val) { - bufferlist bl; - encode(val, bl); - reinterpret_cast<OpImpl*>(&impl)-> - op.cmpxattr(name, std::uint8_t(op), CEPH_OSD_CMPXATTR_MODE_U64, bl); -} - -void Op::assert_version(uint64_t ver) { - reinterpret_cast<OpImpl*>(&impl)->op.assert_version(ver); -} -void Op::assert_exists() { - reinterpret_cast<OpImpl*>(&impl)->op.stat( - nullptr, - static_cast<ceph::real_time*>(nullptr), - static_cast<bs::error_code*>(nullptr)); -} -void Op::cmp_omap(const bc::flat_map< - std::string, std::pair<cb::list, - int>>& assertions) { - reinterpret_cast<OpImpl*>(&impl)->op.omap_cmp(assertions, nullptr); -} - -std::size_t Op::size() const { - return reinterpret_cast<const OpImpl*>(&impl)->op.size(); -} - -std::ostream& operator <<(std::ostream& m, const Op& o) { - return m << reinterpret_cast<const OpImpl*>(&o.impl)->op; -} - - -// --- - -// ReadOp / WriteOp - -void ReadOp::read(size_t off, uint64_t len, cb::list* out, - bs::error_code* ec) { - reinterpret_cast<OpImpl*>(&impl)->op.read(off, len, ec, out); -} - -void ReadOp::get_xattr(std::string_view name, cb::list* out, - bs::error_code* ec) { - reinterpret_cast<OpImpl*>(&impl)->op.getxattr(name, ec, out); -} - -void ReadOp::get_omap_header(cb::list* out, - bs::error_code* ec) { - reinterpret_cast<OpImpl*>(&impl)->op.omap_get_header(ec, out); -} - -void ReadOp::sparse_read(uint64_t off, uint64_t len, cb::list* out, - std::vector<std::pair<std::uint64_t, - std::uint64_t>>* extents, - bs::error_code* ec) { - reinterpret_cast<OpImpl*>(&impl)->op.sparse_read(off, len, ec, extents, out); -} - -void ReadOp::stat(std::uint64_t* size, ceph::real_time* mtime, - bs::error_code* ec) { - reinterpret_cast<OpImpl*>(&impl)->op.stat(size, mtime, ec); -} - -void ReadOp::get_omap_keys(std::optional<std::string_view> start_after, - std::uint64_t max_return, - bc::flat_set<std::string>* keys, - bool* done, - bs::error_code* ec) { - reinterpret_cast<OpImpl*>(&impl)->op.omap_get_keys(start_after, max_return, - ec, keys, done); -} - -void ReadOp::get_xattrs(bc::flat_map<std::string, - cb::list>* kv, - bs::error_code* ec) { - reinterpret_cast<OpImpl*>(&impl)->op.getxattrs(ec, kv); -} - -void ReadOp::get_omap_vals(std::optional<std::string_view> start_after, - std::optional<std::string_view> filter_prefix, - uint64_t max_return, - bc::flat_map<std::string, - cb::list>* kv, - bool* done, - bs::error_code* ec) { - reinterpret_cast<OpImpl*>(&impl)->op.omap_get_vals(start_after, filter_prefix, - max_return, ec, kv, done); -} - -void ReadOp::get_omap_vals_by_keys( - const bc::flat_set<std::string>& keys, - bc::flat_map<std::string, cb::list>* kv, - bs::error_code* ec) { - reinterpret_cast<OpImpl*>(&impl)->op.omap_get_vals_by_keys(keys, ec, kv); -} - -void ReadOp::list_watchers(std::vector<obj_watch_t>* watchers, - bs::error_code* ec) { - reinterpret_cast<OpImpl*>(&impl)-> op.list_watchers(watchers, ec); -} - -void ReadOp::list_snaps(librados::snap_set_t* snaps, - bs::error_code* ec) { - reinterpret_cast<OpImpl*>(&impl)->op.list_snaps(snaps, nullptr, ec); -} - -void ReadOp::exec(std::string_view cls, std::string_view method, - const bufferlist& inbl, - cb::list* out, - bs::error_code* ec) { - reinterpret_cast<OpImpl*>(&impl)->op.call(cls, method, inbl, ec, out); -} - -void ReadOp::exec(std::string_view cls, std::string_view method, - const bufferlist& inbl, - fu2::unique_function<void (bs::error_code, - const cb::list&) &&> f) { - reinterpret_cast<OpImpl*>(&impl)->op.call(cls, method, inbl, std::move(f)); -} - -// WriteOp - -void WriteOp::set_mtime(ceph::real_time t) { - auto o = reinterpret_cast<OpImpl*>(&impl); - o->mtime = t; -} - -void WriteOp::create(bool exclusive) { - reinterpret_cast<OpImpl*>(&impl)->op.create(exclusive); -} - -void WriteOp::write(uint64_t off, bufferlist&& bl) { - reinterpret_cast<OpImpl*>(&impl)->op.write(off, bl); -} - -void WriteOp::write_full(bufferlist&& bl) { - reinterpret_cast<OpImpl*>(&impl)->op.write_full(bl); -} - -void WriteOp::writesame(uint64_t off, uint64_t write_len, bufferlist&& bl) { - reinterpret_cast<OpImpl*>(&impl)->op.writesame(off, write_len, bl); -} - -void WriteOp::append(bufferlist&& bl) { - reinterpret_cast<OpImpl*>(&impl)->op.append(bl); -} - -void WriteOp::remove() { - reinterpret_cast<OpImpl*>(&impl)->op.remove(); -} - -void WriteOp::truncate(uint64_t off) { - reinterpret_cast<OpImpl*>(&impl)->op.truncate(off); -} - -void WriteOp::zero(uint64_t off, uint64_t len) { - reinterpret_cast<OpImpl*>(&impl)->op.zero(off, len); -} - -void WriteOp::rmxattr(std::string_view name) { - reinterpret_cast<OpImpl*>(&impl)->op.rmxattr(name); -} - -void WriteOp::setxattr(std::string_view name, - bufferlist&& bl) { - reinterpret_cast<OpImpl*>(&impl)->op.setxattr(name, bl); -} - -void WriteOp::rollback(uint64_t snapid) { - reinterpret_cast<OpImpl*>(&impl)->op.rollback(snapid); -} - -void WriteOp::set_omap( - const bc::flat_map<std::string, cb::list>& map) { - reinterpret_cast<OpImpl*>(&impl)->op.omap_set(map); -} - -void WriteOp::set_omap_header(bufferlist&& bl) { - reinterpret_cast<OpImpl*>(&impl)->op.omap_set_header(bl); -} - -void WriteOp::clear_omap() { - reinterpret_cast<OpImpl*>(&impl)->op.omap_clear(); -} - -void WriteOp::rm_omap_keys( - const bc::flat_set<std::string>& to_rm) { - reinterpret_cast<OpImpl*>(&impl)->op.omap_rm_keys(to_rm); -} - -void WriteOp::set_alloc_hint(uint64_t expected_object_size, - uint64_t expected_write_size, - alloc_hint::alloc_hint_t flags) { - reinterpret_cast<OpImpl*>(&impl)->op.set_alloc_hint(expected_object_size, - expected_write_size, - flags); -} - -void WriteOp::exec(std::string_view cls, std::string_view method, - const bufferlist& inbl, bs::error_code* ec) { - reinterpret_cast<OpImpl*>(&impl)->op.call(cls, method, inbl, ec); -} - -// RADOS - -RADOS::Builder& RADOS::Builder::add_conf_file(std::string_view f) { - if (conf_files) - *conf_files += (", " + std::string(f)); - else - conf_files = std::string(f); - return *this; -} - -void RADOS::Builder::build(boost::asio::io_context& ioctx, - std::unique_ptr<BuildComp> c) { - constexpr auto env = CODE_ENVIRONMENT_LIBRARY; - CephInitParameters ci(env); - if (name) - ci.name.set(CEPH_ENTITY_TYPE_CLIENT, *name); - else - ci.name.set(CEPH_ENTITY_TYPE_CLIENT, "admin"); - uint32_t flags = 0; - if (no_default_conf) - flags |= CINIT_FLAG_NO_DEFAULT_CONFIG_FILE; - if (no_mon_conf) - flags |= CINIT_FLAG_NO_MON_CONFIG; - - CephContext *cct = common_preinit(ci, env, flags); - if (cluster) - cct->_conf->cluster = *cluster; - - if (no_mon_conf) - cct->_conf->no_mon_config = true; - - // TODO: Come up with proper error codes here. Maybe augment the - // functions with a default bs::error_code* parameter to - // pass back. - { - std::ostringstream ss; - auto r = cct->_conf.parse_config_files(conf_files ? conf_files->data() : nullptr, - &ss, flags); - if (r < 0) - c->dispatch(std::move(c), ceph::to_error_code(r), RADOS{nullptr}); - } - - cct->_conf.parse_env(cct->get_module_type()); - - for (const auto& [n, v] : configs) { - std::stringstream ss; - auto r = cct->_conf.set_val(n, v, &ss); - if (r < 0) - c->dispatch(std::move(c), ceph::to_error_code(-EINVAL), RADOS{nullptr}); - } - - if (!no_mon_conf) { - MonClient mc_bootstrap(cct, ioctx); - // TODO This function should return an error code. - auto err = mc_bootstrap.get_monmap_and_config(); - if (err < 0) - c->dispatch(std::move(c), ceph::to_error_code(err), RADOS{nullptr}); - } - if (!cct->_log->is_started()) { - cct->_log->start(); - } - common_init_finish(cct); - - RADOS::make_with_cct(cct, ioctx, std::move(c)); -} - -void RADOS::make_with_cct(CephContext* cct, - boost::asio::io_context& ioctx, - std::unique_ptr<BuildComp> c) { - try { - auto r = new detail::RADOS(ioctx, cct); - r->objecter->wait_for_osd_map( - [c = std::move(c), r = std::unique_ptr<detail::RADOS>(r)]() mutable { - c->dispatch(std::move(c), bs::error_code{}, - RADOS{std::move(r)}); - }); - } catch (const bs::system_error& err) { - c->dispatch(std::move(c), err.code(), RADOS{nullptr}); - } -} - - -RADOS::RADOS() = default; - -RADOS::RADOS(std::unique_ptr<detail::RADOS> impl) - : impl(std::move(impl)) {} - -RADOS::RADOS(RADOS&&) = default; -RADOS& RADOS::operator =(RADOS&&) = default; - -RADOS::~RADOS() = default; - -RADOS::executor_type RADOS::get_executor() { - return impl->ioctx.get_executor(); -} - -void RADOS::execute(const Object& o, const IOContext& _ioc, ReadOp&& _op, - cb::list* bl, - std::unique_ptr<ReadOp::Completion> c, version_t* objver) { - auto oid = reinterpret_cast<const object_t*>(&o.impl); - auto ioc = reinterpret_cast<const IOContextImpl*>(&_ioc.impl); - auto op = reinterpret_cast<OpImpl*>(&_op.impl); - auto flags = 0; // Should be in Op. - - impl->objecter->read( - *oid, ioc->oloc, std::move(op->op), ioc->snap_seq, bl, flags, - std::move(c), objver); -} - -void RADOS::execute(const Object& o, const IOContext& _ioc, WriteOp&& _op, - std::unique_ptr<WriteOp::Completion> c, version_t* objver) { - auto oid = reinterpret_cast<const object_t*>(&o.impl); - auto ioc = reinterpret_cast<const IOContextImpl*>(&_ioc.impl); - auto op = reinterpret_cast<OpImpl*>(&_op.impl); - auto flags = 0; // Should be in Op. - ceph::real_time mtime; - if (op->mtime) - mtime = *op->mtime; - else - mtime = ceph::real_clock::now(); - - impl->objecter->mutate( - *oid, ioc->oloc, std::move(op->op), ioc->snapc, - mtime, flags, - std::move(c), objver); -} - -void RADOS::execute(const Object& o, std::int64_t pool, ReadOp&& _op, - cb::list* bl, - std::unique_ptr<ReadOp::Completion> c, - std::optional<std::string_view> ns, - std::optional<std::string_view> key, - version_t* objver) { - auto oid = reinterpret_cast<const object_t*>(&o.impl); - auto op = reinterpret_cast<OpImpl*>(&_op.impl); - auto flags = 0; // Should be in Op. - object_locator_t oloc; - oloc.pool = pool; - if (ns) - oloc.nspace = *ns; - if (key) - oloc.key = *key; - - impl->objecter->read( - *oid, oloc, std::move(op->op), CEPH_NOSNAP, bl, flags, - std::move(c), objver); -} - -void RADOS::execute(const Object& o, std::int64_t pool, WriteOp&& _op, - std::unique_ptr<WriteOp::Completion> c, - std::optional<std::string_view> ns, - std::optional<std::string_view> key, - version_t* objver) { - auto oid = reinterpret_cast<const object_t*>(&o.impl); - auto op = reinterpret_cast<OpImpl*>(&_op.impl); - auto flags = 0; // Should be in Op. - object_locator_t oloc; - oloc.pool = pool; - if (ns) - oloc.nspace = *ns; - if (key) - oloc.key = *key; - - ceph::real_time mtime; - if (op->mtime) - mtime = *op->mtime; - else - mtime = ceph::real_clock::now(); - - impl->objecter->mutate( - *oid, oloc, std::move(op->op), {}, - mtime, flags, - std::move(c), objver); -} - -boost::uuids::uuid RADOS::get_fsid() const noexcept { - return impl->monclient.get_fsid().uuid; -} - - -void RADOS::lookup_pool(std::string_view name, - std::unique_ptr<LookupPoolComp> c) -{ - // I kind of want to make lookup_pg_pool return - // std::optional<int64_t> since it can only return one error code. - int64_t ret = impl->objecter->with_osdmap( - std::mem_fn(&OSDMap::lookup_pg_pool_name), - name); - if (ret < 0) { - impl->objecter->wait_for_latest_osdmap( - [name = std::string(name), c = std::move(c), - objecter = impl->objecter.get()] - (bs::error_code ec) mutable { - int64_t ret = - objecter->with_osdmap(std::mem_fn(&OSDMap::lookup_pg_pool_name), - name); - if (ret < 0) - ca::dispatch(std::move(c), osdc_errc::pool_dne, - std::int64_t(0)); - else - ca::dispatch(std::move(c), bs::error_code{}, ret); - }); - } else if (ret < 0) { - ca::dispatch(std::move(c), osdc_errc::pool_dne, - std::int64_t(0)); - } else { - ca::dispatch(std::move(c), bs::error_code{}, ret); - } -} - - -std::optional<uint64_t> RADOS::get_pool_alignment(int64_t pool_id) -{ - return impl->objecter->with_osdmap( - [pool_id](const OSDMap &o) -> std::optional<uint64_t> { - if (!o.have_pg_pool(pool_id)) { - throw bs::system_error( - ENOENT, bs::system_category(), - "Cannot find pool in OSDMap."); - } else if (o.get_pg_pool(pool_id)->requires_aligned_append()) { - return o.get_pg_pool(pool_id)->required_alignment(); - } else { - return std::nullopt; - } - }); -} - -void RADOS::list_pools(std::unique_ptr<LSPoolsComp> c) { - impl->objecter->with_osdmap( - [&](OSDMap& o) { - std::vector<std::pair<std::int64_t, std::string>> v; - for (auto p : o.get_pools()) - v.push_back(std::make_pair(p.first, o.get_pool_name(p.first))); - ca::dispatch(std::move(c), std::move(v)); - }); -} - -void RADOS::create_pool_snap(std::int64_t pool, - std::string_view snapName, - std::unique_ptr<SimpleOpComp> c) -{ - impl->objecter->create_pool_snap( - pool, snapName, - Objecter::PoolOp::OpComp::create( - get_executor(), - [c = std::move(c)](bs::error_code e, const bufferlist&) mutable { - ca::dispatch(std::move(c), e); - })); -} - -void RADOS::allocate_selfmanaged_snap(int64_t pool, - std::unique_ptr<SMSnapComp> c) { - impl->objecter->allocate_selfmanaged_snap( - pool, - ca::Completion<void(bs::error_code, snapid_t)>::create( - get_executor(), - [c = std::move(c)](bs::error_code e, snapid_t snap) mutable { - ca::dispatch(std::move(c), e, snap); - })); -} - -void RADOS::delete_pool_snap(std::int64_t pool, - std::string_view snapName, - std::unique_ptr<SimpleOpComp> c) -{ - impl->objecter->delete_pool_snap( - pool, snapName, - Objecter::PoolOp::OpComp::create( - get_executor(), - [c = std::move(c)](bs::error_code e, const bufferlist&) mutable { - ca::dispatch(std::move(c), e); - })); -} - -void RADOS::delete_selfmanaged_snap(std::int64_t pool, - snapid_t snap, - std::unique_ptr<SimpleOpComp> c) -{ - impl->objecter->delete_selfmanaged_snap( - pool, snap, - Objecter::PoolOp::OpComp::create( - get_executor(), - [c = std::move(c)](bs::error_code e, const bufferlist&) mutable { - ca::dispatch(std::move(c), e); - })); -} - -void RADOS::create_pool(std::string_view name, - std::optional<int> crush_rule, - std::unique_ptr<SimpleOpComp> c) -{ - impl->objecter->create_pool( - name, - Objecter::PoolOp::OpComp::create( - get_executor(), - [c = std::move(c)](bs::error_code e, const bufferlist&) mutable { - ca::dispatch(std::move(c), e); - }), - crush_rule.value_or(-1)); -} - -void RADOS::delete_pool(std::string_view name, - std::unique_ptr<SimpleOpComp> c) -{ - impl->objecter->delete_pool( - name, - Objecter::PoolOp::OpComp::create( - get_executor(), - [c = std::move(c)](bs::error_code e, const bufferlist&) mutable { - ca::dispatch(std::move(c), e); - })); -} - -void RADOS::delete_pool(std::int64_t pool, - std::unique_ptr<SimpleOpComp> c) -{ - impl->objecter->delete_pool( - pool, - Objecter::PoolOp::OpComp::create( - get_executor(), - [c = std::move(c)](bs::error_code e, const bufferlist&) mutable { - ca::dispatch(std::move(c), e); - })); -} - -void RADOS::stat_pools(const std::vector<std::string>& pools, - std::unique_ptr<PoolStatComp> c) { - impl->objecter->get_pool_stats( - pools, - [c = std::move(c)] - (bs::error_code ec, - bc::flat_map<std::string, pool_stat_t> s, - bool p) mutable { - ca::dispatch(std::move(c), ec, std::move(s), p); - }); -} - -void RADOS::stat_fs(std::optional<std::int64_t> _pool, - std::unique_ptr<StatFSComp> c) { - boost::optional<int64_t> pool; - if (_pool) - pool = *pool; - impl->objecter->get_fs_stats(pool, std::move(c)); -} - -// --- Watch/Notify - -void RADOS::watch(const Object& o, const IOContext& _ioc, - std::optional<std::chrono::seconds> timeout, WatchCB&& cb, - std::unique_ptr<WatchComp> c) { - auto oid = reinterpret_cast<const object_t*>(&o.impl); - auto ioc = reinterpret_cast<const IOContextImpl*>(&_ioc.impl); - - ObjectOperation op; - - auto linger_op = impl->objecter->linger_register(*oid, ioc->oloc, 0); - uint64_t cookie = linger_op->get_cookie(); - linger_op->handle = std::move(cb); - op.watch(cookie, CEPH_OSD_WATCH_OP_WATCH, timeout.value_or(0s).count()); - bufferlist bl; - impl->objecter->linger_watch( - linger_op, op, ioc->snapc, ceph::real_clock::now(), bl, - Objecter::LingerOp::OpComp::create( - get_executor(), - [c = std::move(c), cookie](bs::error_code e, cb::list) mutable { - ca::dispatch(std::move(c), e, cookie); - }), nullptr); -} - -void RADOS::watch(const Object& o, std::int64_t pool, - std::optional<std::chrono::seconds> timeout, WatchCB&& cb, - std::unique_ptr<WatchComp> c, - std::optional<std::string_view> ns, - std::optional<std::string_view> key) { - auto oid = reinterpret_cast<const object_t*>(&o.impl); - object_locator_t oloc; - oloc.pool = pool; - if (ns) - oloc.nspace = *ns; - if (key) - oloc.key = *key; - - ObjectOperation op; - - Objecter::LingerOp *linger_op = impl->objecter->linger_register(*oid, oloc, 0); - uint64_t cookie = linger_op->get_cookie(); - linger_op->handle = std::move(cb); - op.watch(cookie, CEPH_OSD_WATCH_OP_WATCH, timeout.value_or(0s).count()); - bufferlist bl; - impl->objecter->linger_watch( - linger_op, op, {}, ceph::real_clock::now(), bl, - Objecter::LingerOp::OpComp::create( - get_executor(), - [c = std::move(c), cookie](bs::error_code e, bufferlist) mutable { - ca::dispatch(std::move(c), e, cookie); - }), nullptr); -} - -void RADOS::notify_ack(const Object& o, - const IOContext& _ioc, - uint64_t notify_id, - uint64_t cookie, - bufferlist&& bl, - std::unique_ptr<SimpleOpComp> c) -{ - auto oid = reinterpret_cast<const object_t*>(&o.impl); - auto ioc = reinterpret_cast<const IOContextImpl*>(&_ioc.impl); - - ObjectOperation op; - op.notify_ack(notify_id, cookie, bl); - - impl->objecter->read(*oid, ioc->oloc, std::move(op), ioc->snap_seq, - nullptr, 0, std::move(c)); -} - -void RADOS::notify_ack(const Object& o, - std::int64_t pool, - uint64_t notify_id, - uint64_t cookie, - bufferlist&& bl, - std::unique_ptr<SimpleOpComp> c, - std::optional<std::string_view> ns, - std::optional<std::string_view> key) { - auto oid = reinterpret_cast<const object_t*>(&o.impl); - object_locator_t oloc; - oloc.pool = pool; - if (ns) - oloc.nspace = *ns; - if (key) - oloc.key = *key; - - ObjectOperation op; - op.notify_ack(notify_id, cookie, bl); - impl->objecter->read(*oid, oloc, std::move(op), CEPH_NOSNAP, nullptr, 0, - std::move(c)); -} - -tl::expected<ceph::timespan, bs::error_code> RADOS::watch_check(uint64_t cookie) -{ - Objecter::LingerOp *linger_op = reinterpret_cast<Objecter::LingerOp*>(cookie); - return impl->objecter->linger_check(linger_op); -} - -void RADOS::unwatch(uint64_t cookie, const IOContext& _ioc, - std::unique_ptr<SimpleOpComp> c) -{ - auto ioc = reinterpret_cast<const IOContextImpl*>(&_ioc.impl); - - Objecter::LingerOp *linger_op = reinterpret_cast<Objecter::LingerOp*>(cookie); - - ObjectOperation op; - op.watch(cookie, CEPH_OSD_WATCH_OP_UNWATCH); - impl->objecter->mutate(linger_op->target.base_oid, ioc->oloc, std::move(op), - ioc->snapc, ceph::real_clock::now(), 0, - Objecter::Op::OpComp::create( - get_executor(), - [objecter = impl->objecter.get(), - linger_op, c = std::move(c)] - (bs::error_code ec) mutable { - objecter->linger_cancel(linger_op); - ca::dispatch(std::move(c), ec); - })); -} - -void RADOS::unwatch(uint64_t cookie, std::int64_t pool, - std::unique_ptr<SimpleOpComp> c, - std::optional<std::string_view> ns, - std::optional<std::string_view> key) -{ - object_locator_t oloc; - oloc.pool = pool; - if (ns) - oloc.nspace = *ns; - if (key) - oloc.key = *key; - - Objecter::LingerOp *linger_op = reinterpret_cast<Objecter::LingerOp*>(cookie); - - ObjectOperation op; - op.watch(cookie, CEPH_OSD_WATCH_OP_UNWATCH); - impl->objecter->mutate(linger_op->target.base_oid, oloc, std::move(op), - {}, ceph::real_clock::now(), 0, - Objecter::Op::OpComp::create( - get_executor(), - [objecter = impl->objecter.get(), - linger_op, c = std::move(c)] - (bs::error_code ec) mutable { - objecter->linger_cancel(linger_op); - ca::dispatch(std::move(c), ec); - })); -} - -void RADOS::flush_watch(std::unique_ptr<VoidOpComp> c) -{ - impl->objecter->linger_callback_flush([c = std::move(c)]() mutable { - ca::post(std::move(c)); - }); -} - -struct NotifyHandler : std::enable_shared_from_this<NotifyHandler> { - boost::asio::io_context& ioc; - boost::asio::io_context::strand strand; - Objecter* objecter; - Objecter::LingerOp* op; - std::unique_ptr<RADOS::NotifyComp> c; - - bool acked = false; - bool finished = false; - bs::error_code res; - bufferlist rbl; - - NotifyHandler(boost::asio::io_context& ioc, - Objecter* objecter, - Objecter::LingerOp* op, - std::unique_ptr<RADOS::NotifyComp> c) - : ioc(ioc), strand(ioc), objecter(objecter), op(op), c(std::move(c)) {} - - // Use bind or a lambda to pass this in. - void handle_ack(bs::error_code ec, - bufferlist&&) { - boost::asio::post( - strand, - [this, ec, p = shared_from_this()]() mutable { - acked = true; - maybe_cleanup(ec); - }); - } - - // Notify finish callback. It can actually own the object's storage. - - void operator()(bs::error_code ec, - bufferlist&& bl) { - boost::asio::post( - strand, - [this, ec, p = shared_from_this()]() mutable { - finished = true; - maybe_cleanup(ec); - }); - } - - // Should be called from strand. - void maybe_cleanup(bs::error_code ec) { - if (!res && ec) - res = ec; - if ((acked && finished) || res) { - objecter->linger_cancel(op); - ceph_assert(c); - ca::dispatch(std::move(c), res, std::move(rbl)); - } - } -}; - -void RADOS::notify(const Object& o, const IOContext& _ioc, bufferlist&& bl, - std::optional<std::chrono::milliseconds> timeout, - std::unique_ptr<NotifyComp> c) -{ - auto oid = reinterpret_cast<const object_t*>(&o.impl); - auto ioc = reinterpret_cast<const IOContextImpl*>(&_ioc.impl); - auto linger_op = impl->objecter->linger_register(*oid, ioc->oloc, 0); - - auto cb = std::make_shared<NotifyHandler>(impl->ioctx, impl->objecter.get(), - linger_op, std::move(c)); - linger_op->on_notify_finish = - Objecter::LingerOp::OpComp::create( - get_executor(), - [cb](bs::error_code ec, ceph::bufferlist bl) mutable { - (*cb)(ec, std::move(bl)); - }); - ObjectOperation rd; - bufferlist inbl; - rd.notify( - linger_op->get_cookie(), 1, - timeout ? timeout->count() : impl->cct->_conf->client_notify_timeout, - bl, &inbl); - - impl->objecter->linger_notify( - linger_op, rd, ioc->snap_seq, inbl, - Objecter::LingerOp::OpComp::create( - get_executor(), - [cb](bs::error_code ec, ceph::bufferlist bl) mutable { - cb->handle_ack(ec, std::move(bl)); - }), nullptr); -} - -void RADOS::notify(const Object& o, std::int64_t pool, bufferlist&& bl, - std::optional<std::chrono::milliseconds> timeout, - std::unique_ptr<NotifyComp> c, - std::optional<std::string_view> ns, - std::optional<std::string_view> key) -{ - auto oid = reinterpret_cast<const object_t*>(&o.impl); - object_locator_t oloc; - oloc.pool = pool; - if (ns) - oloc.nspace = *ns; - if (key) - oloc.key = *key; - auto linger_op = impl->objecter->linger_register(*oid, oloc, 0); - - auto cb = std::make_shared<NotifyHandler>(impl->ioctx, impl->objecter.get(), - linger_op, std::move(c)); - linger_op->on_notify_finish = - Objecter::LingerOp::OpComp::create( - get_executor(), - [cb](bs::error_code ec, ceph::bufferlist&& bl) mutable { - (*cb)(ec, std::move(bl)); - }); - ObjectOperation rd; - bufferlist inbl; - rd.notify( - linger_op->get_cookie(), 1, - timeout ? timeout->count() : impl->cct->_conf->client_notify_timeout, - bl, &inbl); - - impl->objecter->linger_notify( - linger_op, rd, CEPH_NOSNAP, inbl, - Objecter::LingerOp::OpComp::create( - get_executor(), - [cb](bs::error_code ec, bufferlist&& bl) mutable { - cb->handle_ack(ec, std::move(bl)); - }), nullptr); -} - -// Enumeration - -Cursor::Cursor() { - static_assert(impl_size >= sizeof(hobject_t)); - new (&impl) hobject_t(); -}; - -Cursor::Cursor(end_magic_t) { - static_assert(impl_size >= sizeof(hobject_t)); - new (&impl) hobject_t(hobject_t::get_max()); -} - -Cursor::Cursor(void* p) { - static_assert(impl_size >= sizeof(hobject_t)); - new (&impl) hobject_t(std::move(*reinterpret_cast<hobject_t*>(p))); -} - -Cursor Cursor::begin() { - Cursor e; - return e; -} - -Cursor Cursor::end() { - Cursor e(end_magic_t{}); - return e; -} - -Cursor::Cursor(const Cursor& rhs) { - static_assert(impl_size >= sizeof(hobject_t)); - new (&impl) hobject_t(*reinterpret_cast<const hobject_t*>(&rhs.impl)); -} - -Cursor& Cursor::operator =(const Cursor& rhs) { - static_assert(impl_size >= sizeof(hobject_t)); - reinterpret_cast<hobject_t*>(&impl)->~hobject_t(); - new (&impl) hobject_t(*reinterpret_cast<const hobject_t*>(&rhs.impl)); - return *this; -} - -Cursor::Cursor(Cursor&& rhs) { - static_assert(impl_size >= sizeof(hobject_t)); - new (&impl) hobject_t(std::move(*reinterpret_cast<hobject_t*>(&rhs.impl))); -} - -Cursor& Cursor::operator =(Cursor&& rhs) { - static_assert(impl_size >= sizeof(hobject_t)); - reinterpret_cast<hobject_t*>(&impl)->~hobject_t(); - new (&impl) hobject_t(std::move(*reinterpret_cast<hobject_t*>(&rhs.impl))); - return *this; -} -Cursor::~Cursor() { - reinterpret_cast<hobject_t*>(&impl)->~hobject_t(); -} - -bool operator ==(const Cursor& lhs, const Cursor& rhs) { - return (*reinterpret_cast<const hobject_t*>(&lhs.impl) == - *reinterpret_cast<const hobject_t*>(&rhs.impl)); -} - -bool operator !=(const Cursor& lhs, const Cursor& rhs) { - return (*reinterpret_cast<const hobject_t*>(&lhs.impl) != - *reinterpret_cast<const hobject_t*>(&rhs.impl)); -} - -bool operator <(const Cursor& lhs, const Cursor& rhs) { - return (*reinterpret_cast<const hobject_t*>(&lhs.impl) < - *reinterpret_cast<const hobject_t*>(&rhs.impl)); -} - -bool operator <=(const Cursor& lhs, const Cursor& rhs) { - return (*reinterpret_cast<const hobject_t*>(&lhs.impl) <= - *reinterpret_cast<const hobject_t*>(&rhs.impl)); -} - -bool operator >=(const Cursor& lhs, const Cursor& rhs) { - return (*reinterpret_cast<const hobject_t*>(&lhs.impl) >= - *reinterpret_cast<const hobject_t*>(&rhs.impl)); -} - -bool operator >(const Cursor& lhs, const Cursor& rhs) { - return (*reinterpret_cast<const hobject_t*>(&lhs.impl) > - *reinterpret_cast<const hobject_t*>(&rhs.impl)); -} - -std::string Cursor::to_str() const { - using namespace std::literals; - auto& h = *reinterpret_cast<const hobject_t*>(&impl); - - return h.is_max() ? "MAX"s : h.to_str(); -} - -std::optional<Cursor> -Cursor::from_str(const std::string& s) { - Cursor e; - auto& h = *reinterpret_cast<hobject_t*>(&e.impl); - if (!h.parse(s)) - return std::nullopt; - - return e; -} - -void RADOS::enumerate_objects(const IOContext& _ioc, - const Cursor& begin, - const Cursor& end, - const std::uint32_t max, - const bufferlist& filter, - std::vector<Entry>* ls, - Cursor* cursor, - std::unique_ptr<SimpleOpComp> c) { - auto ioc = reinterpret_cast<const IOContextImpl*>(&_ioc.impl); - - impl->objecter->enumerate_objects( - ioc->oloc.pool, - ioc->oloc.nspace, - *reinterpret_cast<const hobject_t*>(&begin.impl), - *reinterpret_cast<const hobject_t*>(&end.impl), - max, - filter, - [c = std::move(c), ls, cursor] - (bs::error_code ec, std::vector<Entry>&& v, - hobject_t&& n) mutable { - if (ls) - *ls = std::move(v); - if (cursor) { - Cursor next(static_cast<void*>(&n)); - *cursor = std::move(next); - } - ca::dispatch(std::move(c), ec); - }); -} - -void RADOS::enumerate_objects(std::int64_t pool, - const Cursor& begin, - const Cursor& end, - const std::uint32_t max, - const bufferlist& filter, - std::vector<Entry>* ls, - Cursor* cursor, - std::unique_ptr<SimpleOpComp> c, - std::optional<std::string_view> ns, - std::optional<std::string_view> key) { - impl->objecter->enumerate_objects( - pool, - ns ? *ns : std::string_view{}, - *reinterpret_cast<const hobject_t*>(&begin.impl), - *reinterpret_cast<const hobject_t*>(&end.impl), - max, - filter, - [c = std::move(c), ls, cursor] - (bs::error_code ec, std::vector<Entry>&& v, - hobject_t&& n) mutable { - if (ls) - *ls = std::move(v); - if (cursor) { - Cursor next(static_cast<void*>(&n)); - *cursor = std::move(next); - } - ca::dispatch(std::move(c), ec); - }); -} - -void RADOS::enumerate_objects(const IOContext& _ioc, - const Cursor& begin, - const Cursor& end, - const std::uint32_t max, - const bufferlist& filter, - std::unique_ptr<EnumerateComp> c) { - auto ioc = reinterpret_cast<const IOContextImpl*>(&_ioc.impl); - - impl->objecter->enumerate_objects( - ioc->oloc.pool, - ioc->oloc.nspace, - *reinterpret_cast<const hobject_t*>(&begin.impl), - *reinterpret_cast<const hobject_t*>(&end.impl), - max, - filter, - [c = std::move(c)] - (bs::error_code ec, std::vector<Entry>&& v, - hobject_t&& n) mutable { - ca::dispatch(std::move(c), ec, std::move(v), - Cursor(static_cast<void*>(&n))); - }); -} - -void RADOS::enumerate_objects(std::int64_t pool, - const Cursor& begin, - const Cursor& end, - const std::uint32_t max, - const bufferlist& filter, - std::unique_ptr<EnumerateComp> c, - std::optional<std::string_view> ns, - std::optional<std::string_view> key) { - impl->objecter->enumerate_objects( - pool, - ns ? *ns : std::string_view{}, - *reinterpret_cast<const hobject_t*>(&begin.impl), - *reinterpret_cast<const hobject_t*>(&end.impl), - max, - filter, - [c = std::move(c)] - (bs::error_code ec, std::vector<Entry>&& v, - hobject_t&& n) mutable { - ca::dispatch(std::move(c), ec, std::move(v), - Cursor(static_cast<void*>(&n))); - }); -} - - -void RADOS::osd_command(int osd, std::vector<std::string>&& cmd, - ceph::bufferlist&& in, std::unique_ptr<CommandComp> c) { - impl->objecter->osd_command(osd, std::move(cmd), std::move(in), nullptr, - [c = std::move(c)] - (bs::error_code ec, - std::string&& s, - ceph::bufferlist&& b) mutable { - ca::dispatch(std::move(c), ec, - std::move(s), - std::move(b)); - }); -} -void RADOS::pg_command(pg_t pg, std::vector<std::string>&& cmd, - ceph::bufferlist&& in, std::unique_ptr<CommandComp> c) { - impl->objecter->pg_command(pg, std::move(cmd), std::move(in), nullptr, - [c = std::move(c)] - (bs::error_code ec, - std::string&& s, - ceph::bufferlist&& b) mutable { - ca::dispatch(std::move(c), ec, - std::move(s), - std::move(b)); - }); -} - -void RADOS::enable_application(std::string_view pool, std::string_view app_name, - bool force, std::unique_ptr<SimpleOpComp> c) { - // pre-Luminous clusters will return -EINVAL and application won't be - // preserved until Luminous is configured as minimum version. - if (!impl->get_required_monitor_features().contains_all( - ceph::features::mon::FEATURE_LUMINOUS)) { - ca::dispatch(std::move(c), ceph::to_error_code(-EOPNOTSUPP)); - } else { - impl->monclient.start_mon_command( - { fmt::format("{{ \"prefix\": \"osd pool application enable\"," - "\"pool\": \"{}\", \"app\": \"{}\"{}}}", - pool, app_name, - force ? " ,\"yes_i_really_mean_it\": true" : "")}, - {}, [c = std::move(c)](bs::error_code e, - std::string, cb::list) mutable { - ca::post(std::move(c), e); - }); - } -} - -void RADOS::mon_command(std::vector<std::string> command, - const cb::list& bl, - std::string* outs, cb::list* outbl, - std::unique_ptr<SimpleOpComp> c) { - - impl->monclient.start_mon_command( - command, bl, - [c = std::move(c), outs, outbl](bs::error_code e, - std::string s, cb::list bl) mutable { - if (outs) - *outs = std::move(s); - if (outbl) - *outbl = std::move(bl); - ca::post(std::move(c), e); - }); -} - -uint64_t RADOS::instance_id() const { - return impl->get_instance_id(); -} -} - -namespace std { -size_t hash<RADOS::Object>::operator ()( - const RADOS::Object& r) const { - static constexpr const hash<object_t> H; - return H(*reinterpret_cast<const object_t*>(&r.impl)); -} -} diff --git a/src/RADOS/RADOSImpl.cc b/src/RADOS/RADOSImpl.cc deleted file mode 100644 index 4dd816da519..00000000000 --- a/src/RADOS/RADOSImpl.cc +++ /dev/null @@ -1,112 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2004-2012 Sage Weil <sage@newdream.net> - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - - -#include <boost/system/system_error.hpp> - -#include "common/common_init.h" - -#include "global/global_init.h" - -#include "RADOSImpl.h" - -namespace RADOS { -namespace detail { - -RADOS::RADOS(boost::asio::io_context& ioctx, - boost::intrusive_ptr<CephContext> _cct) - : Dispatcher(_cct.detach()), - ioctx(ioctx), - monclient(cct, ioctx), - moncsd(monclient), - mgrclient(cct, nullptr, &monclient.monmap), - mgrcsd(mgrclient) { - auto err = monclient.build_initial_monmap(); - if (err < 0) - throw std::system_error(ceph::to_error_code(err)); - - messenger.reset(Messenger::create_client_messenger(cct, "radosclient")); - if (!messenger) - throw std::bad_alloc(); - - // require OSDREPLYMUX feature. this means we will fail to talk to - // old servers. this is necessary because otherwise we won't know - // how to decompose the reply data into its constituent pieces. - messenger->set_default_policy( - Messenger::Policy::lossy_client(CEPH_FEATURE_OSDREPLYMUX)); - - objecter.reset(new Objecter(cct, messenger.get(), &monclient, - ioctx, - cct->_conf->rados_mon_op_timeout, - cct->_conf->rados_osd_op_timeout)); - - objecter->set_balanced_budget(); - monclient.set_messenger(messenger.get()); - mgrclient.set_messenger(messenger.get()); - objecter->init(); - messenger->add_dispatcher_head(&mgrclient); - messenger->add_dispatcher_tail(objecter.get()); - messenger->start(); - monclient.set_want_keys(CEPH_ENTITY_TYPE_MON | CEPH_ENTITY_TYPE_OSD | CEPH_ENTITY_TYPE_MGR); - err = monclient.init(); - if (err) { - throw boost::system::system_error(ceph::to_error_code(err)); - } - err = monclient.authenticate(cct->_conf->client_mount_timeout); - if (err) { - throw boost::system::system_error(ceph::to_error_code(err)); - } - messenger->set_myname(entity_name_t::CLIENT(monclient.get_global_id())); - // Detect older cluster, put mgrclient into compatible mode - mgrclient.set_mgr_optional( - !get_required_monitor_features().contains_all( - ceph::features::mon::FEATURE_LUMINOUS)); - - // MgrClient needs this (it doesn't have MonClient reference itself) - monclient.sub_want("mgrmap", 0, 0); - monclient.renew_subs(); - - mgrclient.init(); - objecter->set_client_incarnation(0); - objecter->start(); - - messenger->add_dispatcher_tail(this); - - std::unique_lock l(lock); - instance_id = monclient.get_global_id(); -} - -bool RADOS::ms_dispatch(Message *m) -{ - switch (m->get_type()) { - // OSD - case CEPH_MSG_OSD_MAP: - m->put(); - return true; - } - return false; -} - -void RADOS::ms_handle_connect(Connection *con) {} -bool RADOS::ms_handle_reset(Connection *con) { - return false; -} -void RADOS::ms_handle_remote_reset(Connection *con) {} -bool RADOS::ms_handle_refused(Connection *con) { - return false; -} - -RADOS::~RADOS() = default; -} -} diff --git a/src/RADOS/RADOSImpl.h b/src/RADOS/RADOSImpl.h deleted file mode 100644 index c7ce18a9e7d..00000000000 --- a/src/RADOS/RADOSImpl.h +++ /dev/null @@ -1,105 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2004-2012 Sage Weil <sage@newdream.net> - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ -#ifndef CEPH_LIBRADOS_RADOSCLIENT_H -#define CEPH_LIBRADOS_RADOSCLIENT_H - -#include <functional> -#include <memory> -#include <string> - -#include <boost/asio.hpp> -#include <boost/intrusive_ptr.hpp> - -#include "common/ceph_context.h" -#include "common/ceph_mutex.h" - -#include "mon/MonClient.h" - -#include "mgr/MgrClient.h" - -#include "osdc/Objecter.h" - - - -namespace RADOS { - class RADOS; -namespace detail { - -class RADOS : public Dispatcher -{ - friend ::RADOS::RADOS; - struct MsgDeleter { - void operator()(Messenger* p) const { - if (p) { - p->shutdown(); - p->wait(); - } - delete p; - } - }; - - struct ObjDeleter { - void operator()(Objecter* p) const { - if (p) { - p->shutdown(); - } - delete p; - } - }; - - template<typename T> - struct scoped_shutdown { - T& m; - scoped_shutdown(T& m) : m(m) {} - - ~scoped_shutdown() { - m.shutdown(); - } - }; - - boost::asio::io_context& ioctx; - ceph::mutex lock = ceph::make_mutex("RADOS_unleashed::_::RADOSImpl"); - int instance_id = -1; - - std::unique_ptr<Messenger, MsgDeleter> messenger; - - MonClient monclient; - scoped_shutdown<MonClient> moncsd; - - MgrClient mgrclient; - scoped_shutdown<MgrClient> mgrcsd; - - std::unique_ptr<Objecter, ObjDeleter> objecter; - - -public: - - RADOS(boost::asio::io_context& ioctx, boost::intrusive_ptr<CephContext> cct); - ~RADOS(); - bool ms_dispatch(Message *m) override; - void ms_handle_connect(Connection *con) override; - bool ms_handle_reset(Connection *con) override; - void ms_handle_remote_reset(Connection *con) override; - bool ms_handle_refused(Connection *con) override; - mon_feature_t get_required_monitor_features() const { - return monclient.with_monmap(std::mem_fn(&MonMap::get_required_features)); - } - int get_instance_id() const { - return instance_id; - } -}; -} -} - -#endif diff --git a/src/ceph_fuse.cc b/src/ceph_fuse.cc index 4f889328f95..5ac18116f12 100644 --- a/src/ceph_fuse.cc +++ b/src/ceph_fuse.cc @@ -16,9 +16,7 @@ #include <sys/utsname.h> #include <iostream> #include <string> -#include <optional> -#include "common/async/context_pool.h" #include "common/config.h" #include "common/errno.h" @@ -46,8 +44,6 @@ #define dout_context g_ceph_context -ceph::async::io_context_pool icp; - static void fuse_usage() { const char* argv[] = { @@ -227,8 +223,7 @@ int main(int argc, const char **argv, const char *envp[]) { int tester_r = 0; void *tester_rp = nullptr; - icp.start(cct->_conf.get_val<std::uint64_t>("client_asio_thread_count")); - MonClient *mc = new MonClient(g_ceph_context, icp); + MonClient *mc = new MonClient(g_ceph_context); int r = mc->build_initial_monmap(); if (r == -EINVAL) { cerr << "failed to generate initial mon list" << std::endl; @@ -243,7 +238,7 @@ int main(int argc, const char **argv, const char *envp[]) { messenger->set_policy(entity_name_t::TYPE_MDS, Messenger::Policy::lossless_client(0)); - client = new StandaloneClient(messenger, mc, icp); + client = new StandaloneClient(messenger, mc); if (filer_flags) { client->set_filer_flags(filer_flags); } @@ -310,7 +305,6 @@ int main(int argc, const char **argv, const char *envp[]) { client->unmount(); cfuse->finalize(); out_shutdown: - icp.stop(); client->shutdown(); out_init_failed: unregister_async_signal_handler(SIGHUP, sighup_handler); diff --git a/src/ceph_mds.cc b/src/ceph_mds.cc index 4e6714ac44e..38e673755a9 100644 --- a/src/ceph_mds.cc +++ b/src/ceph_mds.cc @@ -20,7 +20,6 @@ #include <iostream> #include <string> -#include "common/async/context_pool.h" #include "include/ceph_features.h" #include "include/compat.h" #include "include/random.h" @@ -177,8 +176,7 @@ int main(int argc, const char **argv) register_async_signal_handler(SIGHUP, sighup_handler); // get monmap - ceph::async::io_context_pool ctxpool(2); - MonClient mc(g_ceph_context, ctxpool); + MonClient mc(g_ceph_context); if (mc.build_initial_monmap() < 0) forker.exit(1); global_init_chdir(g_ceph_context); @@ -186,7 +184,7 @@ int main(int argc, const char **argv) msgr->start(); // start mds - mds = new MDSDaemon(g_conf()->name.get_id().c_str(), msgr, &mc, ctxpool); + mds = new MDSDaemon(g_conf()->name.get_id().c_str(), msgr, &mc); // in case we have to respawn... mds->orig_argc = argc; @@ -217,7 +215,6 @@ int main(int argc, const char **argv) shutdown_async_signal_handler(); shutdown: - ctxpool.stop(); // yuck: grab the mds lock, so we can be sure that whoever in *mds // called shutdown finishes what they were doing. mds->mds_lock.lock(); @@ -241,3 +238,4 @@ int main(int argc, const char **argv) return 0; } + diff --git a/src/ceph_osd.cc b/src/ceph_osd.cc index 18101dee122..3e03e863239 100644 --- a/src/ceph_osd.cc +++ b/src/ceph_osd.cc @@ -664,10 +664,7 @@ flushjournal_out: srand(time(NULL) + getpid()); - ceph::async::io_context_pool poolctx( - cct->_conf.get_val<std::uint64_t>("osd_asio_thread_count")); - - MonClient mc(g_ceph_context, poolctx); + MonClient mc(g_ceph_context); if (mc.build_initial_monmap() < 0) return -1; global_init_chdir(g_ceph_context); @@ -688,8 +685,7 @@ flushjournal_out: ms_objecter, &mc, data_path, - journal_path, - poolctx); + journal_path); int err = osdptr->pre_init(); if (err < 0) { @@ -744,7 +740,6 @@ flushjournal_out: shutdown_async_signal_handler(); // done - poolctx.stop(); delete osdptr; delete ms_public; delete ms_hb_front_client; diff --git a/src/ceph_syn.cc b/src/ceph_syn.cc index 165ea42308a..50e26f2815a 100644 --- a/src/ceph_syn.cc +++ b/src/ceph_syn.cc @@ -18,7 +18,6 @@ #include "common/config.h" -#include "common/async/context_pool.h" #include "client/SyntheticClient.h" #include "client/Client.h" @@ -51,8 +50,7 @@ int main(int argc, const char **argv, char *envp[]) pick_addresses(g_ceph_context, CEPH_PICK_ADDRESS_PUBLIC); // get monmap - ceph::async::io_context_pool poolctx(1); - MonClient mc(g_ceph_context, poolctx); + MonClient mc(g_ceph_context); if (mc.build_initial_monmap() < 0) return -1; @@ -66,9 +64,9 @@ int main(int argc, const char **argv, char *envp[]) messengers[i] = Messenger::create_client_messenger(g_ceph_context, "synclient"); messengers[i]->bind(g_conf()->public_addr); - mclients[i] = new MonClient(g_ceph_context, poolctx); + mclients[i] = new MonClient(g_ceph_context); mclients[i]->build_initial_monmap(); - auto client = new StandaloneClient(messengers[i], mclients[i], poolctx); + auto client = new StandaloneClient(messengers[i], mclients[i]); client->set_filer_flags(syn_filer_flags); SyntheticClient *syn = new SyntheticClient(client); clients.push_back(client); @@ -81,8 +79,6 @@ int main(int argc, const char **argv, char *envp[]) ++p) (*p)->start_thread(); - poolctx.stop(); - //cout << "waiting for client(s) to finish" << std::endl; while (!clients.empty()) { Client *client = clients.front(); @@ -103,3 +99,4 @@ int main(int argc, const char **argv, char *envp[]) } return 0; } + diff --git a/src/client/Client.cc b/src/client/Client.cc index a9528891fa8..e042539c3b5 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -29,8 +29,6 @@ #include <boost/lexical_cast.hpp> #include <boost/fusion/include/std_pair.hpp> -#include "common/async/waiter.h" - #if defined(__FreeBSD__) #define XATTR_CREATE 0x1 #define XATTR_REPLACE 0x2 @@ -46,7 +44,6 @@ #include "common/config.h" #include "common/version.h" -#include "common/async/waiter.h" #include "mon/MonClient.h" @@ -127,9 +124,6 @@ #define DEBUG_GETATTR_CAPS (CEPH_CAP_XATTR_SHARED) -namespace bs = boost::system; -using ceph::async::waiter; - void client_flush_set_callback(void *p, ObjectCacher::ObjectSet *oset) { Client *client = static_cast<Client*>(p); @@ -5649,22 +5643,22 @@ int Client::authenticate() int Client::fetch_fsmap(bool user) { + int r; // Retrieve FSMap to enable looking up daemon addresses. We need FSMap // rather than MDSMap because no one MDSMap contains all the daemons, and // a `tell` can address any daemon. version_t fsmap_latest; - boost::system::error_code ec; do { - waiter<bs::error_code, version_t, version_t> w; - monclient->get_version("fsmap", w); + C_SaferCond cond; + monclient->get_version("fsmap", &fsmap_latest, NULL, &cond); client_lock.unlock(); - std::tie(ec, fsmap_latest, std::ignore) = w.wait(); + r = cond.wait(); client_lock.lock(); - } while (ec == boost::system::errc::resource_unavailable_try_again); + } while (r == -EAGAIN); - if (ec) { - lderr(cct) << "Failed to learn FSMap version: " << ec << dendl; - return ceph::from_error_code(ec); + if (r < 0) { + lderr(cct) << "Failed to learn FSMap version: " << cpp_strerror(r) << dendl; + return r; } ldout(cct, 10) << __func__ << " learned FSMap version " << fsmap_latest << dendl; @@ -11604,9 +11598,9 @@ void Client::_setxattr_maybe_wait_for_osdmap(const char *name, const void *value }); if (r == -ENOENT) { - waiter<bs::error_code> w; - objecter->wait_for_latest_osdmap(w); - w.wait(); + C_SaferCond ctx; + objecter->wait_for_latest_osdmap(&ctx); + ctx.wait(); } } } @@ -14205,7 +14199,7 @@ int Client::check_pool_perm(Inode *in, int need) C_SaferCond rd_cond; ObjectOperation rd_op; - rd_op.stat(nullptr, nullptr, nullptr); + rd_op.stat(NULL, (ceph::real_time*)nullptr, NULL); objecter->mutate(oid, OSDMap::file_to_object_locator(in->layout), rd_op, nullsnapc, ceph::real_clock::now(), 0, &rd_cond); @@ -14392,7 +14386,7 @@ void Client::set_session_timeout(unsigned timeout) int Client::start_reclaim(const std::string& uuid, unsigned flags, const std::string& fs_name) { - std::unique_lock l(client_lock); + std::lock_guard l(client_lock); if (!initialized) return -ENOTCONN; @@ -14468,15 +14462,13 @@ int Client::start_reclaim(const std::string& uuid, unsigned flags, // use blacklist to check if target session was killed // (config option mds_session_blacklist_on_evict needs to be true) - ldout(cct, 10) << __func__ << ": waiting for OSD epoch " << reclaim_osd_epoch << dendl; - waiter<bs::error_code> w; - objecter->wait_for_map(reclaim_osd_epoch, w); - l.unlock(); - auto ec = w.wait(); - l.lock(); - - if (ec) - return ceph::from_error_code(ec); + C_SaferCond cond; + if (!objecter->wait_for_map(reclaim_osd_epoch, &cond)) { + ldout(cct, 10) << __func__ << ": waiting for OSD epoch " << reclaim_osd_epoch << dendl; + client_lock.unlock(); + cond.wait(); + client_lock.lock(); + } bool blacklisted = objecter->with_osdmap( [this](const OSDMap &osd_map) -> bool { @@ -14600,9 +14592,8 @@ mds_rank_t Client::_get_random_up_mds() const } -StandaloneClient::StandaloneClient(Messenger *m, MonClient *mc, - boost::asio::io_context& ictx) - : Client(m, mc, new Objecter(m->cct, m, mc, ictx, 0, 0)) +StandaloneClient::StandaloneClient(Messenger *m, MonClient *mc) + : Client(m, mc, new Objecter(m->cct, m, mc, NULL, 0, 0)) { monclient->set_messenger(m); objecter->set_client_incarnation(0); diff --git a/src/client/Client.h b/src/client/Client.h index b75aa47fc1c..a88abb5d86e 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -1305,7 +1305,7 @@ private: class StandaloneClient : public Client { public: - StandaloneClient(Messenger *m, MonClient *mc, boost::asio::io_context& ictx); + StandaloneClient(Messenger *m, MonClient *mc); ~StandaloneClient() override; diff --git a/src/cls/rgw/cls_rgw_types.h b/src/cls/rgw/cls_rgw_types.h index 1f519acb751..2b2907ba6fa 100644 --- a/src/cls/rgw/cls_rgw_types.h +++ b/src/cls/rgw/cls_rgw_types.h @@ -242,7 +242,7 @@ void decode_packed_val(T& val, bufferlist::const_iterator& bl) } break; default: - throw buffer::malformed_input(); + throw buffer::error(); } } diff --git a/src/common/async/context_pool.h b/src/common/async/context_pool.h deleted file mode 100644 index 2e90ba95a25..00000000000 --- a/src/common/async/context_pool.h +++ /dev/null @@ -1,97 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2018 Red Hat <contact@redhat.com> - * Author: Adam C. Emerson <aemerson@redhat.com> - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#ifndef CEPH_COMMON_ASYNC_CONTEXT_POOL_H -#define CEPH_COMMON_ASYNC_CONTEXT_POOL_H - -#include <cstddef> -#include <cstdint> -#include <mutex> -#include <optional> -#include <thread> -#include <vector> - -#include <boost/asio/io_context.hpp> -#include <boost/asio/executor_work_guard.hpp> - -#include "common/ceph_mutex.h" - -namespace ceph::async { -class io_context_pool { - std::vector<std::thread> threadvec; - boost::asio::io_context ioctx; - std::optional<boost::asio::executor_work_guard< - boost::asio::io_context::executor_type>> guard; - ceph::mutex m = make_mutex("ceph::io_context_pool::m"); - - void cleanup() noexcept { - guard = std::nullopt; - for (auto& th : threadvec) { - th.join(); - } - threadvec.clear(); - } -public: - io_context_pool() noexcept {} - io_context_pool(std::int16_t threadcnt) noexcept { - start(threadcnt); - } - ~io_context_pool() { - stop(); - } - void start(std::int16_t threadcnt) noexcept { - auto l = std::scoped_lock(m); - if (threadvec.empty()) { - guard.emplace(boost::asio::make_work_guard(ioctx)); - ioctx.restart(); - for (std::int16_t i = 0; i < threadcnt; ++i) { - // Mark this function as noexcept so any uncaught exceptions - // call terminate at point of throw. Otherwise, under - // libstdc++, they get caught by the thread cancellation - // infrastructure, unwinding the stack and making debugging - // much more difficult. - threadvec.emplace_back([this]() noexcept { - ioctx.run(); - }); - } - } - } - void finish() noexcept { - auto l = std::scoped_lock(m); - if (!threadvec.empty()) { - cleanup(); - } - } - void stop() noexcept { - auto l = std::scoped_lock(m); - if (!threadvec.empty()) { - ioctx.stop(); - cleanup(); - } - } - - boost::asio::io_context& get_io_context() { - return ioctx; - } - operator boost::asio::io_context&() { - return ioctx; - } - boost::asio::io_context::executor_type get_executor() { - return ioctx.get_executor(); - } -}; -} - -#endif // CEPH_COMMON_ASYNC_CONTEXT_POOL_H diff --git a/src/common/async/waiter.h b/src/common/async/waiter.h deleted file mode 100644 index 1e95d007c43..00000000000 --- a/src/common/async/waiter.h +++ /dev/null @@ -1,257 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net> - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#ifndef CEPH_COMMON_WAITER_H -#define CEPH_COMMON_WAITER_H - -#include <condition_variable> -#include <tuple> - -#include <boost/asio/async_result.hpp> - -#include "include/ceph_assert.h" -#include "include/function2.hpp" - -#include "common/ceph_mutex.h" - -namespace ceph::async { -namespace detail { -// For safety reasons (avoiding undefined behavior around sequence -// points) std::reference_wrapper disallows move construction. This -// harms us in cases where we want to pass a reference in to something -// that unavoidably moves. -// -// It should not be used generally. -template<typename T> -class rvalue_reference_wrapper { -public: - // types - using type = T; - - rvalue_reference_wrapper(T& r) noexcept - : p(std::addressof(r)) {} - - // We write our semantics to match those of reference collapsing. If - // we're treated as an lvalue, collapse to one. - - rvalue_reference_wrapper(const rvalue_reference_wrapper&) noexcept = default; - rvalue_reference_wrapper(rvalue_reference_wrapper&&) noexcept = default; - - // assignment - rvalue_reference_wrapper& operator=( - const rvalue_reference_wrapper& x) noexcept = default; - rvalue_reference_wrapper& operator=( - rvalue_reference_wrapper&& x) noexcept = default; - - operator T& () const noexcept { - return *p; - } - T& get() const noexcept { - return *p; - } - - operator T&& () noexcept { - return std::move(*p); - } - T&& get() noexcept { - return std::move(*p); - } - - template<typename... Args> - std::result_of_t<T&(Args&&...)> operator ()(Args&&... args ) const { - return (*p)(std::forward<Args>(args)...); - } - - template<typename... Args> - std::result_of_t<T&&(Args&&...)> operator ()(Args&&... args ) { - return std::move(*p)(std::forward<Args>(args)...); - } - -private: - T* p; -}; - -class base { -protected: - ceph::mutex lock = ceph::make_mutex("ceph::async::detail::base::lock"); - ceph::condition_variable cond; - bool has_value = false; - - ~base() = default; - - auto wait_base() { - std::unique_lock l(lock); - cond.wait(l, [this](){ return has_value; }); - return l; - } - - auto exec_base() { - std::unique_lock l(lock); - // There's no really good way to handle being called twice - // without being reset. - ceph_assert(!has_value); - has_value = true; - cond.notify_one(); - return l; - } -}; -} - -// waiter is a replacement for C_SafeCond and friends. It is the -// moral equivalent of a future but plays well with a world of -// callbacks. -template<typename ...S> -class waiter; - -template<> -class waiter<> final : public detail::base { -public: - void wait() { - wait_base(); - has_value = false; - } - - void operator()() { - exec_base(); - } - - auto ref() { - return detail::rvalue_reference_wrapper(*this); - } - - - operator fu2::unique_function<void() &&>() { - return fu2::unique_function<void() &&>(ref()); - } -}; - -template<typename Ret> -class waiter<Ret> final : public detail::base { - std::aligned_storage_t<sizeof(Ret)> ret; - -public: - Ret wait() { - auto l = wait_base(); - auto r = reinterpret_cast<Ret*>(&ret); - auto t = std::move(*r); - r->~Ret(); - has_value = false; - return t; - } - - void operator()(Ret&& _ret) { - auto l = exec_base(); - auto r = reinterpret_cast<Ret*>(&ret); - *r = std::move(_ret); - } - - void operator()(const Ret& _ret) { - auto l = exec_base(); - auto r = reinterpret_cast<Ret*>(&ret); - *r = std::move(_ret); - } - - auto ref() { - return detail::rvalue_reference_wrapper(*this); - } - - operator fu2::unique_function<void(Ret) &&>() { - return fu2::unique_function<void(Ret) &&>(ref()); - } - - ~waiter() { - if (has_value) - reinterpret_cast<Ret*>(&ret)->~Ret(); - } -}; - -template<typename ...Ret> -class waiter final : public detail::base { - std::tuple<Ret...> ret; - -public: - std::tuple<Ret...> wait() { - using std::tuple; - auto l = wait_base(); - return std::move(ret); - auto r = reinterpret_cast<std::tuple<Ret...>*>(&ret); - auto t = std::move(*r); - r->~tuple<Ret...>(); - has_value = false; - return t; - } - - void operator()(Ret&&... _ret) { - auto l = exec_base(); - auto r = reinterpret_cast<std::tuple<Ret...>*>(&ret); - *r = std::forward_as_tuple(_ret...); - } - - void operator()(const Ret&... _ret) { - auto l = exec_base(); - auto r = reinterpret_cast<std::tuple<Ret...>*>(&ret); - *r = std::forward_as_tuple(_ret...); - } - - auto ref() { - return detail::rvalue_reference_wrapper(*this); - } - - operator fu2::unique_function<void(Ret...) &&>() { - return fu2::unique_function<void(Ret...) &&>(ref()); - } - - ~waiter() { - using std::tuple; - if (has_value) - reinterpret_cast<tuple<Ret...>*>(&ret)->~tuple<Ret...>(); - } -}; -} - -namespace boost::asio { -template<typename ...S> -class async_result<ceph::async::waiter<S...>, void(S...)> { -public: - using completion_handler_type = - ceph::async::detail::rvalue_reference_wrapper<ceph::async::waiter<S...>>; - - using return_type = void; - - explicit async_result(completion_handler_type& h) {} - - return_type get() {} - - async_result(const async_result&) = delete; - async_result& operator=(const async_result&) = delete; -}; - -template<typename ...S> -struct async_completion<ceph::async::waiter<S...>, void(S...)> { - using completion_handler_type = - typename boost::asio::async_result<ceph::async::waiter<S...>, - void(S...)>::completion_handler_type; - - explicit async_completion(ceph::async::waiter<S...>& w) - : completion_handler(ceph::async::detail::rvalue_reference_wrapper(w)), - result(completion_handler){} - - completion_handler_type completion_handler; - - /// The result of the asynchronous operation's initiating function. - async_result<ceph::async::waiter<S...>, void(S...)> result; -}; -} - -#endif // CEPH_COMMON_WAITER_H diff --git a/src/common/buffer.cc b/src/common/buffer.cc index 9ea83101826..b7d3591600a 100644 --- a/src/common/buffer.cc +++ b/src/common/buffer.cc @@ -33,7 +33,6 @@ #include "common/valgrind.h" #include "common/deleter.h" #include "common/RWLock.h" -#include "common/error_code.h" #include "include/spinlock.h" #include "include/scope_guard.h" @@ -71,6 +70,21 @@ static ceph::spinlock debug_lock; return buffer_missed_crc; } + const char * buffer::error::what() const throw () { + return "buffer::exception"; + } + const char * buffer::bad_alloc::what() const throw () { + return "buffer::bad_alloc"; + } + const char * buffer::end_of_buffer::what() const throw () { + return "buffer::end_of_buffer"; + } + const char * buffer::malformed_input::what() const throw () { + return buf; + } + buffer::error_code::error_code(int error) : + buffer::malformed_input(cpp_strerror(error).c_str()), code(error) {} + /* * raw_combined is always placed within a single allocation along * with the data buffer. the data goes at the beginning, and @@ -2252,6 +2266,11 @@ std::ostream& buffer::operator<<(std::ostream& out, const buffer::list& bl) { return out; } +std::ostream& buffer::operator<<(std::ostream& out, const buffer::error& e) +{ + return out << e.what(); +} + MEMPOOL_DEFINE_OBJECT_FACTORY(buffer::raw_malloc, buffer_raw_malloc, buffer_meta); MEMPOOL_DEFINE_OBJECT_FACTORY(buffer::raw_posix_aligned, @@ -2264,81 +2283,3 @@ MEMPOOL_DEFINE_OBJECT_FACTORY(buffer::raw_unshareable, buffer_raw_unshareable, MEMPOOL_DEFINE_OBJECT_FACTORY(buffer::raw_static, buffer_raw_static, buffer_meta); - -namespace ceph::buffer { -inline namespace v14_2_0 { - -class buffer_error_category : public ceph::converting_category { -public: - buffer_error_category(){} - const char* name() const noexcept override; - std::string message(int ev) const override; - boost::system::error_condition default_error_condition(int ev) const noexcept - override; - using ceph::converting_category::equivalent; - bool equivalent(int ev, const boost::system::error_condition& c) const - noexcept override; - int from_code(int ev) const noexcept override; -}; - -const char* buffer_error_category::name() const noexcept { - return "buffer"; -} - -std::string buffer_error_category::message(int ev) const { - using ceph::buffer::errc; - if (ev == 0) - return "No error"; - - switch (static_cast<errc>(ev)) { - case errc::bad_alloc: - return "Bad allocation"; - - case errc::end_of_buffer: - return "End of buffer"; - - case errc::malformed_input: - return "Malformed input"; - } - - return "Unknown error"; -} - -boost::system::error_condition -buffer_error_category::default_error_condition(int ev)const noexcept { - using ceph::buffer::errc; - switch (static_cast<errc>(ev)) { - case errc::bad_alloc: - return boost::system::errc::not_enough_memory; - case errc::end_of_buffer: - case errc::malformed_input: - return boost::system::errc::io_error; - } - return { ev, *this }; -} - -bool buffer_error_category::equivalent(int ev, const boost::system::error_condition& c) const noexcept { - return default_error_condition(ev) == c; -} - -int buffer_error_category::from_code(int ev) const noexcept { - using ceph::buffer::errc; - switch (static_cast<errc>(ev)) { - case errc::bad_alloc: - return -ENOMEM; - - case errc::end_of_buffer: - return -EIO; - - case errc::malformed_input: - return -EIO; - } - return -EDOM; -} - -const boost::system::error_category& buffer_category() noexcept { - static const buffer_error_category c; - return c; -} -} -} diff --git a/src/common/ceph_context.h b/src/common/ceph_context.h index ae590865945..6b6e9482b99 100644 --- a/src/common/ceph_context.h +++ b/src/common/ceph_context.h @@ -25,8 +25,6 @@ #include <typeinfo> #include <typeindex> -#include <boost/intrusive_ptr.hpp> - #include "include/any.h" #include "common/cmdparse.h" @@ -365,15 +363,4 @@ private: }; #endif // WITH_SEASTAR -inline void intrusive_ptr_add_ref(CephContext* cct) -{ - cct->get(); -} - -inline void intrusive_ptr_release(CephContext* cct) -{ - cct->put(); -} - - #endif diff --git a/src/common/ceph_time.h b/src/common/ceph_time.h index a2018703a27..ae4a17c7812 100644 --- a/src/common/ceph_time.h +++ b/src/common/ceph_time.h @@ -18,7 +18,6 @@ #include <chrono> #include <iostream> #include <string> -#include <optional> #include <sys/time.h> #include "include/ceph_assert.h" @@ -435,9 +434,6 @@ namespace ceph { return std::chrono::duration_cast<timespan>( std::chrono::duration<double>(d)); } - inline std::optional<timespan> maybe_timespan(const double d) { - return d ? std::make_optional(make_timespan(d)) : std::nullopt; - } } std::ostream& operator<<(std::ostream& m, const timespan& t); diff --git a/src/common/ceph_timer.h b/src/common/ceph_timer.h index 0090f7ccdfe..b29fac9c3fc 100644 --- a/src/common/ceph_timer.h +++ b/src/common/ceph_timer.h @@ -19,9 +19,14 @@ #include <thread> #include <boost/intrusive/set.hpp> -#include "common/detail/construct_suspended.h" - namespace ceph { + + /// Newly constructed timer should be suspended at point of + /// construction. + + struct construct_suspended_t { }; + constexpr construct_suspended_t construct_suspended { }; + namespace timer_detail { using boost::intrusive::member_hook; using boost::intrusive::set_member_hook; diff --git a/src/common/config.cc b/src/common/config.cc index 4c2af4ce604..0259ef2f8ee 100644 --- a/src/common/config.cc +++ b/src/common/config.cc @@ -1306,7 +1306,7 @@ void md_config_t::_get_my_sections(const ConfigValues& values, { sections.push_back(values.name.to_str()); - sections.push_back(values.name.get_type_name().data()); + sections.push_back(values.name.get_type_name()); sections.push_back("global"); } diff --git a/src/common/detail/construct_suspended.h b/src/common/detail/construct_suspended.h deleted file mode 100644 index 521bda0f833..00000000000 --- a/src/common/detail/construct_suspended.h +++ /dev/null @@ -1,24 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2018 Red Hat <contact@redhat.com> - * Author: Adam C. Emerson <aemerson@redhat.com> - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#ifndef CEPH_COMMON_DETAIL_CONSTRUCT_SUSPENDED_H -#define CEPH_COMMON_DETAIL_CONSTRUCT_SUSPENDED_H - -namespace ceph { - struct construct_suspended_t { }; - inline constexpr construct_suspended_t construct_suspended { }; -} - -#endif // CEPH_COMMON_DETAIL_CONSTRUCT_SUSPENDED_H diff --git a/src/common/entity_name.cc b/src/common/entity_name.cc index 2eb24829a1c..37d02bd94df 100644 --- a/src/common/entity_name.cc +++ b/src/common/entity_name.cc @@ -42,22 +42,22 @@ to_cstr() const } bool EntityName:: -from_str(std::string_view s) +from_str(const string& s) { size_t pos = s.find('.'); if (pos == string::npos) return false; - - auto type_ = s.substr(0, pos); - auto id_ = s.substr(pos + 1); + + string type_ = s.substr(0, pos); + string id_ = s.substr(pos + 1); if (set(type_, id_)) return false; return true; } void EntityName:: -set(uint32_t type_, std::string_view id_) +set(uint32_t type_, const std::string &id_) { type = type_; id = id_; @@ -72,9 +72,9 @@ set(uint32_t type_, std::string_view id_) } int EntityName:: -set(std::string_view type_, std::string_view id_) +set(const std::string &type_, const std::string &id_) { - uint32_t t = str_to_ceph_entity_type(type_); + uint32_t t = str_to_ceph_entity_type(type_.c_str()); if (t == CEPH_ENTITY_TYPE_ANY) return -EINVAL; set(t, id_); @@ -88,13 +88,13 @@ set_type(uint32_t type_) } int EntityName:: -set_type(std::string_view type_) +set_type(const char *type_) { return set(type_, id); } void EntityName:: -set_id(std::string_view id_) +set_id(const std::string &id_) { set(type, id_); } @@ -106,13 +106,13 @@ void EntityName::set_name(entity_name_t n) set(n.type(), s); } -std::string_view EntityName:: +const char* EntityName:: get_type_str() const { return ceph_entity_type_name(type); } -std::string_view EntityName:: +const char *EntityName:: get_type_name() const { return ceph_entity_type_name(type); diff --git a/src/common/entity_name.h b/src/common/entity_name.h index 886c4b4946f..1dd56f66d74 100644 --- a/src/common/entity_name.h +++ b/src/common/entity_name.h @@ -15,8 +15,6 @@ #ifndef CEPH_COMMON_ENTITY_NAME_H #define CEPH_COMMON_ENTITY_NAME_H -#include <string_view> - #include <ifaddrs.h> #include "msg/msg_types.h" @@ -44,15 +42,15 @@ struct EntityName const std::string& to_str() const; const char *to_cstr() const; - bool from_str(std::string_view s); - void set(uint32_t type_, std::string_view id_); - int set(std::string_view type_, std::string_view id_); + bool from_str(const std::string& s); + void set(uint32_t type_, const std::string &id_); + int set(const std::string &type_, const std::string &id_); void set_type(uint32_t type_); - int set_type(std::string_view type); - void set_id(std::string_view id_); + int set_type(const char *type); + void set_id(const std::string &id_); void set_name(entity_name_t n); - std::string_view get_type_str() const; + const char* get_type_str() const; uint32_t get_type() const { return type; } bool is_osd() const { return get_type() == CEPH_ENTITY_TYPE_OSD; } @@ -61,7 +59,7 @@ struct EntityName bool is_client() const { return get_type() == CEPH_ENTITY_TYPE_CLIENT; } bool is_mon() const { return get_type() == CEPH_ENTITY_TYPE_MON; } - std::string_view get_type_name() const; + const char * get_type_name() const; const std::string &get_id() const; bool has_default_id() const; diff --git a/src/common/error_code.cc b/src/common/error_code.cc deleted file mode 100644 index 52eee7f1b5e..00000000000 --- a/src/common/error_code.cc +++ /dev/null @@ -1,182 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2017 Red Hat, Inc. <contact@redhat.com> - * - * Author: Adam C. Emerson <aemerson@redhat.com> - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License version - * 2.1, as published by the Free Software Foundation. See file - * COPYING. - */ - -#include <exception> - -#include "common/error_code.h" - -using boost::system::error_category; -using boost::system::error_condition; -using boost::system::generic_category; -using boost::system::system_category; - -namespace ceph { - -// A category for error conditions particular to Ceph - -class ceph_error_category : public converting_category { -public: - ceph_error_category(){} - const char* name() const noexcept override; - std::string message(int ev) const override; - using converting_category::equivalent; - bool equivalent(const boost::system::error_code& c, - int ev) const noexcept override; - int from_code(int ev) const noexcept override; -}; - -const char* ceph_error_category::name() const noexcept { - return "ceph"; -} - -std::string ceph_error_category::message(int ev) const { - if (ev == 0) - return "No error"; - - switch (static_cast<errc>(ev)) { - - case errc::not_in_map: - return "Map does not contain requested entry."; - case errc::does_not_exist: - return "Item does not exist"; - case errc::failure: - return "An internal fault or inconsistency occurred"; - case errc::exists: - return "Already exists"; - case errc::limit_exceeded: - return "Attempt to use too much"; - case errc::auth: - return "Authentication error"; - case errc::conflict: - return "Conflict detected or precondition failed"; - } - - return "Unknown error."; -} - -bool ceph_error_category::equivalent(const boost::system::error_code& c, - int ev) const noexcept { - if (c.category() == system_category()) { - if (c.value() == boost::system::errc::no_such_file_or_directory) { - if (ev == static_cast<int>(errc::not_in_map) || - ev == static_cast<int>(errc::does_not_exist)) { - // Blargh. A bunch of stuff returns ENOENT now, so just to be safe. - return true; - } - } - if (c.value() == boost::system::errc::io_error) { - if (ev == static_cast<int>(errc::failure)) { - return true; - } - } - if (c.value() == boost::system::errc::file_exists) { - if (ev == static_cast<int>(errc::exists)) { - return true; - } - } - if (c.value() == boost::system::errc::no_space_on_device || - c.value() == boost::system::errc::invalid_argument) { - if (ev == static_cast<int>(errc::limit_exceeded)) { - return true; - } - } - if (c.value() == boost::system::errc::operation_not_permitted) { - if (ev == static_cast<int>(ceph::errc::conflict)) { - return true; - } - } - } - return false; -} - -int ceph_error_category::from_code(int ev) const noexcept { - if (ev == 0) - return 0; - - switch (static_cast<errc>(ev)) { - case errc::not_in_map: - case errc::does_not_exist: - // What we use now. - return -ENOENT; - case errc::failure: - return -EIO; - case errc::exists: - return -EEXIST; - case errc::limit_exceeded: - return -EIO; - case errc::auth: - return -EACCES; - case errc::conflict: - return -EINVAL; - } - return -EDOM; -} - -const error_category& ceph_category() noexcept { - static const ceph_error_category c; - return c; -} - - -// This is part of the glue for hooking new code to old. Since -// Context* and other things give us integer codes from errno, wrap -// them in an error_code. -boost::system::error_code to_error_code(int ret) noexcept -{ - if (ret == 0) - return {}; - return { std::abs(ret), boost::system::system_category() }; -} - -// This is more complicated. For the case of categories defined -// elsewhere, we have to convert everything here. -int from_error_code(boost::system::error_code e) noexcept -{ - if (!e) - return 0; - - auto c = dynamic_cast<const converting_category*>(&e.category()); - // For categories we define - if (c) - return c->from_code(e.value()); - - // For categories matching values of errno - if (e.category() == boost::system::system_category() || - e.category() == boost::system::generic_category() || - // ASIO uses the system category for these and matches system - // error values. - e.category() == boost::asio::error::get_netdb_category() || - e.category() == boost::asio::error::get_addrinfo_category()) - return -e.value(); - - if (e.category() == boost::asio::error::get_misc_category()) { - // These values are specific to asio - switch (e.value()) { - case boost::asio::error::already_open: - return -EIO; - case boost::asio::error::eof: - return -EIO; - case boost::asio::error::not_found: - return -ENOENT; - case boost::asio::error::fd_set_failure: - return -EINVAL; - } - } - // Add any other categories we use here. - - // Marcus likes this as a sentinel for 'Error code? What error code?' - return -EDOM; -} -} diff --git a/src/common/error_code.h b/src/common/error_code.h deleted file mode 100644 index 2fc7cdd377c..00000000000 --- a/src/common/error_code.h +++ /dev/null @@ -1,75 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2017 Red Hat, Inc. <contact@redhat.com> - * - * Author: Adam C. Emerson <aemerson@redhat.com> - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License version - * 2.1, as published by the Free Software Foundation. See file - * COPYING. - */ - -#ifndef COMMON_CEPH_ERROR_CODE -#define COMMON_CEPH_ERROR_CODE - -#include <netdb.h> - -#include <boost/system/error_code.hpp> -#include <boost/asio.hpp> - -namespace ceph { - -// This is for error categories we define, so we can specify the -// equivalent integral value at the point of definition. -class converting_category : public boost::system::error_category { -public: - virtual int from_code(int code) const noexcept = 0; -}; - -const boost::system::error_category& ceph_category() noexcept; - -enum class errc { - not_in_map = 1, // The requested item was not found in the map - does_not_exist, // Item does not exist - failure, // An internal fault or inconsistency - exists, // Already exists - limit_exceeded, // Attempting to use too much of something - auth, // May not be an auth failure. It could be that the - // preconditions to attempt auth failed. - conflict, // Conflict or precondition failure -}; -} - -namespace boost { -namespace system { -template<> -struct is_error_condition_enum<::ceph::errc> { - static const bool value = true; -}; -template<> -struct is_error_code_enum<::ceph::errc> { - static const bool value = false; -}; -} -} - -namespace ceph { -// explicit conversion: -inline boost::system::error_code make_error_code(errc e) noexcept { - return { static_cast<int>(e), ceph_category() }; -} - -// implicit conversion: -inline boost::system::error_condition make_error_condition(errc e) noexcept { - return { static_cast<int>(e), ceph_category() }; -} - -boost::system::error_code to_error_code(int ret) noexcept; -int from_error_code(boost::system::error_code e) noexcept; -} - -#endif // COMMON_CEPH_ERROR_CODE diff --git a/src/common/options.cc b/src/common/options.cc index 7f65b8bd048..ddfef20fce2 100644 --- a/src/common/options.cc +++ b/src/common/options.cc @@ -5246,18 +5246,6 @@ std::vector<Option> get_global_options() { Option("debug_heartbeat_testing_span", Option::TYPE_INT, Option::LEVEL_DEV) .set_default(0) .set_description("Override 60 second periods for testing only"), - - Option("librados_thread_count", Option::TYPE_UINT, Option::LEVEL_ADVANCED) - .set_default(2) - .set_min(1) - .set_description("Size of thread pool for Objecter") - .add_tag("client"), - - Option("osd_asio_thread_count", Option::TYPE_UINT, Option::LEVEL_ADVANCED) - .set_default(2) - .set_min(1) - .set_description("Size of thread pool for ASIO completions") - .add_tag("osd") }); } @@ -7982,12 +7970,6 @@ std::vector<Option> get_mds_options() { .set_flag(Option::FLAG_RUNTIME) .set_description("max snapshots per directory") .set_long_description("maximum number of snapshots that can be created per directory"), - - Option("mds_asio_thread_count", Option::TYPE_UINT, Option::LEVEL_ADVANCED) - .set_default(2) - .set_min(1) - .set_description("Size of thread pool for ASIO completions") - .add_tag("mds") }); } @@ -8224,12 +8206,6 @@ std::vector<Option> get_mds_client_options() { Option("debug_allow_any_pool_priority", Option::TYPE_BOOL, Option::LEVEL_DEV) .set_default(false) .set_description("Allow any pool priority to be set to test conversion to new range"), - - Option("client_asio_thread_count", Option::TYPE_UINT, Option::LEVEL_ADVANCED) - .set_default(2) - .set_min(1) - .set_description("Size of thread pool for ASIO completions") - .add_tag("client") }); } diff --git a/src/common/snap_types.h b/src/common/snap_types.h index 5fd1e08bc21..9802bdea126 100644 --- a/src/common/snap_types.h +++ b/src/common/snap_types.h @@ -51,7 +51,7 @@ struct SnapContext { seq = 0; snaps.clear(); } - bool empty() const { return seq == 0; } + bool empty() { return seq == 0; } void encode(ceph::buffer::list& bl) const { using ceph::encode; diff --git a/src/crimson/osd/osd.h b/src/crimson/osd/osd.h index d0beee2fad8..843c57e6f73 100644 --- a/src/crimson/osd/osd.h +++ b/src/crimson/osd/osd.h @@ -27,13 +27,13 @@ #include "crimson/osd/pg_map.h" #include "crimson/osd/osd_operations/peering_event.h" -#include "messages/MOSDOp.h" #include "osd/PeeringState.h" #include "osd/osd_types.h" #include "osd/osd_perf_counters.h" #include "osd/PGPeeringEvent.h" class MOSDMap; +class MOSDOp; class MOSDRepOpReply; class MOSDRepOp; class OSDMap; diff --git a/src/crimson/osd/osd_operations/client_request.h b/src/crimson/osd/osd_operations/client_request.h index 09658e2bf9d..8940194f62f 100644 --- a/src/crimson/osd/osd_operations/client_request.h +++ b/src/crimson/osd/osd_operations/client_request.h @@ -6,7 +6,8 @@ #include "crimson/net/Connection.h" #include "crimson/osd/osd_operation.h" #include "crimson/common/type_helpers.h" -#include "messages/MOSDOp.h" + +class MOSDOp; namespace crimson::osd { class PG; diff --git a/src/crimson/osd/pg.h b/src/crimson/osd/pg.h index ecc2dfd5974..4c5cd11b542 100644 --- a/src/crimson/osd/pg.h +++ b/src/crimson/osd/pg.h @@ -13,8 +13,6 @@ #include "common/dout.h" #include "crimson/net/Fwd.h" -#include "messages/MOSDRepOpReply.h" -#include "messages/MOSDOpReply.h" #include "os/Transaction.h" #include "osd/osd_types.h" #include "osd/osd_internal_types.h" diff --git a/src/crimson/osd/pg_backend.h b/src/crimson/osd/pg_backend.h index 60f14b443d9..6530ef11602 100644 --- a/src/crimson/osd/pg_backend.h +++ b/src/crimson/osd/pg_backend.h @@ -12,13 +12,11 @@ #include "crimson/os/futurized_collection.h" #include "crimson/osd/acked_peers.h" #include "crimson/common/shared_lru.h" -#include "messages/MOSDOp.h" -#include "messages/MOSDOpReply.h" -#include "os/Transaction.h" #include "osd/osd_types.h" #include "osd/osd_internal_types.h" struct hobject_t; +class MOSDRepOpReply; namespace ceph::os { class Transaction; diff --git a/src/global/global_init.cc b/src/global/global_init.cc index 314cf3def03..dff97e5c7ee 100644 --- a/src/global/global_init.cc +++ b/src/global/global_init.cc @@ -12,7 +12,6 @@ * */ -#include "common/async/context_pool.h" #include "common/ceph_argparse.h" #include "common/code_environment.h" #include "common/config.h" @@ -333,16 +332,13 @@ global_init(const std::map<std::string,std::string> *defaults, // make sure our mini-session gets legacy values g_conf().apply_changes(nullptr); - ceph::async::io_context_pool cp(1); - MonClient mc_bootstrap(g_ceph_context, cp); + MonClient mc_bootstrap(g_ceph_context); if (mc_bootstrap.get_monmap_and_config() < 0) { - cp.stop(); g_ceph_context->_log->flush(); cerr << "failed to fetch mon config (--no-mon-config to skip)" << std::endl; _exit(1); } - cp.stop(); } // Expand metavariables. Invoke configuration observers. Open log file. @@ -402,6 +398,16 @@ global_init(const std::map<std::string,std::string> *defaults, return boost::intrusive_ptr<CephContext>{g_ceph_context, false}; } +void intrusive_ptr_add_ref(CephContext* cct) +{ + cct->get(); +} + +void intrusive_ptr_release(CephContext* cct) +{ + cct->put(); +} + void global_print_banner(void) { output_ceph_version(); diff --git a/src/global/global_init.h b/src/global/global_init.h index f4c9a4a8c82..fe6f557bb25 100644 --- a/src/global/global_init.h +++ b/src/global/global_init.h @@ -20,10 +20,11 @@ #include <map> #include <boost/intrusive_ptr.hpp> #include "include/ceph_assert.h" -#include "common/ceph_context.h" #include "common/code_environment.h" #include "common/common_init.h" +class CephContext; + /* * global_init is the first initialization function that * daemons and utility programs need to call. It takes care of a lot of @@ -39,6 +40,9 @@ global_init( const char *data_dir_option = 0, bool run_pre_init = true); +void intrusive_ptr_add_ref(CephContext* cct); +void intrusive_ptr_release(CephContext* cct); + // just the first half; enough to get config parsed but doesn't start up the // cct or log. void global_pre_init(const std::map<std::string,std::string> *defaults, diff --git a/src/include/Context.h b/src/include/Context.h index bef85ca5b52..6d39be55ba1 100644 --- a/src/include/Context.h +++ b/src/include/Context.h @@ -18,15 +18,10 @@ #include "common/dout.h" -#include <functional> +#include <boost/function.hpp> #include <list> -#include <memory> #include <set> - -#include <boost/function.hpp> -#include <boost/system/error_code.hpp> - -#include "common/error_code.h" +#include <memory> #include "include/ceph_assert.h" #include "common/ceph_mutex.h" @@ -53,23 +48,6 @@ class GenContext { finish(std::forward<C>(t)); delete this; } - - template <typename C> - void operator()(C &&t) noexcept { - complete(std::forward<C>(t)); - } - - template<typename U = T> - auto operator()() noexcept - -> typename std::enable_if<std::is_default_constructible<U>::value, - void>::type { - complete(T{}); - } - - - std::reference_wrapper<GenContext> func() { - return std::ref(*this); - } }; template <typename T> @@ -106,20 +84,6 @@ class Context { } return false; } - void complete(boost::system::error_code ec) { - complete(ceph::from_error_code(ec)); - } - void operator()(boost::system::error_code ec) noexcept { - complete(ec); - } - - void operator()() noexcept { - complete({}); - } - - std::reference_wrapper<Context> func() { - return std::ref(*this); - } }; /** @@ -162,10 +126,7 @@ class LambdaContext : public Context { public: LambdaContext(T &&t) : t(std::forward<T>(t)) {} void finish(int r) override { - if constexpr (std::is_invocable_v<T, int>) - t(r); - else - t(); + t(r); } private: T t; @@ -522,14 +483,6 @@ public: virtual ContextType *build() = 0; }; -inline auto lambdafy(Context *c) { - return [fin = std::unique_ptr<Context>(c)] - (boost::system::error_code ec) mutable { - fin.release()->complete(ceph::from_error_code(ec)); - }; -} - - #undef mydout #endif diff --git a/src/include/RADOS/RADOS.hpp b/src/include/RADOS/RADOS.hpp deleted file mode 100644 index a2242c98ad7..00000000000 --- a/src/include/RADOS/RADOS.hpp +++ /dev/null @@ -1,1040 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2018 Red Hat <contact@redhat.com> - * Author: Adam C. Emerson - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#ifndef RADOS_UNLEASHED_HPP -#define RADOS_UNLEASHED_HPP - -#include <cstddef> -#include <memory> -#include <tuple> -#include <string> -#include <string_view> -#include <type_traits> -#include <variant> - -#include <boost/asio.hpp> - -#include <boost/container/flat_map.hpp> -#include <boost/container/flat_set.hpp> -#include <boost/uuid/uuid.hpp> - - -// HATE. LET ME TELL YOU HOW MUCH I'VE COME TO HATE BOOST.SYSTEM SINCE -// I BEGAN TO LIVE. - -#include <boost/system/error_code.hpp> - -#include "include/function2.hpp" -#include "include/expected.hpp" - -// Needed for type erasure and template support. We can't really avoid -// it. - -#include "common/async/completion.h" - -// These are needed for RGW, but in general as a 'shiny new interface' -// we should try to use forward declarations and provide standard alternatives. - -#include "include/ceph_fs.h" -#include "include/rados/rados_types.hpp" -#include "include/rados.h" -#include "include/buffer.h" -#include "include/object.h" - -#include "common/ceph_time.h" - -// Figure out exactly what pool stat info we want to expose to clients -// and get rid of this. - -#include "osd/osd_types.h" - -#include "librados/ListObjectImpl.h" - -class CephContext; - -namespace RADOS { -class Object; -} -namespace std { -template<> -struct hash<RADOS::Object>; -} - -namespace RADOS { -namespace detail { -class RADOS; -} - -class RADOS; - -// Exists mostly so that repeated operations on the same object don't -// have to pay for the string copy to construct an object_t. - -class Object final { - friend RADOS; - friend std::hash<Object>; - -public: - Object(std::string_view s); - Object(std::string&& s); - Object(const std::string& s); - ~Object(); - - Object(const Object& o); - Object& operator =(const Object& o); - - Object(Object&& o); - Object& operator =(Object&& o); - - operator std::string_view() const; - - friend std::ostream& operator <<(std::ostream& m, const Object& o); - friend bool operator <(const Object& lhs, const Object& rhs); - friend bool operator <=(const Object& lhs, const Object& rhs); - friend bool operator >=(const Object& lhs, const Object& rhs); - friend bool operator >(const Object& lhs, const Object& rhs); - - friend bool operator ==(const Object& lhs, const Object& rhs); - friend bool operator !=(const Object& lhs, const Object& rhs); - -private: - - static constexpr std::size_t impl_size = 4 * 8; - std::aligned_storage_t<impl_size> impl; -}; - -// Not the same as the librados::IoCtx, but it does gather together -// some of the same metadata. Since we're likely to do multiple -// operations in the same pool or namespace, it doesn't make sense to -// redo a bunch of lookups and string copies. - -struct IOContext final { - friend RADOS; - - IOContext(); - explicit IOContext(std::int64_t pool); - IOContext(std::int64_t _pool, std::string_view _ns); - IOContext(std::int64_t _pool, std::string&& _ns); - ~IOContext(); - - IOContext(const IOContext& rhs); - IOContext& operator =(const IOContext& rhs); - - IOContext(IOContext&& rhs); - IOContext& operator =(IOContext&& rhs); - - std::int64_t pool() const; - void pool(std::int64_t _pool); - - std::string_view ns() const; - void ns(std::string_view _ns); - void ns(std::string&& _ns); - - // Because /some fool/ decided to disallow optional references, - // you'd have to construct a string in an optional which I would then - // take an optional reference to. Thus a separate 'clear' method. - std::optional<std::string_view> key() const; - void key(std::string_view _key); - void key(std::string&& _key); - void clear_key(); - - std::optional<std::int64_t> hash() const; - void hash(std::int64_t _hash); - void clear_hash(); - - std::optional<std::uint64_t> read_snap() const; - void read_snap(std::optional<std::uint64_t> _snapid); - - // I can't actually move-construct here since snapid_t is its own - // separate class type, not an alias. - std::optional< - std::pair<std::uint64_t, - std::vector<std::uint64_t>>> write_snap_context() const; - void write_snap_context(std::optional< - std::pair<std::uint64_t, - std::vector<std::uint64_t>>> snapc); -private: - - static constexpr std::size_t impl_size = 16 * 8; - std::aligned_storage_t<impl_size> impl; -}; - -inline constexpr std::string_view all_nspaces("\001"sv); - -enum class cmpxattr_op : std::uint8_t { - eq = 1, - ne = 2, - gt = 3, - gte = 4, - lt = 5, - lte = 6 -}; - -namespace alloc_hint { -enum alloc_hint_t { - sequential_write = CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_WRITE, - random_write = CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_WRITE, - sequential_read = CEPH_OSD_ALLOC_HINT_FLAG_SEQUENTIAL_READ, - random_read = CEPH_OSD_ALLOC_HINT_FLAG_RANDOM_READ, - append_only = CEPH_OSD_ALLOC_HINT_FLAG_APPEND_ONLY, - immutable = CEPH_OSD_ALLOC_HINT_FLAG_IMMUTABLE, - shortlived = CEPH_OSD_ALLOC_HINT_FLAG_SHORTLIVED, - longlived = CEPH_OSD_ALLOC_HINT_FLAG_LONGLIVED, - compressible = CEPH_OSD_ALLOC_HINT_FLAG_COMPRESSIBLE, - incompressible = CEPH_OSD_ALLOC_HINT_FLAG_INCOMPRESSIBLE -}; -} - -class Op { - friend RADOS; - -public: - - Op(const Op&) = delete; - Op& operator =(const Op&) = delete; - Op(Op&&); - Op& operator =(Op&&); - ~Op(); - - void set_excl(); - void set_failok(); - void set_fadvise_random(); - void set_fadvise_sequential(); - void set_fadvise_willneed(); - void set_fadvise_dontneed(); - void set_fadvise_nocache(); - - void cmpext(uint64_t off, ceph::buffer::list&& cmp_bl, std::size_t* s); - void cmpxattr(std::string_view name, cmpxattr_op op, const ceph::buffer::list& val); - void cmpxattr(std::string_view name, cmpxattr_op op, std::uint64_t val); - void assert_version(uint64_t ver); - void assert_exists(); - void cmp_omap(const boost::container::flat_map< - std::string, - std::pair<ceph::buffer::list, int>>& assertions); - - std::size_t size() const; - using Signature = void(boost::system::error_code); - using Completion = ceph::async::Completion<Signature>; - - friend std::ostream& operator <<(std::ostream& m, const Op& o); -protected: - Op(); - static constexpr std::size_t impl_size = 170 * 8; - std::aligned_storage_t<impl_size> impl; -}; - -// This class is /not/ thread-safe. If you want you can wrap it in -// something that locks it. - -class ReadOp final : public Op { - friend RADOS; - -public: - - ReadOp() = default; - ReadOp(const ReadOp&) = delete; - ReadOp(ReadOp&&) = default; - - ReadOp& operator =(const ReadOp&) = delete; - ReadOp& operator =(ReadOp&&) = default; - - void read(size_t off, uint64_t len, ceph::buffer::list* out, - boost::system::error_code* ec = nullptr); - void get_xattr(std::string_view name, ceph::buffer::list* out, - boost::system::error_code* ec = nullptr); - void get_omap_header(ceph::buffer::list*, - boost::system::error_code* ec = nullptr); - - void sparse_read(uint64_t off, uint64_t len, - ceph::buffer::list* out, - std::vector<std::pair<std::uint64_t, std::uint64_t>>* extents, - boost::system::error_code* ec = nullptr); - - void stat(std::uint64_t* size, ceph::real_time* mtime, - boost::system::error_code* ec = nullptr); - - void get_omap_keys(std::optional<std::string_view> start_after, - std::uint64_t max_return, - boost::container::flat_set<std::string>* keys, - bool* truncated, - boost::system::error_code* ec = nullptr); - - - void get_xattrs(boost::container::flat_map<std::string, - ceph::buffer::list>* kv, - boost::system::error_code* ec = nullptr); - - void get_omap_vals(std::optional<std::string_view> start_after, - std::optional<std::string_view> filter_prefix, - uint64_t max_return, - boost::container::flat_map<std::string, - ceph::buffer::list>* kv, - bool* truncated, - boost::system::error_code* ec = nullptr); - - - void get_omap_vals_by_keys(const boost::container::flat_set<std::string>& keys, - boost::container::flat_map<std::string, - ceph::buffer::list>* kv, - boost::system::error_code* ec = nullptr); - - void list_watchers(std::vector<obj_watch_t>* watchers, - boost::system::error_code* ec = nullptr); - - void list_snaps(librados::snap_set_t* snaps, - boost::system::error_code* ec = nullptr); - - void exec(std::string_view cls, std::string_view method, - const ceph::buffer::list& inbl, - ceph::buffer::list* out, - boost::system::error_code* ec = nullptr); - void exec(std::string_view cls, std::string_view method, - const ceph::buffer::list& inbl, - fu2::unique_function<void (boost::system::error_code, - const ceph::buffer::list&) &&> f); -}; - -class WriteOp final : public Op { - friend RADOS; -public: - - WriteOp() = default; - WriteOp(const WriteOp&) = delete; - WriteOp(WriteOp&&) = default; - - WriteOp& operator =(const WriteOp&) = delete; - WriteOp& operator =(WriteOp&&) = default; - - void set_mtime(ceph::real_time t); - void create(bool exclusive); - void write(uint64_t off, ceph::buffer::list&& bl); - void write_full(ceph::buffer::list&& bl); - void writesame(std::uint64_t off, std::uint64_t write_len, - ceph::buffer::list&& bl); - void append(ceph::buffer::list&& bl); - void remove(); - void truncate(uint64_t off); - void zero(uint64_t off, uint64_t len); - void rmxattr(std::string_view name); - void setxattr(std::string_view name, - ceph::buffer::list&& bl); - void rollback(uint64_t snapid); - void set_omap(const boost::container::flat_map<std::string, - ceph::buffer::list>& map); - void set_omap_header(ceph::buffer::list&& bl); - void clear_omap(); - void rm_omap_keys(const boost::container::flat_set<std::string>& to_rm); - void set_alloc_hint(uint64_t expected_object_size, - uint64_t expected_write_size, - alloc_hint::alloc_hint_t flags); - void exec(std::string_view cls, std::string_view method, - const ceph::buffer::list& inbl, boost::system::error_code* ec = nullptr); -}; - -// Come back and refactor this layer properly at some point. -using Entry = librados::ListObjectImpl; -class Cursor final { -public: - static Cursor begin(); - static Cursor end(); - - Cursor(); - Cursor(const Cursor&); - Cursor& operator =(const Cursor&); - Cursor(Cursor&&); - Cursor& operator =(Cursor&&); - ~Cursor(); - - friend bool operator ==(const Cursor& lhs, - const Cursor& rhs); - friend bool operator !=(const Cursor& lhs, - const Cursor& rhs); - friend bool operator <(const Cursor& lhs, - const Cursor& rhs); - friend bool operator <=(const Cursor& lhs, - const Cursor& rhs); - friend bool operator >=(const Cursor& lhs, - const Cursor& rhs); - friend bool operator >(const Cursor& lhs, - const Cursor& rhs); - - std::string to_str() const; - static std::optional<Cursor> from_str(const std::string& s); - -private: - struct end_magic_t {}; - Cursor(end_magic_t); - Cursor(void*); - friend RADOS; - static constexpr std::size_t impl_size = 16 * 8; - std::aligned_storage_t<impl_size> impl; -}; - -class RADOS final -{ -public: - static constexpr std::tuple<uint32_t, uint32_t, uint32_t> version() { - return {0, 0, 1}; - } - - using BuildSig = void(boost::system::error_code, RADOS); - using BuildComp = ceph::async::Completion<BuildSig>; - class Builder { - std::optional<std::string> conf_files; - std::optional<std::string> cluster; - std::optional<std::string> name; - std::vector<std::pair<std::string, std::string>> configs; - bool no_default_conf = false; - bool no_mon_conf = false; - - public: - Builder() = default; - Builder& add_conf_file(std::string_view v); - Builder& set_cluster(std::string_view c) { - cluster = std::string(c); - return *this; - } - Builder& set_name(std::string_view n) { - name = std::string(n); - return *this; - } - Builder& set_no_default_conf() { - no_default_conf = true; - return *this; - } - Builder& set_no_mon_conf() { - no_mon_conf = true; - return *this; - } - Builder& set_conf_option(std::string_view opt, std::string_view val) { - configs.emplace_back(std::string(opt), std::string(val)); - return *this; - } - - template<typename CompletionToken> - auto build(boost::asio::io_context& ioctx, CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, BuildSig> init(token); - build(ioctx, - BuildComp::create(ioctx.get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - private: - void build(boost::asio::io_context& ioctx, - std::unique_ptr<BuildComp> c); - }; - - - template<typename CompletionToken> - static auto make_with_cct(CephContext* cct, - boost::asio::io_context& ioctx, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, BuildSig> init(token); - make_with_cct(cct, ioctx, - BuildComp::create(ioctx.get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - // Because the coroutine library is stupidly written and doesn't - // support types that aren't default constructible. - // - // Under protest. I don't want a default constructor and I don't - // want people using it. - RADOS(); - - RADOS(const RADOS&) = delete; - RADOS& operator =(const RADOS&) = delete; - - RADOS(RADOS&&); - RADOS& operator =(RADOS&&); - - ~RADOS(); - - CephContext* cct(); - - using executor_type = boost::asio::io_context::executor_type; - executor_type get_executor(); - - template<typename CompletionToken> - auto execute(const Object& o, const IOContext& ioc, ReadOp&& op, - ceph::buffer::list* bl, - CompletionToken&& token, version_t* objver = nullptr) { - boost::asio::async_completion<CompletionToken, Op::Signature> init(token); - execute(o, ioc, std::move(op), bl, - ReadOp::Completion::create(get_executor(), - std::move(init.completion_handler)), - objver); - return init.result.get(); - } - - template<typename CompletionToken> - auto execute(const Object& o, const IOContext& ioc, WriteOp&& op, - CompletionToken&& token, version_t* objver = nullptr) { - boost::asio::async_completion<CompletionToken, Op::Signature> init(token); - execute(o, ioc, std::move(op), - Op::Completion::create(get_executor(), - std::move(init.completion_handler)), - objver); - return init.result.get(); - } - - template<typename CompletionToken> - auto execute(const Object& o, std::int64_t pool, - ReadOp&& op, - ceph::buffer::list* bl, - CompletionToken&& token, - std::optional<std::string_view> ns = {}, - std::optional<std::string_view> key = {}, - version_t* objver = nullptr) { - boost::asio::async_completion<CompletionToken, Op::Signature> init(token); - execute(o, pool, std::move(op), bl, - ReadOp::Completion::create(get_executor(), - std::move(init.completion_handler)), - ns, key, objver); - return init.result.get(); - } - - template<typename CompletionToken> - auto execute(const Object& o, std::int64_t pool, WriteOp&& op, - CompletionToken&& token, - std::optional<std::string_view> ns = {}, - std::optional<std::string_view> key = {}, - version_t* objver = nullptr) { - boost::asio::async_completion<CompletionToken, Op::Signature> init(token); - execute(o, pool, std::move(op), - Op::Completion::create(get_executor(), - std::move(init.completion_handler)), - ns, key, objver); - return init.result.get(); - } - - boost::uuids::uuid get_fsid() const noexcept; - - using LookupPoolSig = void(boost::system::error_code, - std::int64_t); - using LookupPoolComp = ceph::async::Completion<LookupPoolSig>; - template<typename CompletionToken> - auto lookup_pool(std::string_view name, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, LookupPoolSig> init(token); - lookup_pool(name, - LookupPoolComp::create(get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - std::optional<uint64_t> get_pool_alignment(int64_t pool_id); - - using LSPoolsSig = void(std::vector<std::pair<std::int64_t, std::string>>); - using LSPoolsComp = ceph::async::Completion<LSPoolsSig>; - template<typename CompletionToken> - auto list_pools(CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, LSPoolsSig> init(token); - list_pools(LSPoolsComp::create(get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - - - using SimpleOpSig = void(boost::system::error_code); - using SimpleOpComp = ceph::async::Completion<SimpleOpSig>; - template<typename CompletionToken> - auto create_pool_snap(int64_t pool, std::string_view snapName, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token); - create_pool_snap(pool, snapName, - SimpleOpComp::create(get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - using SMSnapSig = void(boost::system::error_code, snapid_t); - using SMSnapComp = ceph::async::Completion<SMSnapSig>; - template<typename CompletionToken> - auto allocate_selfmanaged_snap(int64_t pool, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, SMSnapSig> init(token); - allocate_selfmanaged_snap(pool, - SMSnapComp::create( - get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - template<typename CompletionToken> - auto delete_pool_snap(int64_t pool, std::string_view snapName, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token); - delete_pool_snap(pool, snapName, - SimpleOpComp::create(get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - template<typename CompletionToken> - auto delete_selfmanaged_snap(int64_t pool, std::string_view snapName, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token); - delete_selfmanaged_snap(pool, snapName, - SimpleOpComp::create( - get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - template<typename CompletionToken> - auto create_pool(std::string_view name, std::optional<int> crush_rule, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token); - create_pool(name, crush_rule, - SimpleOpComp::create(get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - template<typename CompletionToken> - auto delete_pool(std::string_view name, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token); - delete_pool(name, - SimpleOpComp::create(get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - template<typename CompletionToken> - auto delete_pool(int64_t pool, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token); - delete_pool(pool, - SimpleOpComp::create(get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - using PoolStatSig = void(boost::system::error_code, - boost::container::flat_map<std::string, - pool_stat_t>, bool); - using PoolStatComp = ceph::async::Completion<PoolStatSig>; - template<typename CompletionToken> - auto stat_pools(const std::vector<std::string>& pools, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, PoolStatSig> init(token); - stat_pools(pools, - PoolStatComp::create(get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - using StatFSSig = void(boost::system::error_code, - ceph_statfs); - using StatFSComp = ceph::async::Completion<StatFSSig>; - template<typename CompletionToken> - auto statfs(std::optional<int64_t> pool, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, StatFSSig> init(token); - ceph_statfs(pool, StatFSComp::create(get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - using WatchCB = fu2::unique_function<void(boost::system::error_code, - uint64_t notify_id, - uint64_t cookie, - uint64_t notifier_id, - ceph::buffer::list&& bl)>; - - using WatchSig = void(boost::system::error_code ec, - uint64_t cookie); - using WatchComp = ceph::async::Completion<WatchSig>; - template<typename CompletionToken> - auto watch(const Object& o, const IOContext& ioc, - std::optional<std::chrono::seconds> timeout, - WatchCB&& cb, CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, WatchSig> init(token); - watch(o, ioc, timeout, std::move(cb), - WatchComp::create(get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - template<typename CompletionToken> - auto watch(const Object& o, std::int64_t pool, - std::optional<std::chrono::seconds> timeout, - WatchCB&& cb, CompletionToken&& token, - std::optional<std::string_view> ns = {}, - std::optional<std::string_view> key = {}) { - boost::asio::async_completion<CompletionToken, WatchSig> init(token); - watch(o, pool, timeout, std::move(cb), - WatchComp::create(get_executor(), - std::move(init.completion_handler)), - ns, key); - return init.result.get(); - } - - template<typename CompletionToken> - auto notify_ack(const Object& o, - const IOContext& ioc, - uint64_t notify_id, - uint64_t cookie, - ceph::buffer::list&& bl, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token); - notify_ack(o, ioc, notify_id, cookie, std::move(bl), - SimpleOpComp::create(get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - template<typename CompletionToken> - auto notify_ack(const Object& o, - std::int64_t pool, - uint64_t notify_id, - uint64_t cookie, - ceph::buffer::list&& bl, - CompletionToken&& token, - std::optional<std::string_view> ns = {}, - std::optional<std::string_view> key = {}) { - boost::asio::async_completion<CompletionToken, WatchSig> init(token); - notify_ack(o, pool, notify_id, cookie, std::move(bl), - SimpleOpComp::create(get_executor(), - std::move(init.completion_handler)), - ns, key); - return init.result.get(); - } - - template<typename CompletionToken> - auto unwatch(uint64_t cookie, const IOContext& ioc, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token); - unwatch(cookie, ioc, - SimpleOpComp::create(get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - template<typename CompletionToken> - auto unwatch(uint64_t cookie, std::int64_t pool, - CompletionToken&& token, - std::optional<std::string_view> ns = {}, - std::optional<std::string_view> key = {}) { - boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token); - unwatch(cookie, pool, - SimpleOpComp::create(get_executor(), - std::move(init.completion_handler)), - ns, key); - return init.result.get(); - } - - // This is one of those places where having to force everything into - // a .cc file is really infuriating. If we had modules, that would - // let us separate out the implementation details without - // sacrificing all the benefits of templates. - using VoidOpSig = void(); - using VoidOpComp = ceph::async::Completion<VoidOpSig>; - template<typename CompletionToken> - auto flush_watch(CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, VoidOpSig> init(token); - flush_watch(VoidOpComp::create(get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - using NotifySig = void(boost::system::error_code, ceph::buffer::list); - using NotifyComp = ceph::async::Completion<NotifySig>; - template<typename CompletionToken> - auto notify(const Object& oid, const IOContext& ioc, ceph::buffer::list&& bl, - std::optional<std::chrono::milliseconds> timeout, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, NotifySig> init(token); - notify(oid, ioc, std::move(bl), timeout, - NotifyComp::create(get_executor(), - std::move(init.completion_handler))); - - return init.result.get(); - } - - template<typename CompletionToken> - auto notify(const Object& oid, std::int64_t pool, ceph::buffer::list&& bl, - std::optional<std::chrono::milliseconds> timeout, - CompletionToken&& token, - std::optional<std::string_view> ns = {}, - std::optional<std::string_view> key = {}) { - boost::asio::async_completion<CompletionToken, NotifySig> init(token); - notify(oid, pool, bl, timeout, - NotifyComp::create(get_executor(), - std::move(init.completion_handler)), - ns, key); - - return init.result.get(); - } - - template<typename CompletionToken> - auto enumerate_objects(const IOContext& ioc, const Cursor& begin, - const Cursor& end, const std::uint32_t max, - const ceph::buffer::list& filter, - std::vector<Entry>* ls, - Cursor* cursor, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token); - enumerate_objects(ioc, begin, end, max, filter, - ls, cursor, - SimpleOpComp::create(get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - template<typename CompletionToken> - auto enumerate_objects(std::int64_t pool, const Cursor& begin, - const Cursor& end, const std::uint32_t max, - const ceph::buffer::list& filter, - std::vector<Entry>* ls, - Cursor* cursor, - CompletionToken&& token, - std::optional<std::string_view> ns = {}, - std::optional<std::string_view> key = {}) { - boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token); - enumerate_objects(pool, begin, end, max, filter, - ls, cursor, - SimpleOpComp::create(get_executor(), - std::move(init.completion_handler)), - ns, key); - return init.result.get(); - } - - // The versions with pointers are fine for coroutines, but - // extraordinarily unappealing for callback-oriented programming. - using EnumerateSig = void(boost::system::error_code, - std::vector<Entry>, - Cursor); - using EnumerateComp = ceph::async::Completion<EnumerateSig>; - template<typename CompletionToken> - auto enumerate_objects(const IOContext& ioc, const Cursor& begin, - const Cursor& end, const std::uint32_t max, - const ceph::buffer::list& filter, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, EnumerateSig> init(token); - enumerate_objects(ioc, begin, end, max, filter, - EnumerateComp::create(get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - template<typename CompletionToken> - auto enumerate_objects(std::int64_t pool, const Cursor& begin, - const Cursor& end, const std::uint32_t max, - const ceph::buffer::list& filter, - CompletionToken&& token, - std::optional<std::string_view> ns = {}, - std::optional<std::string_view> key = {}) { - boost::asio::async_completion<CompletionToken, EnumerateSig> init(token); - enumerate_objects(pool, begin, end, max, filter, - EnumerateComp::create(get_executor(), - std::move(init.completion_handler)), - ns, key); - return init.result.get(); - } - - using CommandSig = void(boost::system::error_code, - std::string, ceph::buffer::list); - using CommandComp = ceph::async::Completion<CommandSig>; - template<typename CompletionToken> - auto osd_command(int osd, std::vector<std::string>&& cmd, - ceph::buffer::list&& in, CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, CommandSig> init(token); - osd_command(osd, std::move(cmd), std::move(in), - CommandComp::create(get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - template<typename CompletionToken> - auto pg_command(pg_t pg, std::vector<std::string>&& cmd, - ceph::buffer::list&& in, CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, CommandSig> init(token); - pg_command(pg, std::move(cmd), std::move(in), - CommandComp::create(get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - template<typename CompletionToken> - auto mon_command(std::vector<std::string> command, - const ceph::buffer::list& bl, - std::string* outs, ceph::buffer::list* outbl, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token); - mon_command(command, bl, outs, outbl, - SimpleOpComp::create(get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - template<typename CompletionToken> - auto enable_application(std::string_view pool, std::string_view app_name, - bool force, CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, SimpleOpSig> init(token); - enable_application(pool, app_name, force, - SimpleOpComp::create(get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - uint64_t instance_id() const; - -private: - - friend Builder; - - RADOS(std::unique_ptr<detail::RADOS> impl); - static void make_with_cct(CephContext* cct, - boost::asio::io_context& ioctx, - std::unique_ptr<BuildComp> c); - - void execute(const Object& o, const IOContext& ioc, ReadOp&& op, - ceph::buffer::list* bl, std::unique_ptr<Op::Completion> c, - version_t* objver); - - void execute(const Object& o, const IOContext& ioc, WriteOp&& op, - std::unique_ptr<Op::Completion> c, version_t* objver); - - void execute(const Object& o, std::int64_t pool, ReadOp&& op, - ceph::buffer::list* bl, std::unique_ptr<Op::Completion> c, - std::optional<std::string_view> ns, - std::optional<std::string_view> key, - version_t* objver); - - void execute(const Object& o, std::int64_t pool, WriteOp&& op, - std::unique_ptr<Op::Completion> c, - std::optional<std::string_view> ns, - std::optional<std::string_view> key, - version_t* objver); - - void lookup_pool(std::string_view name, std::unique_ptr<LookupPoolComp> c); - void list_pools(std::unique_ptr<LSPoolsComp> c); - void create_pool_snap(int64_t pool, std::string_view snapName, - std::unique_ptr<SimpleOpComp> c); - void allocate_selfmanaged_snap(int64_t pool, std::unique_ptr<SMSnapComp> c); - void delete_pool_snap(int64_t pool, std::string_view snapName, - std::unique_ptr<SimpleOpComp> c); - void delete_selfmanaged_snap(int64_t pool, snapid_t snap, - std::unique_ptr<SimpleOpComp> c); - void create_pool(std::string_view name, std::optional<int> crush_rule, - std::unique_ptr<SimpleOpComp> c); - void delete_pool(std::string_view name, - std::unique_ptr<SimpleOpComp> c); - void delete_pool(int64_t pool, - std::unique_ptr<SimpleOpComp> c); - void stat_pools(const std::vector<std::string>& pools, - std::unique_ptr<PoolStatComp> c); - void stat_fs(std::optional<std::int64_t> pool, - std::unique_ptr<StatFSComp> c); - - void watch(const Object& o, const IOContext& ioc, - std::optional<std::chrono::seconds> timeout, - WatchCB&& cb, std::unique_ptr<WatchComp> c); - void watch(const Object& o, std::int64_t pool, - std::optional<std::chrono::seconds> timeout, - WatchCB&& cb, std::unique_ptr<WatchComp> c, - std::optional<std::string_view> ns, - std::optional<std::string_view> key); - tl::expected<ceph::timespan, boost::system::error_code> - watch_check(uint64_t cookie); - void notify_ack(const Object& o, - const IOContext& _ioc, - uint64_t notify_id, - uint64_t cookie, - ceph::buffer::list&& bl, - std::unique_ptr<SimpleOpComp>); - void notify_ack(const Object& o, - std::int64_t pool, - uint64_t notify_id, - uint64_t cookie, - ceph::buffer::list&& bl, - std::unique_ptr<SimpleOpComp>, - std::optional<std::string_view> ns, - std::optional<std::string_view> key); - void unwatch(uint64_t cookie, const IOContext& ioc, - std::unique_ptr<SimpleOpComp>); - void unwatch(uint64_t cookie, std::int64_t pool, - std::unique_ptr<SimpleOpComp>, - std::optional<std::string_view> ns, - std::optional<std::string_view> key); - void notify(const Object& oid, const IOContext& ioctx, - ceph::buffer::list&& bl, - std::optional<std::chrono::milliseconds> timeout, - std::unique_ptr<NotifyComp> c); - void notify(const Object& oid, std::int64_t pool, - ceph::buffer::list&& bl, - std::optional<std::chrono::milliseconds> timeout, - std::unique_ptr<NotifyComp> c, - std::optional<std::string_view> ns, - std::optional<std::string_view> key); - void flush_watch(std::unique_ptr<VoidOpComp>); - - void enumerate_objects(const IOContext& ioc, const Cursor& begin, - const Cursor& end, const std::uint32_t max, - const ceph::buffer::list& filter, - std::vector<Entry>* ls, - Cursor* cursor, - std::unique_ptr<SimpleOpComp> c); - void enumerate_objects(std::int64_t pool, const Cursor& begin, - const Cursor& end, const std::uint32_t max, - const ceph::buffer::list& filter, - std::vector<Entry>* ls, - Cursor* cursor, - std::unique_ptr<SimpleOpComp> c, - std::optional<std::string_view> ns, - std::optional<std::string_view> key); - void enumerate_objects(const IOContext& ioc, const Cursor& begin, - const Cursor& end, const std::uint32_t max, - const ceph::buffer::list& filter, - std::unique_ptr<EnumerateComp> c); - void enumerate_objects(std::int64_t pool, const Cursor& begin, - const Cursor& end, const std::uint32_t max, - const ceph::buffer::list& filter, - std::unique_ptr<EnumerateComp> c, - std::optional<std::string_view> ns, - std::optional<std::string_view> key); - void osd_command(int osd, std::vector<std::string>&& cmd, - ceph::buffer::list&& in, std::unique_ptr<CommandComp> c); - void pg_command(pg_t pg, std::vector<std::string>&& cmd, - ceph::buffer::list&& in, std::unique_ptr<CommandComp> c); - - void mon_command(std::vector<std::string> command, - const ceph::buffer::list& bl, - std::string* outs, ceph::buffer::list* outbl, - std::unique_ptr<SimpleOpComp> c); - - void enable_application(std::string_view pool, std::string_view app_name, - bool force, std::unique_ptr<SimpleOpComp> c); - - - // Since detail::RADOS has immovable things inside it, hold a - // unique_ptr to it so we can be moved. - std::unique_ptr<detail::RADOS> impl; -}; -} - -namespace std { -template<> -struct hash<RADOS::Object> { - size_t operator ()(const RADOS::Object& r) const; -}; -} // namespace std - -#endif diff --git a/src/include/RADOS/buffer_fwd.h b/src/include/RADOS/buffer_fwd.h deleted file mode 120000 index bd1f6f1b064..00000000000 --- a/src/include/RADOS/buffer_fwd.h +++ /dev/null @@ -1 +0,0 @@ -../buffer_fwd.h
\ No newline at end of file diff --git a/src/include/RADOS/completion.h b/src/include/RADOS/completion.h deleted file mode 120000 index 100678fc2a5..00000000000 --- a/src/include/RADOS/completion.h +++ /dev/null @@ -1 +0,0 @@ -../../common/async/completion.h
\ No newline at end of file diff --git a/src/include/buffer.h b/src/include/buffer.h index 3d41eaa6e67..98358e450f6 100644 --- a/src/include/buffer.h +++ b/src/include/buffer.h @@ -50,13 +50,10 @@ #include <exception> #include <type_traits> -#include <boost/system/system_error.hpp> - #include "page.h" #include "crc32c.h" #include "buffer_fwd.h" - #ifdef __CEPH__ # include "include/ceph_assert.h" #else @@ -104,69 +101,30 @@ struct unique_leakable_ptr : public std::unique_ptr<T, ceph::nop_delete<T>> { namespace buffer CEPH_BUFFER_API { inline namespace v14_2_0 { - const boost::system::error_category& buffer_category() noexcept; - enum class errc { bad_alloc = 1, - end_of_buffer, - malformed_input }; -} -} -} - -namespace boost { -namespace system { -template<> -struct is_error_code_enum<::ceph::buffer::errc> { - static const bool value = true; -}; -} -} - -namespace ceph { - -namespace buffer CEPH_BUFFER_API { -inline namespace v14_2_0 { - /* * exceptions */ - // explicit conversion: - inline boost::system::error_code make_error_code(errc e) noexcept { - return { static_cast<int>(e), buffer_category() }; - } - -// implicit conversion: - inline boost::system::error_condition - make_error_condition(errc e) noexcept { - return { static_cast<int>(e), buffer_category() }; - } - - using error = boost::system::system_error; - + struct error : public std::exception{ + const char *what() const throw () override; + }; struct bad_alloc : public error { - bad_alloc() : error(errc::bad_alloc) {} - bad_alloc(const char* what_arg) : error(errc::bad_alloc, what_arg) {} - bad_alloc(const std::string& what_arg) : error(errc::bad_alloc, what_arg) {} + const char *what() const throw () override; }; struct end_of_buffer : public error { - end_of_buffer() : error(errc::end_of_buffer) {} - end_of_buffer(const char* what_arg) : error(errc::end_of_buffer, what_arg) {} - end_of_buffer(const std::string& what_arg) - : error(errc::end_of_buffer, what_arg) {} + const char *what() const throw () override; }; struct malformed_input : public error { - malformed_input() : error(errc::malformed_input) {} - malformed_input(const char* what_arg) - : error(errc::malformed_input, what_arg) {} - malformed_input(const std::string& what_arg) - : error(errc::malformed_input, what_arg) {} + explicit malformed_input(const std::string& w) { + snprintf(buf, sizeof(buf), "buffer::malformed_input: %s", w.c_str()); + } + const char *what() const throw () override; + private: + char buf[256]; }; - struct error_code : public error { - error_code(int r) : error(-r, boost::system::system_category()) {} - error_code(int r, const char* what_arg) - : error(-r, boost::system::system_category(), what_arg) {} - error_code(int r, const std::string& what_arg) - : error(-r, boost::system::system_category(), what_arg) {} + struct error_code : public malformed_input { + explicit error_code(int error); + int code; }; @@ -1354,5 +1312,4 @@ inline bufferhash& operator<<(bufferhash& l, const bufferlist &r) { } // namespace ceph - #endif diff --git a/src/include/expected.hpp b/src/include/expected.hpp deleted file mode 100644 index 740c6ad2495..00000000000 --- a/src/include/expected.hpp +++ /dev/null @@ -1,2282 +0,0 @@ -/// -// expected - An implementation of std::expected with extensions -// Written in 2017 by Simon Brand (@TartanLlama) -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to the -// public domain worldwide. This software is distributed without any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. If not, see -// <http://creativecommons.org/publicdomain/zero/1.0/>. -/// - -#ifndef TL_EXPECTED_HPP -#define TL_EXPECTED_HPP - -#define TL_EXPECTED_VERSION_MAJOR 0 -#define TL_EXPECTED_VERSION_MINOR 2 - -#include <exception> -#include <functional> -#include <type_traits> -#include <utility> - -#if defined(__EXCEPTIONS) || defined(_CPPUNWIND) -#define TL_EXPECTED_EXCEPTIONS_ENABLED -#endif - -#if (defined(_MSC_VER) && _MSC_VER == 1900) -/// \exclude -#define TL_EXPECTED_MSVC2015 -#define TL_EXPECTED_MSVC2015_CONSTEXPR -#else -#define TL_EXPECTED_MSVC2015_CONSTEXPR constexpr -#endif - -#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ - !defined(__clang__)) -/// \exclude -#define TL_EXPECTED_GCC49 -#endif - -#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \ - !defined(__clang__)) -/// \exclude -#define TL_EXPECTED_GCC54 -#endif - -#if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \ - !defined(__clang__)) -/// \exclude -#define TL_EXPECTED_GCC55 -#endif - -#if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ - !defined(__clang__)) -// GCC < 5 doesn't support overloading on const&& for member functions -/// \exclude -#define TL_EXPECTED_NO_CONSTRR - -// GCC < 5 doesn't support some standard C++11 type traits -/// \exclude -#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ - std::has_trivial_copy_constructor<T> -/// \exclude -#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ - std::has_trivial_copy_assign<T> - -// This one will be different for GCC 5.7 if it's ever supported -/// \exclude -#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \ - std::is_trivially_destructible<T> - -// GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks std::vector -// for non-copyable types -#elif (defined(__GNUC__) && __GNUC__ < 8 && \ - !defined(__clang__)) -#ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX -#define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX -namespace tl { - namespace detail { - template<class T> - struct is_trivially_copy_constructible : std::is_trivially_copy_constructible<T>{}; -#ifdef _GLIBCXX_VECTOR - template<class T, class A> - struct is_trivially_copy_constructible<std::vector<T,A>> - : std::is_trivially_copy_constructible<T>{}; -#endif - } -} -#endif - -#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ - tl::detail::is_trivially_copy_constructible<T> -#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ - std::is_trivially_copy_assignable<T> -#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible<T> -#else -/// \exclude -#define TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ - std::is_trivially_copy_constructible<T> -/// \exclude -#define TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ - std::is_trivially_copy_assignable<T> -/// \exclude -#define TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T) \ - std::is_trivially_destructible<T> -#endif - -#if __cplusplus > 201103L -/// \exclude -#define TL_EXPECTED_CXX14 -#endif - -#ifdef TL_EXPECTED_GCC49 -#define TL_EXPECTED_GCC49_CONSTEXPR -#else -#define TL_EXPECTED_GCC49_CONSTEXPR constexpr -#endif - -#if (__cplusplus == 201103L || defined(TL_EXPECTED_MSVC2015) || \ - defined(TL_EXPECTED_GCC49)) -/// \exclude -#define TL_EXPECTED_11_CONSTEXPR -#else -/// \exclude -#define TL_EXPECTED_11_CONSTEXPR constexpr -#endif - -namespace tl { -template <class T, class E> class expected; - -#ifndef TL_MONOSTATE_INPLACE_MUTEX -#define TL_MONOSTATE_INPLACE_MUTEX -/// \brief Used to represent an expected with no data -class monostate {}; - -/// \brief A tag type to tell expected to construct its value in-place -struct in_place_t { - explicit in_place_t() = default; -}; -/// \brief A tag to tell expected to construct its value in-place -static constexpr in_place_t in_place{}; -#endif - -/// Used as a wrapper to store the unexpected value -template <class E> class unexpected { -public: - static_assert(!std::is_same<E, void>::value, "E must not be void"); - - unexpected() = delete; - constexpr explicit unexpected(const E &e) : m_val(e) {} - - constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {} - - /// \returns the contained value - /// \group unexpected_value - constexpr const E &value() const & { return m_val; } - /// \group unexpected_value - TL_EXPECTED_11_CONSTEXPR E &value() & { return m_val; } - /// \group unexpected_value - TL_EXPECTED_11_CONSTEXPR E &&value() && { return std::move(m_val); } - /// \exclude - constexpr const E &&value() const && { return std::move(m_val); } - -private: - E m_val; -}; - -/// \brief Compares two unexpected objects -/// \details Simply compares lhs.value() to rhs.value() -/// \group unexpected_relop -template <class E> -constexpr bool operator==(const unexpected<E> &lhs, const unexpected<E> &rhs) { - return lhs.value() == rhs.value(); -} -/// \group unexpected_relop -template <class E> -constexpr bool operator!=(const unexpected<E> &lhs, const unexpected<E> &rhs) { - return lhs.value() != rhs.value(); -} -/// \group unexpected_relop -template <class E> -constexpr bool operator<(const unexpected<E> &lhs, const unexpected<E> &rhs) { - return lhs.value() < rhs.value(); -} -/// \group unexpected_relop -template <class E> -constexpr bool operator<=(const unexpected<E> &lhs, const unexpected<E> &rhs) { - return lhs.value() <= rhs.value(); -} -/// \group unexpected_relop -template <class E> -constexpr bool operator>(const unexpected<E> &lhs, const unexpected<E> &rhs) { - return lhs.value() > rhs.value(); -} -/// \group unexpected_relop -template <class E> -constexpr bool operator>=(const unexpected<E> &lhs, const unexpected<E> &rhs) { - return lhs.value() >= rhs.value(); -} - -/// Create an `unexpected` from `e`, deducing the return type -/// -/// *Example:* -/// auto e1 = tl::make_unexpected(42); -/// unexpected<int> e2 (42); //same semantics -template <class E> -unexpected<typename std::decay<E>::type> make_unexpected(E &&e) { - return unexpected<typename std::decay<E>::type>(std::forward<E>(e)); -} - -/// \brief A tag type to tell expected to construct the unexpected value -struct unexpect_t { - unexpect_t() = default; -}; -/// \brief A tag to tell expected to construct the unexpected value -static constexpr unexpect_t unexpect{}; - -/// \exclude -namespace detail { -template<typename E> -[[noreturn]] TL_EXPECTED_11_CONSTEXPR void throw_exception(E &&e) { -#ifdef TL_EXPECTED_EXCEPTIONS_ENABLED - throw std::forward<E>(e); -#else - #ifdef _MSC_VER - __assume(0); - #else - __builtin_unreachable(); - #endif -#endif -} - -#ifndef TL_TRAITS_MUTEX -#define TL_TRAITS_MUTEX -// C++14-style aliases for brevity -template <class T> using remove_const_t = typename std::remove_const<T>::type; -template <class T> -using remove_reference_t = typename std::remove_reference<T>::type; -template <class T> using decay_t = typename std::decay<T>::type; -template <bool E, class T = void> -using enable_if_t = typename std::enable_if<E, T>::type; -template <bool B, class T, class F> -using conditional_t = typename std::conditional<B, T, F>::type; - -// std::conjunction from C++17 -template <class...> struct conjunction : std::true_type {}; -template <class B> struct conjunction<B> : B {}; -template <class B, class... Bs> -struct conjunction<B, Bs...> - : std::conditional<bool(B::value), conjunction<Bs...>, B>::type {}; - -// std::invoke from C++17 -// https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround -template <typename Fn, typename... Args, - typename = enable_if_t<std::is_member_pointer<decay_t<Fn>>{}>, - int = 0> -constexpr auto invoke(Fn &&f, Args &&... args) noexcept( - noexcept(std::mem_fn(f)(std::forward<Args>(args)...))) - -> decltype(std::mem_fn(f)(std::forward<Args>(args)...)) { - return std::mem_fn(f)(std::forward<Args>(args)...); -} - -template <typename Fn, typename... Args, - typename = enable_if_t<!std::is_member_pointer<decay_t<Fn>>{}>> -constexpr auto invoke(Fn &&f, Args &&... args) noexcept( - noexcept(std::forward<Fn>(f)(std::forward<Args>(args)...))) - -> decltype(std::forward<Fn>(f)(std::forward<Args>(args)...)) { - return std::forward<Fn>(f)(std::forward<Args>(args)...); -} - -// std::invoke_result from C++17 -template <class F, class, class... Us> struct invoke_result_impl; - -template <class F, class... Us> -struct invoke_result_impl< - F, decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...), void()), - Us...> { - using type = decltype(detail::invoke(std::declval<F>(), std::declval<Us>()...)); -}; - -template <class F, class... Us> -using invoke_result = invoke_result_impl<F, void, Us...>; - -template <class F, class... Us> -using invoke_result_t = typename invoke_result<F, Us...>::type; -#endif - -// Trait for checking if a type is a tl::expected -template <class T> struct is_expected_impl : std::false_type {}; -template <class T, class E> -struct is_expected_impl<expected<T, E>> : std::true_type {}; -template <class T> using is_expected = is_expected_impl<decay_t<T>>; - -template <class T, class E, class U> -using expected_enable_forward_value = detail::enable_if_t< - std::is_constructible<T, U &&>::value && - !std::is_same<detail::decay_t<U>, in_place_t>::value && - !std::is_same<expected<T, E>, detail::decay_t<U>>::value && - !std::is_same<unexpected<E>, detail::decay_t<U>>::value>; - -template <class T, class E, class U, class G, class UR, class GR> -using expected_enable_from_other = detail::enable_if_t< - std::is_constructible<T, UR>::value && - std::is_constructible<E, GR>::value && - !std::is_constructible<T, expected<U, G> &>::value && - !std::is_constructible<T, expected<U, G> &&>::value && - !std::is_constructible<T, const expected<U, G> &>::value && - !std::is_constructible<T, const expected<U, G> &&>::value && - !std::is_convertible<expected<U, G> &, T>::value && - !std::is_convertible<expected<U, G> &&, T>::value && - !std::is_convertible<const expected<U, G> &, T>::value && - !std::is_convertible<const expected<U, G> &&, T>::value>; - -template <class T, class U> -using is_void_or = conditional_t<std::is_void<T>::value, std::true_type, U>; - -template <class T> -using is_copy_constructible_or_void = - is_void_or<T, std::is_copy_constructible<T>>; - -template <class T> -using is_move_constructible_or_void = - is_void_or<T, std::is_move_constructible<T>>; - -template <class T> -using is_copy_assignable_or_void = - is_void_or<T, std::is_copy_assignable<T>>; - - -template <class T> -using is_move_assignable_or_void = - is_void_or<T, std::is_move_assignable<T>>; - - -} // namespace detail - -/// \exclude -namespace detail { -struct no_init_t {}; -static constexpr no_init_t no_init{}; - -// Implements the storage of the values, and ensures that the destructor is -// trivial if it can be. -// -// This specialization is for where neither `T` or `E` is trivially -// destructible, so the destructors must be called on destruction of the -// `expected` -template <class T, class E, bool = std::is_trivially_destructible<T>::value, - bool = std::is_trivially_destructible<E>::value> -struct expected_storage_base { - constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} - constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} - - template <class... Args, - detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * = - nullptr> - constexpr expected_storage_base(in_place_t, Args &&... args) - : m_val(std::forward<Args>(args)...), m_has_val(true) {} - - template <class U, class... Args, - detail::enable_if_t<std::is_constructible< - T, std::initializer_list<U> &, Args &&...>::value> * = nullptr> - constexpr expected_storage_base(in_place_t, std::initializer_list<U> il, - Args &&... args) - : m_val(il, std::forward<Args>(args)...), m_has_val(true) {} - template <class... Args, - detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = - nullptr> - constexpr explicit expected_storage_base(unexpect_t, Args &&... args) - : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {} - - template <class U, class... Args, - detail::enable_if_t<std::is_constructible< - E, std::initializer_list<U> &, Args &&...>::value> * = nullptr> - constexpr explicit expected_storage_base(unexpect_t, - std::initializer_list<U> il, - Args &&... args) - : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {} - - ~expected_storage_base() { - if (m_has_val) { - m_val.~T(); - } else { - m_unexpect.~unexpected<E>(); - } - } - union { - char m_no_init; - T m_val; - unexpected<E> m_unexpect; - }; - bool m_has_val; -}; - -// This specialization is for when both `T` and `E` are trivially-destructible, -// so the destructor of the `expected` can be trivial. -template <class T, class E> struct expected_storage_base<T, E, true, true> { - constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} - constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} - - template <class... Args, - detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * = - nullptr> - constexpr expected_storage_base(in_place_t, Args &&... args) - : m_val(std::forward<Args>(args)...), m_has_val(true) {} - - template <class U, class... Args, - detail::enable_if_t<std::is_constructible< - T, std::initializer_list<U> &, Args &&...>::value> * = nullptr> - constexpr expected_storage_base(in_place_t, std::initializer_list<U> il, - Args &&... args) - : m_val(il, std::forward<Args>(args)...), m_has_val(true) {} - template <class... Args, - detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = - nullptr> - constexpr explicit expected_storage_base(unexpect_t, Args &&... args) - : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {} - - template <class U, class... Args, - detail::enable_if_t<std::is_constructible< - E, std::initializer_list<U> &, Args &&...>::value> * = nullptr> - constexpr explicit expected_storage_base(unexpect_t, - std::initializer_list<U> il, - Args &&... args) - : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {} - - ~expected_storage_base() = default; - union { - char m_no_init; - T m_val; - unexpected<E> m_unexpect; - }; - bool m_has_val; -}; - -// T is trivial, E is not. -template <class T, class E> struct expected_storage_base<T, E, true, false> { - constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} - TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base(no_init_t) - : m_no_init(), m_has_val(false) {} - - template <class... Args, - detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * = - nullptr> - constexpr expected_storage_base(in_place_t, Args &&... args) - : m_val(std::forward<Args>(args)...), m_has_val(true) {} - - template <class U, class... Args, - detail::enable_if_t<std::is_constructible< - T, std::initializer_list<U> &, Args &&...>::value> * = nullptr> - constexpr expected_storage_base(in_place_t, std::initializer_list<U> il, - Args &&... args) - : m_val(il, std::forward<Args>(args)...), m_has_val(true) {} - template <class... Args, - detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = - nullptr> - constexpr explicit expected_storage_base(unexpect_t, Args &&... args) - : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {} - - template <class U, class... Args, - detail::enable_if_t<std::is_constructible< - E, std::initializer_list<U> &, Args &&...>::value> * = nullptr> - constexpr explicit expected_storage_base(unexpect_t, - std::initializer_list<U> il, - Args &&... args) - : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {} - - ~expected_storage_base() { - if (!m_has_val) { - m_unexpect.~unexpected<E>(); - } - } - - union { - char m_no_init; - T m_val; - unexpected<E> m_unexpect; - }; - bool m_has_val; -}; - -// E is trivial, T is not. -template <class T, class E> struct expected_storage_base<T, E, false, true> { - constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {} - constexpr expected_storage_base(no_init_t) : m_no_init(), m_has_val(false) {} - - template <class... Args, - detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * = - nullptr> - constexpr expected_storage_base(in_place_t, Args &&... args) - : m_val(std::forward<Args>(args)...), m_has_val(true) {} - - template <class U, class... Args, - detail::enable_if_t<std::is_constructible< - T, std::initializer_list<U> &, Args &&...>::value> * = nullptr> - constexpr expected_storage_base(in_place_t, std::initializer_list<U> il, - Args &&... args) - : m_val(il, std::forward<Args>(args)...), m_has_val(true) {} - template <class... Args, - detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = - nullptr> - constexpr explicit expected_storage_base(unexpect_t, Args &&... args) - : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {} - - template <class U, class... Args, - detail::enable_if_t<std::is_constructible< - E, std::initializer_list<U> &, Args &&...>::value> * = nullptr> - constexpr explicit expected_storage_base(unexpect_t, - std::initializer_list<U> il, - Args &&... args) - : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {} - - ~expected_storage_base() { - if (m_has_val) { - m_val.~T(); - } - } - union { - char m_no_init; - T m_val; - unexpected<E> m_unexpect; - }; - bool m_has_val; -}; - -// `T` is `void`, `E` is trivially-destructible -template <class E> struct expected_storage_base<void, E, false, true> { - TL_EXPECTED_MSVC2015_CONSTEXPR expected_storage_base() : m_has_val(true) {} - constexpr expected_storage_base(no_init_t) : m_val(), m_has_val(false) {} - - constexpr expected_storage_base(in_place_t) : m_has_val(true) {} - - template <class... Args, - detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = - nullptr> - constexpr explicit expected_storage_base(unexpect_t, Args &&... args) - : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {} - - template <class U, class... Args, - detail::enable_if_t<std::is_constructible< - E, std::initializer_list<U> &, Args &&...>::value> * = nullptr> - constexpr explicit expected_storage_base(unexpect_t, - std::initializer_list<U> il, - Args &&... args) - : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {} - - ~expected_storage_base() = default; - struct dummy {}; - union { - dummy m_val; - unexpected<E> m_unexpect; - }; - bool m_has_val; -}; - -// `T` is `void`, `E` is not trivially-destructible -template <class E> struct expected_storage_base<void, E, false, false> { - constexpr expected_storage_base() : m_dummy(), m_has_val(true) {} - constexpr expected_storage_base(no_init_t) : m_dummy(), m_has_val(false) {} - - constexpr expected_storage_base(in_place_t) : m_dummy(), m_has_val(true) {} - - template <class... Args, - detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = - nullptr> - constexpr explicit expected_storage_base(unexpect_t, Args &&... args) - : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {} - - template <class U, class... Args, - detail::enable_if_t<std::is_constructible< - E, std::initializer_list<U> &, Args &&...>::value> * = nullptr> - constexpr explicit expected_storage_base(unexpect_t, - std::initializer_list<U> il, - Args &&... args) - : m_unexpect(il, std::forward<Args>(args)...), m_has_val(false) {} - - ~expected_storage_base() { - if (!m_has_val) { - m_unexpect.~unexpected<E>(); - } - } - - union { - char m_dummy; - unexpected<E> m_unexpect; - }; - bool m_has_val; -}; - -// This base class provides some handy member functions which can be used in -// further derived classes -template <class T, class E> -struct expected_operations_base : expected_storage_base<T, E> { - using expected_storage_base<T, E>::expected_storage_base; - - template <class... Args> void construct(Args &&... args) noexcept { - new (std::addressof(this->m_val)) T(std::forward<Args>(args)...); - this->m_has_val = true; - } - - template <class Rhs> void construct_with(Rhs &&rhs) noexcept { - new (std::addressof(this->m_val)) T(std::forward<Rhs>(rhs).get()); - this->m_has_val = true; - } - - template <class... Args> void construct_error(Args &&... args) noexcept { - new (std::addressof(this->m_unexpect)) - unexpected<E>(std::forward<Args>(args)...); - this->m_has_val = false; - } - - #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED - - // These assign overloads ensure that the most efficient assignment - // implementation is used while maintaining the strong exception guarantee. - // The problematic case is where rhs has a value, but *this does not. - // - // This overload handles the case where we can just copy-construct `T` - // directly into place without throwing. - template <class U = T, - detail::enable_if_t<std::is_nothrow_copy_constructible<U>::value> - * = nullptr> - void assign(const expected_operations_base &rhs) noexcept { - if (!this->m_has_val && rhs.m_has_val) { - geterr().~unexpected<E>(); - construct(rhs.get()); - } else { - assign_common(rhs); - } - } - - // This overload handles the case where we can attempt to create a copy of - // `T`, then no-throw move it into place if the copy was successful. - template <class U = T, - detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value && - std::is_nothrow_move_constructible<U>::value> - * = nullptr> - void assign(const expected_operations_base &rhs) noexcept { - if (!this->m_has_val && rhs.m_has_val) { - T tmp = rhs.get(); - geterr().~unexpected<E>(); - construct(std::move(tmp)); - } else { - assign_common(rhs); - } - } - - // This overload is the worst-case, where we have to move-construct the - // unexpected value into temporary storage, then try to copy the T into place. - // If the construction succeeds, then everything is fine, but if it throws, - // then we move the old unexpected value back into place before rethrowing the - // exception. - template <class U = T, - detail::enable_if_t<!std::is_nothrow_copy_constructible<U>::value && - !std::is_nothrow_move_constructible<U>::value> - * = nullptr> - void assign(const expected_operations_base &rhs) { - if (!this->m_has_val && rhs.m_has_val) { - auto tmp = std::move(geterr()); - geterr().~unexpected<E>(); - - try { - construct(rhs.get()); - } catch (...) { - geterr() = std::move(tmp); - throw; - } - } else { - assign_common(rhs); - } - } - - // These overloads do the same as above, but for rvalues - template <class U = T, - detail::enable_if_t<std::is_nothrow_move_constructible<U>::value> - * = nullptr> - void assign(expected_operations_base &&rhs) noexcept { - if (!this->m_has_val && rhs.m_has_val) { - geterr().~unexpected<E>(); - construct(std::move(rhs).get()); - } else { - assign_common(std::move(rhs)); - } - } - - template <class U = T, - detail::enable_if_t<!std::is_nothrow_move_constructible<U>::value> - * = nullptr> - void assign(expected_operations_base &&rhs) { - if (!this->m_has_val && rhs.m_has_val) { - auto tmp = std::move(geterr()); - geterr().~unexpected<E>(); - try { - construct(std::move(rhs).get()); - } catch (...) { - geterr() = std::move(tmp); - throw; - } - } else { - assign_common(std::move(rhs)); - } - } - - #else - - // If exceptions are disabled then we can just copy-construct - void assign(const expected_operations_base &rhs) noexcept { - if (!this->m_has_val && rhs.m_has_val) { - geterr().~unexpected<E>(); - construct(rhs.get()); - } else { - assign_common(rhs); - } - } - - void assign(expected_operations_base &&rhs) noexcept { - if (!this->m_has_val && rhs.m_has_val) { - geterr().~unexpected<E>(); - construct(std::move(rhs).get()); - } else { - assign_common(rhs); - } - } - - #endif - - // The common part of move/copy assigning - template <class Rhs> void assign_common(Rhs &&rhs) { - if (this->m_has_val) { - if (rhs.m_has_val) { - get() = std::forward<Rhs>(rhs).get(); - } else { - destroy_val(); - construct_error(std::forward<Rhs>(rhs).geterr()); - } - } else { - if (!rhs.m_has_val) { - geterr() = std::forward<Rhs>(rhs).geterr(); - } - } - } - - bool has_value() const { return this->m_has_val; } - - TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; } - constexpr const T &get() const & { return this->m_val; } - TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); } -#ifndef TL_EXPECTED_NO_CONSTRR - constexpr const T &&get() const && { return std::move(this->m_val); } -#endif - - TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & { - return this->m_unexpect; - } - constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; } - TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && { - return std::move(this->m_unexpect); - } -#ifndef TL_EXPECTED_NO_CONSTRR - constexpr const unexpected<E> &&geterr() const && { - return std::move(this->m_unexpect); - } -#endif - - constexpr void destroy_val() { - get().~T(); - } -}; - -// This base class provides some handy member functions which can be used in -// further derived classes -template <class E> -struct expected_operations_base<void, E> : expected_storage_base<void, E> { - using expected_storage_base<void, E>::expected_storage_base; - - template <class... Args> void construct() noexcept { this->m_has_val = true; } - - // This function doesn't use its argument, but needs it so that code in - // levels above this can work independently of whether T is void - template <class Rhs> void construct_with(Rhs &&) noexcept { - this->m_has_val = true; - } - - template <class... Args> void construct_error(Args &&... args) noexcept { - new (std::addressof(this->m_unexpect)) - unexpected<E>(std::forward<Args>(args)...); - this->m_has_val = false; - } - - template <class Rhs> void assign(Rhs &&rhs) noexcept { - if (!this->m_has_val) { - if (rhs.m_has_val) { - geterr().~unexpected<E>(); - construct(); - } else { - geterr() = std::forward<Rhs>(rhs).geterr(); - } - } else { - if (!rhs.m_has_val) { - construct_error(std::forward<Rhs>(rhs).geterr()); - } - } - } - - bool has_value() const { return this->m_has_val; } - - TL_EXPECTED_11_CONSTEXPR unexpected<E> &geterr() & { - return this->m_unexpect; - } - constexpr const unexpected<E> &geterr() const & { return this->m_unexpect; } - TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && { - return std::move(this->m_unexpect); - } -#ifndef TL_EXPECTED_NO_CONSTRR - constexpr const unexpected<E> &&geterr() const && { - return std::move(this->m_unexpect); - } -#endif - - constexpr void destroy_val() { - //no-op - } -}; - -// This class manages conditionally having a trivial copy constructor -// This specialization is for when T and E are trivially copy constructible -template <class T, class E, - bool = is_void_or<T, TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T)>:: - value &&TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value> -struct expected_copy_base : expected_operations_base<T, E> { - using expected_operations_base<T, E>::expected_operations_base; -}; - -// This specialization is for when T or E are not trivially copy constructible -template <class T, class E> -struct expected_copy_base<T, E, false> : expected_operations_base<T, E> { - using expected_operations_base<T, E>::expected_operations_base; - - expected_copy_base() = default; - expected_copy_base(const expected_copy_base &rhs) - : expected_operations_base<T, E>(no_init) { - if (rhs.has_value()) { - this->construct_with(rhs); - } else { - this->construct_error(rhs.geterr()); - } - } - - expected_copy_base(expected_copy_base &&rhs) = default; - expected_copy_base &operator=(const expected_copy_base &rhs) = default; - expected_copy_base &operator=(expected_copy_base &&rhs) = default; -}; - -// This class manages conditionally having a trivial move constructor -// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it -// doesn't implement an analogue to std::is_trivially_move_constructible. We -// have to make do with a non-trivial move constructor even if T is trivially -// move constructible -#ifndef TL_EXPECTED_GCC49 -template <class T, class E, - bool = is_void_or<T, std::is_trivially_move_constructible<T>>::value - &&std::is_trivially_move_constructible<E>::value> -struct expected_move_base : expected_copy_base<T, E> { - using expected_copy_base<T, E>::expected_copy_base; -}; -#else -template <class T, class E, bool = false> struct expected_move_base; -#endif -template <class T, class E> -struct expected_move_base<T, E, false> : expected_copy_base<T, E> { - using expected_copy_base<T, E>::expected_copy_base; - - expected_move_base() = default; - expected_move_base(const expected_move_base &rhs) = default; - - expected_move_base(expected_move_base &&rhs) noexcept( - std::is_nothrow_move_constructible<T>::value) - : expected_copy_base<T, E>(no_init) { - if (rhs.has_value()) { - this->construct_with(std::move(rhs)); - } else { - this->construct_error(std::move(rhs.geterr())); - } - } - expected_move_base &operator=(const expected_move_base &rhs) = default; - expected_move_base &operator=(expected_move_base &&rhs) = default; -}; - -// This class manages conditionally having a trivial copy assignment operator -template <class T, class E, - bool = is_void_or< - T, conjunction<TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(T), - TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T), - TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(T)>>::value - &&TL_EXPECTED_IS_TRIVIALLY_COPY_ASSIGNABLE(E)::value - &&TL_EXPECTED_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(E)::value - &&TL_EXPECTED_IS_TRIVIALLY_DESTRUCTIBLE(E)::value> -struct expected_copy_assign_base : expected_move_base<T, E> { - using expected_move_base<T, E>::expected_move_base; -}; - -template <class T, class E> -struct expected_copy_assign_base<T, E, false> : expected_move_base<T, E> { - using expected_move_base<T, E>::expected_move_base; - - expected_copy_assign_base() = default; - expected_copy_assign_base(const expected_copy_assign_base &rhs) = default; - - expected_copy_assign_base(expected_copy_assign_base &&rhs) = default; - expected_copy_assign_base &operator=(const expected_copy_assign_base &rhs) { - this->assign(rhs); - return *this; - } - expected_copy_assign_base & - operator=(expected_copy_assign_base &&rhs) = default; -}; - -// This class manages conditionally having a trivial move assignment operator -// Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it -// doesn't implement an analogue to std::is_trivially_move_assignable. We have -// to make do with a non-trivial move assignment operator even if T is trivially -// move assignable -#ifndef TL_EXPECTED_GCC49 -template <class T, class E, - bool = - is_void_or<T, conjunction<std::is_trivially_destructible<T>, - std::is_trivially_move_constructible<T>, - std::is_trivially_move_assignable<T>>>:: - value &&std::is_trivially_destructible<E>::value - &&std::is_trivially_move_constructible<E>::value - &&std::is_trivially_move_assignable<E>::value> -struct expected_move_assign_base : expected_copy_assign_base<T, E> { - using expected_copy_assign_base<T, E>::expected_copy_assign_base; -}; -#else -template <class T, class E, bool = false> struct expected_move_assign_base; -#endif - -template <class T, class E> -struct expected_move_assign_base<T, E, false> - : expected_copy_assign_base<T, E> { - using expected_copy_assign_base<T, E>::expected_copy_assign_base; - - expected_move_assign_base() = default; - expected_move_assign_base(const expected_move_assign_base &rhs) = default; - - expected_move_assign_base(expected_move_assign_base &&rhs) = default; - - expected_move_assign_base & - operator=(const expected_move_assign_base &rhs) = default; - - expected_move_assign_base & - operator=(expected_move_assign_base &&rhs) noexcept( - std::is_nothrow_move_constructible<T>::value - &&std::is_nothrow_move_assignable<T>::value) { - this->assign(std::move(rhs)); - return *this; - } -}; - -// expected_delete_ctor_base will conditionally delete copy and move -// constructors depending on whether T is copy/move constructible -template <class T, class E, - bool EnableCopy = (is_copy_constructible_or_void<T>::value && - std::is_copy_constructible<E>::value), - bool EnableMove = (is_move_constructible_or_void<T>::value && - std::is_move_constructible<E>::value)> -struct expected_delete_ctor_base { - expected_delete_ctor_base() = default; - expected_delete_ctor_base(const expected_delete_ctor_base &) = default; - expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default; - expected_delete_ctor_base & - operator=(const expected_delete_ctor_base &) = default; - expected_delete_ctor_base & - operator=(expected_delete_ctor_base &&) noexcept = default; -}; - -template <class T, class E> -struct expected_delete_ctor_base<T, E, true, false> { - expected_delete_ctor_base() = default; - expected_delete_ctor_base(const expected_delete_ctor_base &) = default; - expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete; - expected_delete_ctor_base & - operator=(const expected_delete_ctor_base &) = default; - expected_delete_ctor_base & - operator=(expected_delete_ctor_base &&) noexcept = default; -}; - -template <class T, class E> -struct expected_delete_ctor_base<T, E, false, true> { - expected_delete_ctor_base() = default; - expected_delete_ctor_base(const expected_delete_ctor_base &) = delete; - expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = default; - expected_delete_ctor_base & - operator=(const expected_delete_ctor_base &) = default; - expected_delete_ctor_base & - operator=(expected_delete_ctor_base &&) noexcept = default; -}; - -template <class T, class E> -struct expected_delete_ctor_base<T, E, false, false> { - expected_delete_ctor_base() = default; - expected_delete_ctor_base(const expected_delete_ctor_base &) = delete; - expected_delete_ctor_base(expected_delete_ctor_base &&) noexcept = delete; - expected_delete_ctor_base & - operator=(const expected_delete_ctor_base &) = default; - expected_delete_ctor_base & - operator=(expected_delete_ctor_base &&) noexcept = default; -}; - -// expected_delete_assign_base will conditionally delete copy and move -// constructors depending on whether T and E are copy/move constructible + -// assignable -template <class T, class E, - bool EnableCopy = (is_copy_constructible_or_void<T>::value && - std::is_copy_constructible<E>::value && - is_copy_assignable_or_void<T>::value && - std::is_copy_assignable<E>::value), - bool EnableMove = (is_move_constructible_or_void<T>::value && - std::is_move_constructible<E>::value && - is_move_assignable_or_void<T>::value && - std::is_move_assignable<E>::value)> -struct expected_delete_assign_base { - expected_delete_assign_base() = default; - expected_delete_assign_base(const expected_delete_assign_base &) = default; - expected_delete_assign_base(expected_delete_assign_base &&) noexcept = - default; - expected_delete_assign_base & - operator=(const expected_delete_assign_base &) = default; - expected_delete_assign_base & - operator=(expected_delete_assign_base &&) noexcept = default; -}; - -template <class T, class E> -struct expected_delete_assign_base<T, E, true, false> { - expected_delete_assign_base() = default; - expected_delete_assign_base(const expected_delete_assign_base &) = default; - expected_delete_assign_base(expected_delete_assign_base &&) noexcept = - default; - expected_delete_assign_base & - operator=(const expected_delete_assign_base &) = default; - expected_delete_assign_base & - operator=(expected_delete_assign_base &&) noexcept = delete; -}; - -template <class T, class E> -struct expected_delete_assign_base<T, E, false, true> { - expected_delete_assign_base() = default; - expected_delete_assign_base(const expected_delete_assign_base &) = default; - expected_delete_assign_base(expected_delete_assign_base &&) noexcept = - default; - expected_delete_assign_base & - operator=(const expected_delete_assign_base &) = delete; - expected_delete_assign_base & - operator=(expected_delete_assign_base &&) noexcept = default; -}; - -template <class T, class E> -struct expected_delete_assign_base<T, E, false, false> { - expected_delete_assign_base() = default; - expected_delete_assign_base(const expected_delete_assign_base &) = default; - expected_delete_assign_base(expected_delete_assign_base &&) noexcept = - default; - expected_delete_assign_base & - operator=(const expected_delete_assign_base &) = delete; - expected_delete_assign_base & - operator=(expected_delete_assign_base &&) noexcept = delete; -}; - -// This is needed to be able to construct the expected_default_ctor_base which -// follows, while still conditionally deleting the default constructor. -struct default_constructor_tag { - explicit constexpr default_constructor_tag() = default; -}; - -// expected_default_ctor_base will ensure that expected has a deleted default -// consturctor if T is not default constructible. -// This specialization is for when T is default constructible -template <class T, class E, - bool Enable = - std::is_default_constructible<T>::value || std::is_void<T>::value> -struct expected_default_ctor_base { - constexpr expected_default_ctor_base() noexcept = default; - constexpr expected_default_ctor_base( - expected_default_ctor_base const &) noexcept = default; - constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept = - default; - expected_default_ctor_base & - operator=(expected_default_ctor_base const &) noexcept = default; - expected_default_ctor_base & - operator=(expected_default_ctor_base &&) noexcept = default; - - constexpr explicit expected_default_ctor_base(default_constructor_tag) {} -}; - -// This specialization is for when T is not default constructible -template <class T, class E> struct expected_default_ctor_base<T, E, false> { - constexpr expected_default_ctor_base() noexcept = delete; - constexpr expected_default_ctor_base( - expected_default_ctor_base const &) noexcept = default; - constexpr expected_default_ctor_base(expected_default_ctor_base &&) noexcept = - default; - expected_default_ctor_base & - operator=(expected_default_ctor_base const &) noexcept = default; - expected_default_ctor_base & - operator=(expected_default_ctor_base &&) noexcept = default; - - constexpr explicit expected_default_ctor_base(default_constructor_tag) {} -}; -} // namespace detail - -template <class E> class bad_expected_access : public std::exception { -public: - explicit bad_expected_access(E e) : m_val(std::move(e)) {} - - virtual const char *what() const noexcept override { - return "Bad expected access"; - } - - const E &error() const & { return m_val; } - E &error() & { return m_val; } - const E &&error() const && { return std::move(m_val); } - E &&error() && { return std::move(m_val); } - -private: - E m_val; -}; - -/// An `expected<T, E>` object is an object that contains the storage for -/// another object and manages the lifetime of this contained object `T`. -/// Alternatively it could contain the storage for another unexpected object -/// `E`. The contained object may not be initialized after the expected object -/// has been initialized, and may not be destroyed before the expected object -/// has been destroyed. The initialization state of the contained object is -/// tracked by the expected object. -template <class T, class E> -class expected : private detail::expected_move_assign_base<T, E>, - private detail::expected_delete_ctor_base<T, E>, - private detail::expected_delete_assign_base<T, E>, - private detail::expected_default_ctor_base<T, E> { - static_assert(!std::is_reference<T>::value, "T must not be a reference"); - static_assert(!std::is_same<T, std::remove_cv<in_place_t>>::value, - "T must not be in_place_t"); - static_assert(!std::is_same<T, std::remove_cv<unexpect_t>>::value, - "T must not be unexpect_t"); - static_assert(!std::is_same<T, std::remove_cv<unexpected<E>>>::value, - "T must not be unexpected<E>"); - static_assert(!std::is_reference<E>::value, "E must not be a reference"); - - T *valptr() { return std::addressof(this->m_val); } - const T *valptr() const { return std::addressof(this->m_val); } - unexpected<E> *errptr() { return std::addressof(this->m_unexpect); } - const unexpected<E> *errptr() const { return std::addressof(this->m_unexpect); } - - template <class U = T, - detail::enable_if_t<!std::is_void<U>::value> * = nullptr> - U &val() { - return this->m_val; - } - unexpected<E> &err() { return this->m_unexpect; } - - template <class U = T, - detail::enable_if_t<!std::is_void<U>::value> * = nullptr> - const U &val() const { - return this->m_val; - } - const unexpected<E> &err() const { return this->m_unexpect; } - - using impl_base = detail::expected_move_assign_base<T, E>; - using ctor_base = detail::expected_default_ctor_base<T, E>; - -public: - typedef T value_type; - typedef E error_type; - typedef unexpected<E> unexpected_type; - -#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ - !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) - /// \group and_then - /// Carries out some operation which returns an expected on the stored object - /// if there is one. \requires `std::invoke(std::forward<F>(f), value())` - /// returns an `expected<U>` for some `U`. \returns Let `U` be the result - /// of `std::invoke(std::forward<F>(f), value())`. Returns an - /// `expected<U>`. The return value is empty if `*this` is empty, - /// otherwise the return value of `std::invoke(std::forward<F>(f), value())` - /// is returned. - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &; - template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) & { - return and_then_impl(*this, std::forward<F>(f)); - } - - /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&; - template <class F> TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && { - return and_then_impl(std::move(*this), std::forward<F>(f)); - } - - /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &; - template <class F> constexpr auto and_then(F &&f) const & { - return and_then_impl(*this, std::forward<F>(f)); - } - -#ifndef TL_EXPECTED_NO_CONSTRR - /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&; - template <class F> constexpr auto and_then(F &&f) const && { - return and_then_impl(std::move(*this), std::forward<F>(f)); - } -#endif - -#else - /// \group and_then - /// Carries out some operation which returns an expected on the stored object - /// if there is one. \requires `std::invoke(std::forward<F>(f), value())` - /// returns an `expected<U>` for some `U`. \returns Let `U` be the result - /// of `std::invoke(std::forward<F>(f), value())`. Returns an - /// `expected<U>`. The return value is empty if `*this` is empty, - /// otherwise the return value of `std::invoke(std::forward<F>(f), value())` - /// is returned. - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &; - template <class F> - TL_EXPECTED_11_CONSTEXPR auto - and_then(F &&f) & -> decltype(and_then_impl(*this, std::forward<F>(f))) { - return and_then_impl(*this, std::forward<F>(f)); - } - - /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) &&; - template <class F> - TL_EXPECTED_11_CONSTEXPR auto and_then(F &&f) && -> decltype( - and_then_impl(std::move(*this), std::forward<F>(f))) { - return and_then_impl(std::move(*this), std::forward<F>(f)); - } - - /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &; - template <class F> - constexpr auto and_then(F &&f) const & -> decltype( - and_then_impl(*this, std::forward<F>(f))) { - return and_then_impl(*this, std::forward<F>(f)); - } - -#ifndef TL_EXPECTED_NO_CONSTRR - /// \group and_then - /// \synopsis template <class F>\nconstexpr auto and_then(F &&f) const &&; - template <class F> - constexpr auto and_then(F &&f) const && -> decltype( - and_then_impl(std::move(*this), std::forward<F>(f))) { - return and_then_impl(std::move(*this), std::forward<F>(f)); - } -#endif -#endif - -#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ - !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) - /// \brief Carries out some operation on the stored object if there is one. - /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f), - /// value())`. If `U` is `void`, returns an `expected<monostate,E>, otherwise - // returns an `expected<U,E>`. If `*this` is unexpected, the - /// result is `*this`, otherwise an `expected<U,E>` is constructed from the - /// return value of `std::invoke(std::forward<F>(f), value())` and is - /// returned. - /// - /// \group map - /// \synopsis template <class F> constexpr auto map(F &&f) &; - template <class F> TL_EXPECTED_11_CONSTEXPR auto map(F &&f) & { - return expected_map_impl(*this, std::forward<F>(f)); - } - - /// \group map - /// \synopsis template <class F> constexpr auto map(F &&f) &&; - template <class F> TL_EXPECTED_11_CONSTEXPR auto map(F &&f) && { - return expected_map_impl(std::move(*this), std::forward<F>(f)); - } - - /// \group map - /// \synopsis template <class F> constexpr auto map(F &&f) const &; - template <class F> constexpr auto map(F &&f) const & { - return expected_map_impl(*this, std::forward<F>(f)); - } - - /// \group map - /// \synopsis template <class F> constexpr auto map(F &&f) const &&; - template <class F> constexpr auto map(F &&f) const && { - return expected_map_impl(std::move(*this), std::forward<F>(f)); - } -#else - /// \brief Carries out some operation on the stored object if there is one. - /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f), - /// value())`. If `U` is `void`, returns an `expected<monostate,E>, otherwise - // returns an `expected<U,E>`. If `*this` is unexpected, the - /// result is `*this`, otherwise an `expected<U,E>` is constructed from the - /// return value of `std::invoke(std::forward<F>(f), value())` and is - /// returned. - /// - /// \group map - /// \synopsis template <class F> constexpr auto map(F &&f) &; - template <class F> - TL_EXPECTED_11_CONSTEXPR decltype( - expected_map_impl(std::declval<expected &>(), std::declval<F &&>())) - map(F &&f) & { - return expected_map_impl(*this, std::forward<F>(f)); - } - - /// \group map - /// \synopsis template <class F> constexpr auto map(F &&f) &&; - template <class F> - TL_EXPECTED_11_CONSTEXPR decltype( - expected_map_impl(std::declval<expected>(), std::declval<F &&>())) - map(F &&f) && { - return expected_map_impl(std::move(*this), std::forward<F>(f)); - } - - /// \group map - /// \synopsis template <class F> constexpr auto map(F &&f) const &; - template <class F> - constexpr decltype(expected_map_impl(std::declval<const expected &>(), - std::declval<F &&>())) - map(F &&f) const & { - return expected_map_impl(*this, std::forward<F>(f)); - } - -#ifndef TL_EXPECTED_NO_CONSTRR - /// \group map - /// \synopsis template <class F> constexpr auto map(F &&f) const &&; - template <class F> - constexpr decltype(expected_map_impl(std::declval<const expected &&>(), - std::declval<F &&>())) - map(F &&f) const && { - return expected_map_impl(std::move(*this), std::forward<F>(f)); - } -#endif -#endif - -#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ - !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) - /// \brief Carries out some operation on the stored unexpected object if there - /// is one. - /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f), - /// value())`. If `U` is `void`, returns an `expected<T,monostate>`, otherwise - /// returns an `expected<T,U>`. If `*this` has an expected - /// value, the result is `*this`, otherwise an `expected<T,U>` is constructed - /// from `make_unexpected(std::invoke(std::forward<F>(f), value()))` and is - /// returned. - /// - /// \group map_error - /// \synopsis template <class F> constexpr auto map_error(F &&f) &; - template <class F> TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) & { - return map_error_impl(*this, std::forward<F>(f)); - } - - /// \group map_error - /// \synopsis template <class F> constexpr auto map_error(F &&f) &&; - template <class F> TL_EXPECTED_11_CONSTEXPR auto map_error(F &&f) && { - return map_error_impl(std::move(*this), std::forward<F>(f)); - } - - /// \group map_error - /// \synopsis template <class F> constexpr auto map_error(F &&f) const &; - template <class F> constexpr auto map_error(F &&f) const & { - return map_error_impl(*this, std::forward<F>(f)); - } - - /// \group map_error - /// \synopsis template <class F> constexpr auto map_error(F &&f) const &&; - template <class F> constexpr auto map_error(F &&f) const && { - return map_error_impl(std::move(*this), std::forward<F>(f)); - } -#else - /// \brief Carries out some operation on the stored unexpected object if there - /// is one. - /// \returns Let `U` be the result of `std::invoke(std::forward<F>(f), - /// value())`. Returns an `expected<T,U>`. If `*this` has an expected - /// value, the result is `*this`, otherwise an `expected<T,U>` is constructed - /// from `make_unexpected(std::invoke(std::forward<F>(f), value()))` and is - /// returned. - /// - /// \group map_error - /// \synopsis template <class F> constexpr auto map_error(F &&f) &; - template <class F> - TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &>(), - std::declval<F &&>())) - map_error(F &&f) & { - return map_error_impl(*this, std::forward<F>(f)); - } - - /// \group map_error - /// \synopsis template <class F> constexpr auto map_error(F &&f) &&; - template <class F> - TL_EXPECTED_11_CONSTEXPR decltype(map_error_impl(std::declval<expected &&>(), - std::declval<F &&>())) - map_error(F &&f) && { - return map_error_impl(std::move(*this), std::forward<F>(f)); - } - - /// \group map_error - /// \synopsis template <class F> constexpr auto map_error(F &&f) const &; - template <class F> - constexpr decltype(map_error_impl(std::declval<const expected &>(), - std::declval<F &&>())) - map_error(F &&f) const & { - return map_error_impl(*this, std::forward<F>(f)); - } - -#ifndef TL_EXPECTED_NO_CONSTRR - /// \group map_error - /// \synopsis template <class F> constexpr auto map_error(F &&f) const &&; - template <class F> - constexpr decltype(map_error_impl(std::declval<const expected &&>(), - std::declval<F &&>())) - map_error(F &&f) const && { - return map_error_impl(std::move(*this), std::forward<F>(f)); - } -#endif -#endif - - /// \brief Calls `f` if the expectd is in the unexpected state - /// \requires `F` is invokable with `E`, and `std::invoke_result_t<F>` - /// must be void or convertible to `expcted<T,E>`. - /// \effects If `*this` has a value, returns `*this`. - /// Otherwise, if `f` returns `void`, calls `std::forward<F>(f)(E)` and returns - /// `std::nullopt`. Otherwise, returns `std::forward<F>(f)(E)`. - /// - /// \group or_else - template <class F> expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) & { - return or_else_impl(*this, std::forward<F>(f)); - } - - template <class F> expected TL_EXPECTED_11_CONSTEXPR or_else(F &&f) && { - return or_else_impl(std::move(*this), std::forward<F>(f)); - } - - template <class F> expected constexpr or_else(F &&f) const & { - return or_else_impl(*this, std::forward<F>(f)); - } - -#ifndef TL_EXPECTED_NO_CONSTRR - template <class F> expected constexpr or_else(F &&f) const && { - return or_else_impl(std::move(*this), std::forward<F>(f)); - } -#endif - constexpr expected() = default; - constexpr expected(const expected &rhs) = default; - constexpr expected(expected &&rhs) = default; - expected &operator=(const expected &rhs) = default; - expected &operator=(expected &&rhs) = default; - - template <class... Args, - detail::enable_if_t<std::is_constructible<T, Args &&...>::value> * = - nullptr> - constexpr expected(in_place_t, Args &&... args) - : impl_base(in_place, std::forward<Args>(args)...), - ctor_base(detail::default_constructor_tag{}) {} - - template <class U, class... Args, - detail::enable_if_t<std::is_constructible< - T, std::initializer_list<U> &, Args &&...>::value> * = nullptr> - constexpr expected(in_place_t, std::initializer_list<U> il, Args &&... args) - : impl_base(in_place, il, std::forward<Args>(args)...), - ctor_base(detail::default_constructor_tag{}) {} - - /// \group unexpected_ctor - /// \synopsis EXPLICIT constexpr expected(const unexpected<G> &e); - template <class G = E, - detail::enable_if_t<std::is_constructible<E, const G &>::value> * = - nullptr, - detail::enable_if_t<!std::is_convertible<const G &, E>::value> * = - nullptr> - explicit constexpr expected(const unexpected<G> &e) - : impl_base(unexpect, e.value()), - ctor_base(detail::default_constructor_tag{}) {} - - /// \exclude - template < - class G = E, - detail::enable_if_t<std::is_constructible<E, const G &>::value> * = - nullptr, - detail::enable_if_t<std::is_convertible<const G &, E>::value> * = nullptr> - constexpr expected(unexpected<G> const &e) - : impl_base(unexpect, e.value()), - ctor_base(detail::default_constructor_tag{}) {} - - /// \group unexpected_ctor - /// \synopsis EXPLICIT constexpr expected(unexpected<G> &&e); - template < - class G = E, - detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr, - detail::enable_if_t<!std::is_convertible<G &&, E>::value> * = nullptr> - explicit constexpr expected(unexpected<G> &&e) noexcept( - std::is_nothrow_constructible<E, G &&>::value) - : impl_base(unexpect, std::move(e.value())), - ctor_base(detail::default_constructor_tag{}) {} - - /// \exclude - template < - class G = E, - detail::enable_if_t<std::is_constructible<E, G &&>::value> * = nullptr, - detail::enable_if_t<std::is_convertible<G &&, E>::value> * = nullptr> - constexpr expected(unexpected<G> &&e) noexcept( - std::is_nothrow_constructible<E, G &&>::value) - : impl_base(unexpect, std::move(e.value())), - ctor_base(detail::default_constructor_tag{}) {} - - template <class... Args, - detail::enable_if_t<std::is_constructible<E, Args &&...>::value> * = - nullptr> - constexpr explicit expected(unexpect_t, Args &&... args) - : impl_base(unexpect, std::forward<Args>(args)...), - ctor_base(detail::default_constructor_tag{}) {} - - /// \exclude - template <class U, class... Args, - detail::enable_if_t<std::is_constructible< - E, std::initializer_list<U> &, Args &&...>::value> * = nullptr> - constexpr explicit expected(unexpect_t, std::initializer_list<U> il, - Args &&... args) - : impl_base(unexpect, il, std::forward<Args>(args)...), - ctor_base(detail::default_constructor_tag{}) {} - - template <class U, class G, - detail::enable_if_t<!(std::is_convertible<U const &, T>::value && - std::is_convertible<G const &, E>::value)> * = - nullptr, - detail::expected_enable_from_other<T, E, U, G, const U &, const G &> - * = nullptr> - explicit TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs) - : ctor_base(detail::default_constructor_tag{}) { - if (rhs.has_value()) { - this->construct(*rhs); - } else { - this->construct_error(rhs.error()); - } - } - - /// \exclude - template <class U, class G, - detail::enable_if_t<(std::is_convertible<U const &, T>::value && - std::is_convertible<G const &, E>::value)> * = - nullptr, - detail::expected_enable_from_other<T, E, U, G, const U &, const G &> - * = nullptr> - TL_EXPECTED_11_CONSTEXPR expected(const expected<U, G> &rhs) - : ctor_base(detail::default_constructor_tag{}) { - if (rhs.has_value()) { - this->construct(*rhs); - } else { - this->construct_error(rhs.error()); - } - } - - template < - class U, class G, - detail::enable_if_t<!(std::is_convertible<U &&, T>::value && - std::is_convertible<G &&, E>::value)> * = nullptr, - detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr> - explicit TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs) - : ctor_base(detail::default_constructor_tag{}) { - if (rhs.has_value()) { - this->construct(std::move(*rhs)); - } else { - this->construct_error(std::move(rhs.error())); - } - } - - /// \exclude - template < - class U, class G, - detail::enable_if_t<(std::is_convertible<U &&, T>::value && - std::is_convertible<G &&, E>::value)> * = nullptr, - detail::expected_enable_from_other<T, E, U, G, U &&, G &&> * = nullptr> - TL_EXPECTED_11_CONSTEXPR expected(expected<U, G> &&rhs) - : ctor_base(detail::default_constructor_tag{}) { - if (rhs.has_value()) { - this->construct(std::move(*rhs)); - } else { - this->construct_error(std::move(rhs.error())); - } - } - - template < - class U = T, - detail::enable_if_t<!std::is_convertible<U &&, T>::value> * = nullptr, - detail::expected_enable_forward_value<T, E, U> * = nullptr> - explicit TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v) - : expected(in_place, std::forward<U>(v)) {} - - /// \exclude - template < - class U = T, - detail::enable_if_t<std::is_convertible<U &&, T>::value> * = nullptr, - detail::expected_enable_forward_value<T, E, U> * = nullptr> - TL_EXPECTED_MSVC2015_CONSTEXPR expected(U &&v) - : expected(in_place, std::forward<U>(v)) {} - - template < - class U = T, class G = T, - detail::enable_if_t<std::is_nothrow_constructible<T, U &&>::value> * = - nullptr, - detail::enable_if_t<!std::is_void<G>::value> * = nullptr, - detail::enable_if_t< - (!std::is_same<expected<T, E>, detail::decay_t<U>>::value && - !detail::conjunction<std::is_scalar<T>, - std::is_same<T, detail::decay_t<U>>>::value && - std::is_constructible<T, U>::value && - std::is_assignable<G &, U>::value && - std::is_nothrow_move_constructible<E>::value)> * = nullptr> - expected &operator=(U &&v) { - if (has_value()) { - val() = std::forward<U>(v); - } else { - err().~unexpected<E>(); - ::new (valptr()) T(std::forward<U>(v)); - this->m_has_val = true; - } - - return *this; - } - - /// \exclude - template < - class U = T, class G = T, - detail::enable_if_t<!std::is_nothrow_constructible<T, U &&>::value> * = - nullptr, - detail::enable_if_t<!std::is_void<U>::value> * = nullptr, - detail::enable_if_t< - (!std::is_same<expected<T, E>, detail::decay_t<U>>::value && - !detail::conjunction<std::is_scalar<T>, - std::is_same<T, detail::decay_t<U>>>::value && - std::is_constructible<T, U>::value && - std::is_assignable<G &, U>::value && - std::is_nothrow_move_constructible<E>::value)> * = nullptr> - expected &operator=(U &&v) { - if (has_value()) { - val() = std::forward<U>(v); - } else { - auto tmp = std::move(err()); - err().~unexpected<E>(); - - #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED - try { - ::new (valptr()) T(std::move(v)); - this->m_has_val = true; - } catch (...) { - err() = std::move(tmp); - throw; - } - #else - ::new (valptr()) T(std::move(v)); - this->m_has_val = true; - #endif - } - - return *this; - } - - template <class G = E, - detail::enable_if_t<std::is_nothrow_copy_constructible<G>::value && - std::is_assignable<G &, G>::value> * = nullptr> - expected &operator=(const unexpected<G> &rhs) { - if (!has_value()) { - err() = rhs; - } else { - this->destroy_val(); - ::new (errptr()) unexpected<E>(rhs); - this->m_has_val = false; - } - - return *this; - } - - template <class G = E, - detail::enable_if_t<std::is_nothrow_move_constructible<G>::value && - std::is_move_assignable<G>::value> * = nullptr> - expected &operator=(unexpected<G> &&rhs) noexcept { - if (!has_value()) { - err() = std::move(rhs); - } else { - this->destroy_val(); - ::new (errptr()) unexpected<E>(std::move(rhs)); - this->m_has_val = false; - } - - return *this; - } - - template <class... Args, detail::enable_if_t<std::is_nothrow_constructible< - T, Args &&...>::value> * = nullptr> - void emplace(Args &&... args) { - if (has_value()) { - val() = T(std::forward<Args>(args)...); - } else { - err().~unexpected<E>(); - ::new (valptr()) T(std::forward<Args>(args)...); - this->m_has_val = true; - } - } - - /// \exclude - template <class... Args, detail::enable_if_t<!std::is_nothrow_constructible< - T, Args &&...>::value> * = nullptr> - void emplace(Args &&... args) { - if (has_value()) { - val() = T(std::forward<Args>(args)...); - } else { - auto tmp = std::move(err()); - err().~unexpected<E>(); - - #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED - try { - ::new (valptr()) T(std::forward<Args>(args)...); - this->m_has_val = true; - } catch (...) { - err() = std::move(tmp); - throw; - } - #else - ::new (valptr()) T(std::forward<Args>(args)...); - this->m_has_val = true; - #endif - } - } - - template <class U, class... Args, - detail::enable_if_t<std::is_nothrow_constructible< - T, std::initializer_list<U> &, Args &&...>::value> * = nullptr> - void emplace(std::initializer_list<U> il, Args &&... args) { - if (has_value()) { - T t(il, std::forward<Args>(args)...); - val() = std::move(t); - } else { - err().~unexpected<E>(); - ::new (valptr()) T(il, std::forward<Args>(args)...); - this->m_has_val = true; - } - } - - /// \exclude - template <class U, class... Args, - detail::enable_if_t<!std::is_nothrow_constructible< - T, std::initializer_list<U> &, Args &&...>::value> * = nullptr> - void emplace(std::initializer_list<U> il, Args &&... args) { - if (has_value()) { - T t(il, std::forward<Args>(args)...); - val() = std::move(t); - } else { - auto tmp = std::move(err()); - err().~unexpected<E>(); - - #ifdef TL_EXPECTED_EXCEPTIONS_ENABLED - try { - ::new (valptr()) T(il, std::forward<Args>(args)...); - this->m_has_val = true; - } catch (...) { - err() = std::move(tmp); - throw; - } - #else - ::new (valptr()) T(il, std::forward<Args>(args)...); - this->m_has_val = true; - #endif - } - } - - // TODO SFINAE - void swap(expected &rhs) noexcept( - std::is_nothrow_move_constructible<T>::value &&noexcept( - swap(std::declval<T &>(), std::declval<T &>())) && - std::is_nothrow_move_constructible<E>::value && - noexcept(swap(std::declval<E &>(), std::declval<E &>()))) { - if (has_value() && rhs.has_value()) { - using std::swap; - swap(val(), rhs.val()); - } else if (!has_value() && rhs.has_value()) { - using std::swap; - swap(err(), rhs.err()); - } else if (has_value()) { - auto temp = std::move(rhs.err()); - ::new (rhs.valptr()) T(val()); - ::new (errptr()) unexpected_type(std::move(temp)); - std::swap(this->m_has_val, rhs.m_has_val); - } else { - auto temp = std::move(this->err()); - ::new (valptr()) T(rhs.val()); - ::new (errptr()) unexpected_type(std::move(temp)); - std::swap(this->m_has_val, rhs.m_has_val); - } - } - - /// \returns a pointer to the stored value - /// \requires a value is stored - /// \group pointer - constexpr const T *operator->() const { return valptr(); } - /// \group pointer - TL_EXPECTED_11_CONSTEXPR T *operator->() { return valptr(); } - - /// \returns the stored value - /// \requires a value is stored - /// \group deref - template <class U = T, - detail::enable_if_t<!std::is_void<U>::value> * = nullptr> - constexpr const U &operator*() const & { - return val(); - } - /// \group deref - template <class U = T, - detail::enable_if_t<!std::is_void<U>::value> * = nullptr> - TL_EXPECTED_11_CONSTEXPR U &operator*() & { - return val(); - } - /// \group deref - template <class U = T, - detail::enable_if_t<!std::is_void<U>::value> * = nullptr> - constexpr const U &&operator*() const && { - return std::move(val()); - } - /// \group deref - template <class U = T, - detail::enable_if_t<!std::is_void<U>::value> * = nullptr> - TL_EXPECTED_11_CONSTEXPR U &&operator*() && { - return std::move(val()); - } - - /// \returns whether or not the optional has a value - /// \group has_value - constexpr bool has_value() const noexcept { return this->m_has_val; } - /// \group has_value - constexpr explicit operator bool() const noexcept { return this->m_has_val; } - - /// \returns the contained value if there is one, otherwise throws - /// [bad_expected_access] - /// - /// \group value - template <class U = T, - detail::enable_if_t<!std::is_void<U>::value> * = nullptr> - TL_EXPECTED_11_CONSTEXPR const U &value() const & { - if (!has_value()) - detail::throw_exception(bad_expected_access<E>(err().value())); - return val(); - } - /// \group value - template <class U = T, - detail::enable_if_t<!std::is_void<U>::value> * = nullptr> - TL_EXPECTED_11_CONSTEXPR U &value() & { - if (!has_value()) - detail::throw_exception(bad_expected_access<E>(err().value())); - return val(); - } - /// \group value - template <class U = T, - detail::enable_if_t<!std::is_void<U>::value> * = nullptr> - TL_EXPECTED_11_CONSTEXPR const U &&value() const && { - if (!has_value()) - detail::throw_exception(bad_expected_access<E>(err().value())); - return std::move(val()); - } - /// \group value - template <class U = T, - detail::enable_if_t<!std::is_void<U>::value> * = nullptr> - TL_EXPECTED_11_CONSTEXPR U &&value() && { - if (!has_value()) - detail::throw_exception(bad_expected_access<E>(err().value())); - return std::move(val()); - } - - /// \returns the unexpected value - /// \requires there is an unexpected value - /// \group error - constexpr const E &error() const & { return err().value(); } - /// \group error - TL_EXPECTED_11_CONSTEXPR E &error() & { return err().value(); } - /// \group error - constexpr const E &&error() const && { return std::move(err().value()); } - /// \group error - TL_EXPECTED_11_CONSTEXPR E &&error() && { return std::move(err().value()); } - - /// \returns the stored value if there is one, otherwise returns `u` - /// \group value_or - template <class U> constexpr T value_or(U &&v) const & { - static_assert(std::is_copy_constructible<T>::value && - std::is_convertible<U &&, T>::value, - "T must be copy-constructible and convertible to from U&&"); - return bool(*this) ? **this : static_cast<T>(std::forward<U>(v)); - } - /// \group value_or - template <class U> TL_EXPECTED_11_CONSTEXPR T value_or(U &&v) && { - static_assert(std::is_move_constructible<T>::value && - std::is_convertible<U &&, T>::value, - "T must be move-constructible and convertible to from U&&"); - return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v)); - } -}; - -/// \exclude -namespace detail { -template <class Exp> using exp_t = typename detail::decay_t<Exp>::value_type; -template <class Exp> using err_t = typename detail::decay_t<Exp>::error_type; -template <class Exp, class Ret> using ret_t = expected<Ret, err_t<Exp>>; - -#ifdef TL_EXPECTED_CXX14 -template <class Exp, class F, - detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, - class Ret = decltype(detail::invoke(std::declval<F>(), - *std::declval<Exp>()))> -constexpr auto and_then_impl(Exp &&exp, F &&f) { - static_assert(detail::is_expected<Ret>::value, "F must return an expected"); - - return exp.has_value() - ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp)) - : Ret(unexpect, exp.error()); -} - -template <class Exp, class F, - detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr, - class Ret = decltype(detail::invoke(std::declval<F>()))> -constexpr auto and_then_impl(Exp &&exp, F &&f) { - static_assert(detail::is_expected<Ret>::value, "F must return an expected"); - - return exp.has_value() ? detail::invoke(std::forward<F>(f)) - : Ret(unexpect, exp.error()); -} -#else -template <class> struct TC; -template <class Exp, class F, - class Ret = decltype(detail::invoke(std::declval<F>(), - *std::declval<Exp>())), - detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr> -auto and_then_impl(Exp &&exp, F &&f) -> Ret { - static_assert(detail::is_expected<Ret>::value, "F must return an expected"); - - return exp.has_value() - ? detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp)) - : Ret(unexpect, exp.error()); -} - -template <class Exp, class F, - class Ret = decltype(detail::invoke(std::declval<F>())), - detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr> -constexpr auto and_then_impl(Exp &&exp, F &&f) -> Ret { - static_assert(detail::is_expected<Ret>::value, "F must return an expected"); - - return exp.has_value() ? detail::invoke(std::forward<F>(f)) - : Ret(unexpect, exp.error()); -} -#endif - -#ifdef TL_EXPECTED_CXX14 -template <class Exp, class F, - detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, - class Ret = decltype(detail::invoke(std::declval<F>(), - *std::declval<Exp>())), - detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> -constexpr auto expected_map_impl(Exp &&exp, F &&f) { - using result = ret_t<Exp, detail::decay_t<Ret>>; - return exp.has_value() ? result(detail::invoke(std::forward<F>(f), - *std::forward<Exp>(exp))) - : result(unexpect, std::forward<Exp>(exp).error()); -} - -template <class Exp, class F, - detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, - class Ret = decltype(detail::invoke(std::declval<F>(), - *std::declval<Exp>())), - detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> -auto expected_map_impl(Exp &&exp, F &&f) { - using result = expected<void, err_t<Exp>>; - if (exp.has_value()) { - detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp)); - return result(); - } - - return result(unexpect, std::forward<Exp>(exp).error()); -} - -template <class Exp, class F, - detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr, - class Ret = decltype(detail::invoke(std::declval<F>())), - detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> -constexpr auto expected_map_impl(Exp &&exp, F &&f) { - using result = ret_t<Exp, detail::decay_t<Ret>>; - return exp.has_value() ? result(detail::invoke(std::forward<F>(f))) - : result(unexpect, std::forward<Exp>(exp).error()); -} - -template <class Exp, class F, - detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr, - class Ret = decltype(detail::invoke(std::declval<F>())), - detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> -auto expected_map_impl(Exp &&exp, F &&f) { - using result = expected<void, err_t<Exp>>; - if (exp.has_value()) { - detail::invoke(std::forward<F>(f)); - return result(); - } - - return result(unexpect, std::forward<Exp>(exp).error()); -} -#else -template <class Exp, class F, - detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, - class Ret = decltype(detail::invoke(std::declval<F>(), - *std::declval<Exp>())), - detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> - -constexpr auto expected_map_impl(Exp &&exp, F &&f) - -> ret_t<Exp, detail::decay_t<Ret>> { - using result = ret_t<Exp, detail::decay_t<Ret>>; - - return exp.has_value() ? result(detail::invoke(std::forward<F>(f), - *std::forward<Exp>(exp))) - : result(unexpect, std::forward<Exp>(exp).error()); -} - -template <class Exp, class F, - detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, - class Ret = decltype(detail::invoke(std::declval<F>(), - *std::declval<Exp>())), - detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> - -auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> { - if (exp.has_value()) { - detail::invoke(std::forward<F>(f), *std::forward<Exp>(exp)); - return {}; - } - - return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error()); -} - -template <class Exp, class F, - detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr, - class Ret = decltype(detail::invoke(std::declval<F>())), - detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> - -constexpr auto expected_map_impl(Exp &&exp, F &&f) - -> ret_t<Exp, detail::decay_t<Ret>> { - using result = ret_t<Exp, detail::decay_t<Ret>>; - - return exp.has_value() ? result(detail::invoke(std::forward<F>(f))) - : result(unexpect, std::forward<Exp>(exp).error()); -} - -template <class Exp, class F, - detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr, - class Ret = decltype(detail::invoke(std::declval<F>())), - detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> - -auto expected_map_impl(Exp &&exp, F &&f) -> expected<void, err_t<Exp>> { - if (exp.has_value()) { - detail::invoke(std::forward<F>(f)); - return {}; - } - - return unexpected<err_t<Exp>>(std::forward<Exp>(exp).error()); -} -#endif - -#if defined(TL_EXPECTED_CXX14) && !defined(TL_EXPECTED_GCC49) && \ - !defined(TL_EXPECTED_GCC54) && !defined(TL_EXPECTED_GCC55) -template <class Exp, class F, - detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, - class Ret = decltype(detail::invoke(std::declval<F>(), - std::declval<Exp>().error())), - detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> -constexpr auto map_error_impl(Exp &&exp, F &&f) { - using result = expected<exp_t<Exp>, detail::decay_t<Ret>>; - return exp.has_value() - ? result(*std::forward<Exp>(exp)) - : result(unexpect, detail::invoke(std::forward<F>(f), - std::forward<Exp>(exp).error())); -} -template <class Exp, class F, - detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, - class Ret = decltype(detail::invoke(std::declval<F>(), - std::declval<Exp>().error())), - detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> -auto map_error_impl(Exp &&exp, F &&f) { - using result = expected<exp_t<Exp>, monostate>; - if (exp.has_value()) { - return result(*std::forward<Exp>(exp)); - } - - detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()); - return result(unexpect, monostate{}); -} -template <class Exp, class F, - detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr, - class Ret = decltype(detail::invoke(std::declval<F>(), - std::declval<Exp>().error())), - detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> -constexpr auto map_error_impl(Exp &&exp, F &&f) { - using result = expected<exp_t<Exp>, detail::decay_t<Ret>>; - return exp.has_value() - ? result() - : result(unexpect, detail::invoke(std::forward<F>(f), - std::forward<Exp>(exp).error())); -} -template <class Exp, class F, - detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr, - class Ret = decltype(detail::invoke(std::declval<F>(), - std::declval<Exp>().error())), - detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> -auto map_error_impl(Exp &&exp, F &&f) { - using result = expected<exp_t<Exp>, monostate>; - if (exp.has_value()) { - return result(); - } - - detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()); - return result(unexpect, monostate{}); -} -#else -template <class Exp, class F, - detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, - class Ret = decltype(detail::invoke(std::declval<F>(), - std::declval<Exp>().error())), - detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> -constexpr auto map_error_impl(Exp &&exp, F &&f) - -> expected<exp_t<Exp>, detail::decay_t<Ret>> { - using result = expected<exp_t<Exp>, detail::decay_t<Ret>>; - - return exp.has_value() - ? result(*std::forward<Exp>(exp)) - : result(unexpect, detail::invoke(std::forward<F>(f), - std::forward<Exp>(exp).error())); -} - -template <class Exp, class F, - detail::enable_if_t<!std::is_void<exp_t<Exp>>::value> * = nullptr, - class Ret = decltype(detail::invoke(std::declval<F>(), - std::declval<Exp>().error())), - detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> -auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> { - using result = expected<exp_t<Exp>, monostate>; - if (exp.has_value()) { - return result(*std::forward<Exp>(exp)); - } - - detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()); - return result(unexpect, monostate{}); -} - -template <class Exp, class F, - detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr, - class Ret = decltype(detail::invoke(std::declval<F>(), - std::declval<Exp>().error())), - detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> -constexpr auto map_error_impl(Exp &&exp, F &&f) - -> expected<exp_t<Exp>, detail::decay_t<Ret>> { - using result = expected<exp_t<Exp>, detail::decay_t<Ret>>; - - return exp.has_value() - ? result() - : result(unexpect, detail::invoke(std::forward<F>(f), - std::forward<Exp>(exp).error())); -} - -template <class Exp, class F, - detail::enable_if_t<std::is_void<exp_t<Exp>>::value> * = nullptr, - class Ret = decltype(detail::invoke(std::declval<F>(), - std::declval<Exp>().error())), - detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> -auto map_error_impl(Exp &&exp, F &&f) -> expected<exp_t<Exp>, monostate> { - using result = expected<exp_t<Exp>, monostate>; - if (exp.has_value()) { - return result(); - } - - detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()); - return result(unexpect, monostate{}); -} -#endif - -#ifdef TL_EXPECTED_CXX14 -template <class Exp, class F, - class Ret = decltype(detail::invoke(std::declval<F>(), - std::declval<Exp>().error())), - detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> -constexpr auto or_else_impl(Exp &&exp, F &&f) { - static_assert(detail::is_expected<Ret>::value, "F must return an expected"); - return exp.has_value() - ? std::forward<Exp>(exp) - : detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()); -} - -template <class Exp, class F, - class Ret = decltype(detail::invoke(std::declval<F>(), - std::declval<Exp>().error())), - detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> -detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) { - return exp.has_value() - ? std::forward<Exp>(exp) - : (detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()), - std::forward<Exp>(exp)); -} -#else -template <class Exp, class F, - class Ret = decltype(detail::invoke(std::declval<F>(), - std::declval<Exp>().error())), - detail::enable_if_t<!std::is_void<Ret>::value> * = nullptr> -auto or_else_impl(Exp &&exp, F &&f) -> Ret { - static_assert(detail::is_expected<Ret>::value, "F must return an expected"); - return exp.has_value() - ? std::forward<Exp>(exp) - : detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()); -} - -template <class Exp, class F, - class Ret = decltype(detail::invoke(std::declval<F>(), - std::declval<Exp>().error())), - detail::enable_if_t<std::is_void<Ret>::value> * = nullptr> -detail::decay_t<Exp> or_else_impl(Exp &&exp, F &&f) { - return exp.has_value() - ? std::forward<Exp>(exp) - : (detail::invoke(std::forward<F>(f), std::forward<Exp>(exp).error()), - std::forward<Exp>(exp)); -} -#endif -} // namespace detail - -template <class T, class E, class U, class F> -constexpr bool operator==(const expected<T, E> &lhs, - const expected<U, F> &rhs) { - return (lhs.has_value() != rhs.has_value()) - ? false - : (!lhs.has_value() ? lhs.error() == rhs.error() : *lhs == *rhs); -} -template <class T, class E, class U, class F> -constexpr bool operator!=(const expected<T, E> &lhs, - const expected<U, F> &rhs) { - return (lhs.has_value() != rhs.has_value()) - ? true - : (!lhs.has_value() ? lhs.error() != rhs.error() : *lhs != *rhs); -} - -template <class T, class E, class U> -constexpr bool operator==(const expected<T, E> &x, const U &v) { - return x.has_value() ? *x == v : false; -} -template <class T, class E, class U> -constexpr bool operator==(const U &v, const expected<T, E> &x) { - return x.has_value() ? *x == v : false; -} -template <class T, class E, class U> -constexpr bool operator!=(const expected<T, E> &x, const U &v) { - return x.has_value() ? *x != v : true; -} -template <class T, class E, class U> -constexpr bool operator!=(const U &v, const expected<T, E> &x) { - return x.has_value() ? *x != v : true; -} - -template <class T, class E> -constexpr bool operator==(const expected<T, E> &x, const unexpected<E> &e) { - return x.has_value() ? false : x.error() == e.value(); -} -template <class T, class E> -constexpr bool operator==(const unexpected<E> &e, const expected<T, E> &x) { - return x.has_value() ? false : x.error() == e.value(); -} -template <class T, class E> -constexpr bool operator!=(const expected<T, E> &x, const unexpected<E> &e) { - return x.has_value() ? true : x.error() != e.value(); -} -template <class T, class E> -constexpr bool operator!=(const unexpected<E> &e, const expected<T, E> &x) { - return x.has_value() ? true : x.error() != e.value(); -} - -// TODO is_swappable -template <class T, class E, - detail::enable_if_t<std::is_move_constructible<T>::value && - std::is_move_constructible<E>::value> * = nullptr> -void swap(expected<T, E> &lhs, - expected<T, E> &rhs) noexcept(noexcept(lhs.swap(rhs))) { - lhs.swap(rhs); -} -} // namespace tl - -#define TL_OPTIONAL_EXPECTED_MUTEX -#endif diff --git a/src/include/object.h b/src/include/object.h index 96951e74de7..b0f21bc4558 100644 --- a/src/include/object.h +++ b/src/include/object.h @@ -17,11 +17,10 @@ #include <cstdint> #include <cstdio> -#include <iomanip> #include <iosfwd> +#include <iomanip> #include <string> -#include <string> -#include <string_view> + #include "include/rados.h" #include "include/unordered_map.h" @@ -41,8 +40,6 @@ struct object_t { object_t(const char *s) : name(s) {} // cppcheck-suppress noExplicitConstructor object_t(const std::string& s) : name(s) {} - object_t(std::string&& s) : name(std::move(s)) {} - object_t(std::string_view s) : name(s) {} void swap(object_t& o) { name.swap(o.name); diff --git a/src/libcephfs.cc b/src/libcephfs.cc index 8cde7fb3219..8a6b14d1ed8 100644 --- a/src/libcephfs.cc +++ b/src/libcephfs.cc @@ -20,7 +20,6 @@ #include "auth/Crypto.h" #include "client/Client.h" #include "librados/RadosClient.h" -#include "common/async/context_pool.h" #include "common/ceph_argparse.h" #include "common/common_init.h" #include "common/config.h" @@ -37,7 +36,6 @@ #define DEFAULT_UMASK 002 static mode_t umask_cb(void *); -ceph::async::io_context_pool icp; struct ceph_mount_info { @@ -85,9 +83,8 @@ public: cct->_log->start(); } - icp.start(cct->_conf.get_val<std::uint64_t>("client_asio_thread_count")); { - MonClient mc_bootstrap(cct, icp); + MonClient mc_bootstrap(cct); ret = mc_bootstrap.get_monmap_and_config(); if (ret < 0) return ret; @@ -96,7 +93,7 @@ public: common_init_finish(cct); //monmap - monclient = new MonClient(cct, icp); + monclient = new MonClient(cct); ret = -CEPHFS_ERROR_MON_MAP_BUILD; //defined in libcephfs.h; if (monclient->build_initial_monmap() < 0) goto fail; @@ -106,7 +103,7 @@ public: //at last the client ret = -CEPHFS_ERROR_NEW_CLIENT; //defined in libcephfs.h; - client = new StandaloneClient(messenger, monclient, icp); + client = new StandaloneClient(messenger, monclient); if (!client) goto fail; @@ -205,7 +202,6 @@ public: delete messenger; messenger = nullptr; } - icp.stop(); if (monclient) { delete monclient; monclient = nullptr; diff --git a/src/librados/AioCompletionImpl.h b/src/librados/AioCompletionImpl.h index 7b49bc68d73..d3a674e8ee7 100644 --- a/src/librados/AioCompletionImpl.h +++ b/src/librados/AioCompletionImpl.h @@ -126,14 +126,14 @@ struct librados::AioCompletionImpl { }; namespace librados { -struct CB_AioComplete { +struct C_AioComplete : public Context { AioCompletionImpl *c; - explicit CB_AioComplete(AioCompletionImpl *cc) : c(cc) { + explicit C_AioComplete(AioCompletionImpl *cc) : c(cc) { c->_get(); } - void operator()() { + void finish(int r) override { rados_callback_t cb_complete = c->callback_complete; void *cb_complete_arg = c->callback_complete_arg; if (cb_complete) @@ -160,14 +160,14 @@ struct CB_AioComplete { * flush where we only want to wait for things to be safe, * but allow users to specify any of the callbacks. */ -struct CB_AioCompleteAndSafe { +struct C_AioCompleteAndSafe : public Context { AioCompletionImpl *c; - explicit CB_AioCompleteAndSafe(AioCompletionImpl *cc) : c(cc) { + explicit C_AioCompleteAndSafe(AioCompletionImpl *cc) : c(cc) { c->get(); } - void operator()(int r = 0) { + void finish(int r) override { c->lock.lock(); c->rval = r; c->complete = true; @@ -190,6 +190,7 @@ struct CB_AioCompleteAndSafe { c->put_unlock(); } }; + } #endif diff --git a/src/librados/IoCtxImpl.cc b/src/librados/IoCtxImpl.cc index 8d3ba1e16fb..ddcd4c6fea1 100644 --- a/src/librados/IoCtxImpl.cc +++ b/src/librados/IoCtxImpl.cc @@ -28,38 +28,34 @@ #undef dout_prefix #define dout_prefix *_dout << "librados: " -namespace bs = boost::system; -namespace ca = ceph::async; -namespace cb = ceph::buffer; - namespace librados { namespace { -struct CB_notify_Finish { +struct C_notify_Finish : public Context { CephContext *cct; Context *ctx; Objecter *objecter; Objecter::LingerOp *linger_op; + bufferlist reply_bl; bufferlist *preply_bl; char **preply_buf; size_t *preply_buf_len; - CB_notify_Finish(CephContext *_cct, Context *_ctx, Objecter *_objecter, - Objecter::LingerOp *_linger_op, bufferlist *_preply_bl, - char **_preply_buf, size_t *_preply_buf_len) + C_notify_Finish(CephContext *_cct, Context *_ctx, Objecter *_objecter, + Objecter::LingerOp *_linger_op, bufferlist *_preply_bl, + char **_preply_buf, size_t *_preply_buf_len) : cct(_cct), ctx(_ctx), objecter(_objecter), linger_op(_linger_op), preply_bl(_preply_bl), preply_buf(_preply_buf), - preply_buf_len(_preply_buf_len) {} - - - CB_notify_Finish(const CB_notify_Finish&) = delete; - CB_notify_Finish operator =(const CB_notify_Finish&) = delete; - CB_notify_Finish(CB_notify_Finish&&) = delete; - CB_notify_Finish operator =(CB_notify_Finish&&) = delete; + preply_buf_len(_preply_buf_len) + { + linger_op->on_notify_finish = this; + linger_op->notify_result_bl = &reply_bl; + } - void operator()(bs::error_code ec, bufferlist&& reply_bl) { + void finish(int r) override + { ldout(cct, 10) << __func__ << " completed notify (linger op " - << linger_op << "), ec = " << ec << dendl; + << linger_op << "), r = " << r << dendl; // pass result back to user // NOTE: we do this regardless of what error code we return @@ -76,21 +72,21 @@ struct CB_notify_Finish { if (preply_bl) preply_bl->claim(reply_bl); - ctx->complete(ceph::from_error_code(ec)); - linger_op->on_notify_finish.reset(); + ctx->complete(r); } }; -struct CB_aio_linger_cancel { +struct C_aio_linger_cancel : public Context { Objecter *objecter; Objecter::LingerOp *linger_op; - CB_aio_linger_cancel(Objecter *_objecter, Objecter::LingerOp *_linger_op) + C_aio_linger_cancel(Objecter *_objecter, Objecter::LingerOp *_linger_op) : objecter(_objecter), linger_op(_linger_op) { } - void operator()() { + void finish(int r) override + { objecter->linger_cancel(linger_op); } }; @@ -108,9 +104,8 @@ struct C_aio_linger_Complete : public Context { void finish(int r) override { if (cancel || r < 0) - boost::asio::defer(c->io->client->finish_strand, - CB_aio_linger_cancel(c->io->objecter, - linger_op)); + c->io->client->finisher.queue(new C_aio_linger_cancel(c->io->objecter, + linger_op)); c->lock.lock(); c->rval = r; @@ -119,7 +114,7 @@ struct C_aio_linger_Complete : public Context { if (c->callback_complete || c->callback_safe) { - boost::asio::defer(c->io->client->finish_strand, CB_AioComplete(c)); + c->io->client->finisher.queue(new C_AioComplete(c)); } c->put_unlock(); } @@ -166,11 +161,12 @@ struct C_aio_notify_Complete : public C_aio_linger_Complete { struct C_aio_notify_Ack : public Context { CephContext *cct; + C_notify_Finish *onfinish; C_aio_notify_Complete *oncomplete; - C_aio_notify_Ack(CephContext *_cct, + C_aio_notify_Ack(CephContext *_cct, C_notify_Finish *_onfinish, C_aio_notify_Complete *_oncomplete) - : cct(_cct), oncomplete(_oncomplete) + : cct(_cct), onfinish(_onfinish), oncomplete(_oncomplete) { } @@ -199,7 +195,7 @@ struct C_aio_selfmanaged_snap_op_Complete : public Context { c->cond.notify_all(); if (c->callback_complete || c->callback_safe) { - boost::asio::defer(client->finish_strand, librados::CB_AioComplete(c)); + client->finisher.queue(new librados::C_AioComplete(c)); } c->put_unlock(); } @@ -309,7 +305,7 @@ void librados::IoCtxImpl::complete_aio_write(AioCompletionImpl *c) ldout(client->cct, 20) << " waking waiters on seq " << waiters->first << dendl; for (std::list<AioCompletionImpl*>::iterator it = waiters->second.begin(); it != waiters->second.end(); ++it) { - boost::asio::defer(client->finish_strand, CB_AioCompleteAndSafe(*it)); + client->finisher.queue(new C_AioCompleteAndSafe(*it)); (*it)->put(); } aio_write_waiters.erase(waiters++); @@ -329,7 +325,7 @@ void librados::IoCtxImpl::flush_aio_writes_async(AioCompletionImpl *c) if (aio_write_list.empty()) { ldout(client->cct, 20) << "flush_aio_writes_async no writes. (tid " << seq << ")" << dendl; - boost::asio::defer(client->finish_strand, CB_AioCompleteAndSafe(c)); + client->finisher.queue(new C_AioCompleteAndSafe(c)); } else { ldout(client->cct, 20) << "flush_aio_writes_async " << aio_write_list.size() << " writes in flight; waiting on tid " << seq << dendl; @@ -366,10 +362,14 @@ int librados::IoCtxImpl::snap_create(const char *snapName) ceph::condition_variable cond; bool done; Context *onfinish = new C_SafeCond(mylock, cond, &done, &reply); - objecter->create_pool_snap(poolid, sName, onfinish); + reply = objecter->create_pool_snap(poolid, sName, onfinish); - std::unique_lock l{mylock}; - cond.wait(l, [&done] { return done; }); + if (reply < 0) { + delete onfinish; + } else { + std::unique_lock l{mylock}; + cond.wait(l, [&done] { return done; }); + } return reply; } @@ -382,14 +382,18 @@ int librados::IoCtxImpl::selfmanaged_snap_create(uint64_t *psnapid) bool done; Context *onfinish = new C_SafeCond(mylock, cond, &done, &reply); snapid_t snapid; - objecter->allocate_selfmanaged_snap(poolid, &snapid, onfinish); + reply = objecter->allocate_selfmanaged_snap(poolid, &snapid, onfinish); - { - std::unique_lock l{mylock}; - cond.wait(l, [&done] { return done; }); + if (reply < 0) { + delete onfinish; + } else { + { + std::unique_lock l{mylock}; + cond.wait(l, [&done] { return done; }); + } + if (reply == 0) + *psnapid = snapid; } - if (reply == 0) - *psnapid = snapid; return reply; } @@ -398,8 +402,11 @@ void librados::IoCtxImpl::aio_selfmanaged_snap_create(uint64_t *snapid, { C_aio_selfmanaged_snap_create_Complete *onfinish = new C_aio_selfmanaged_snap_create_Complete(client, c, snapid); - objecter->allocate_selfmanaged_snap(poolid, &onfinish->snapid, - onfinish); + int r = objecter->allocate_selfmanaged_snap(poolid, &onfinish->snapid, + onfinish); + if (r < 0) { + onfinish->complete(r); + } } int librados::IoCtxImpl::snap_remove(const char *snapName) @@ -411,9 +418,14 @@ int librados::IoCtxImpl::snap_remove(const char *snapName) ceph::condition_variable cond; bool done; Context *onfinish = new C_SafeCond(mylock, cond, &done, &reply); - objecter->delete_pool_snap(poolid, sName, onfinish); - unique_lock l{mylock}; - cond.wait(l, [&done] { return done; }); + reply = objecter->delete_pool_snap(poolid, sName, onfinish); + + if (reply < 0) { + delete onfinish; + } else { + unique_lock l{mylock}; + cond.wait(l, [&done] { return done; }); + } return reply; } @@ -1143,7 +1155,7 @@ struct AioGetxattrsData { AioGetxattrsData(librados::AioCompletionImpl *c, map<string, bufferlist>* attrset, librados::RadosClient *_client) : user_completion(c), user_attrset(attrset), client(_client) {} - struct librados::CB_AioCompleteAndSafe user_completion; + struct librados::C_AioCompleteAndSafe user_completion; map<string, bufferlist> result_attrset; map<std::string, bufferlist>* user_attrset; librados::RadosClient *client; @@ -1162,7 +1174,7 @@ static void aio_getxattrs_complete(rados_completion_t c, void *arg) { (*cdata->user_attrset)[p->first] = p->second; } } - cdata->user_completion(rc); + cdata->user_completion.finish(rc); ((librados::AioCompletionImpl*)c)->put(); delete cdata; } @@ -1465,7 +1477,7 @@ int librados::IoCtxImpl::stat(const object_t& oid, uint64_t *psize, time_t *pmti ::ObjectOperation rd; prepare_assert_ops(&rd); - rd.stat(psize, &mtime, nullptr); + rd.stat(psize, &mtime, NULL); int r = operate_read(oid, &rd, NULL); if (r >= 0 && pmtime) { @@ -1485,7 +1497,7 @@ int librados::IoCtxImpl::stat2(const object_t& oid, uint64_t *psize, struct time ::ObjectOperation rd; prepare_assert_ops(&rd); - rd.stat(psize, &mtime, nullptr); + rd.stat(psize, &mtime, NULL); int r = operate_read(oid, &rd, NULL); if (r < 0) { return r; @@ -1556,7 +1568,7 @@ void librados::IoCtxImpl::set_sync_op_version(version_t ver) last_objver = ver; } -struct WatchInfo { +struct WatchInfo : public Objecter::WatchContext { librados::IoCtxImpl *ioctx; object_t oid; librados::WatchCtx *ctx; @@ -1569,7 +1581,7 @@ struct WatchInfo { : ioctx(io), oid(o), ctx(c), ctx2(c2), internal(inter) { ioctx->get(); } - ~WatchInfo() { + ~WatchInfo() override { ioctx->put(); if (internal) { delete ctx; @@ -1577,15 +1589,10 @@ struct WatchInfo { } } - WatchInfo(const WatchInfo&) = delete; - WatchInfo& operator =(const WatchInfo&) = delete; - WatchInfo(WatchInfo&&) = delete; - WatchInfo& operator =(WatchInfo&&) = delete; - void handle_notify(uint64_t notify_id, uint64_t cookie, uint64_t notifier_id, - bufferlist& bl) { + bufferlist& bl) override { ldout(ioctx->client->cct, 10) << __func__ << " " << notify_id << " cookie " << cookie << " notifier_id " << notifier_id @@ -1602,25 +1609,13 @@ struct WatchInfo { ioctx->notify_ack(oid, notify_id, cookie, empty); } } - void handle_error(uint64_t cookie, int err) { + void handle_error(uint64_t cookie, int err) override { ldout(ioctx->client->cct, 10) << __func__ << " cookie " << cookie << " err " << err << dendl; if (ctx2) ctx2->handle_error(cookie, err); } - - void operator()(bs::error_code ec, - uint64_t notify_id, - uint64_t cookie, - uint64_t notifier_id, - bufferlist&& bl) { - if (ec) { - handle_error(cookie, ceph::from_error_code(ec)); - } else { - handle_notify(notify_id, cookie, notifier_id, bl); - } - } }; int librados::IoCtxImpl::watch(const object_t& oid, uint64_t *handle, @@ -1643,15 +1638,9 @@ int librados::IoCtxImpl::watch(const object_t& oid, uint64_t *handle, Objecter::LingerOp *linger_op = objecter->linger_register(oid, oloc, 0); *handle = linger_op->get_cookie(); - auto wi = std::make_unique<WatchInfo>(this, oid, ctx, ctx2, internal); - linger_op->handle = - [wi = std::move(wi)](bs::error_code ec, - uint64_t notify_id, - uint64_t cookie, - uint64_t notifier_id, - bufferlist&& bl) mutable { - (*wi)(ec, notify_id, cookie, notifier_id, std::move(bl)); - }; + linger_op->watch_context = new WatchInfo(this, + oid, ctx, ctx2, internal); + prepare_assert_ops(&wr); wr.watch(*handle, CEPH_OSD_WATCH_OP_WATCH, timeout); bufferlist bl; @@ -1695,15 +1684,7 @@ int librados::IoCtxImpl::aio_watch(const object_t& oid, ::ObjectOperation wr; *handle = linger_op->get_cookie(); - auto wi = std::make_unique<WatchInfo>(this, oid, ctx, ctx2, internal); - linger_op->handle = - [wi = std::move(wi)](bs::error_code ec, - uint64_t notify_id, - uint64_t cookie, - uint64_t notifier_id, - bufferlist&& bl) mutable { - (*wi)(ec, notify_id, cookie, notifier_id, std::move(bl)); - }; + linger_op->watch_context = new WatchInfo(this, oid, ctx, ctx2, internal); prepare_assert_ops(&wr); wr.watch(*handle, CEPH_OSD_WATCH_OP_WATCH, timeout); @@ -1731,13 +1712,8 @@ int librados::IoCtxImpl::notify_ack( int librados::IoCtxImpl::watch_check(uint64_t cookie) { - auto linger_op = reinterpret_cast<Objecter::LingerOp*>(cookie); - auto r = objecter->linger_check(linger_op); - if (r) - return 1 + std::chrono::duration_cast< - std::chrono::milliseconds>(*r).count(); - else - return ceph::from_error_code(r.error()); + Objecter::LingerOp *linger_op = reinterpret_cast<Objecter::LingerOp*>(cookie); + return objecter->linger_check(linger_op); } int librados::IoCtxImpl::unwatch(uint64_t cookie) @@ -1782,15 +1758,11 @@ int librados::IoCtxImpl::notify(const object_t& oid, bufferlist& bl, Objecter::LingerOp *linger_op = objecter->linger_register(oid, oloc, 0); C_SaferCond notify_finish_cond; - linger_op->on_notify_finish = - Objecter::LingerOp::OpComp::create( - objecter->service.get_executor(), - [c = std::make_unique<CB_notify_Finish>(client->cct, ¬ify_finish_cond, - objecter, linger_op, preply_bl, - preply_buf, preply_buf_len)] - (bs::error_code ec, cb::list bl) { - std::move(*c)(ec, std::move(bl)); - }); + Context *notify_finish = new C_notify_Finish(client->cct, ¬ify_finish_cond, + objecter, linger_op, preply_bl, + preply_buf, preply_buf_len); + (void) notify_finish; + uint32_t timeout = notify_timeout; if (timeout_ms) timeout = timeout_ms / 1000; @@ -1840,17 +1812,11 @@ int librados::IoCtxImpl::aio_notify(const object_t& oid, AioCompletionImpl *c, c->io = this; C_aio_notify_Complete *oncomplete = new C_aio_notify_Complete(c, linger_op); - linger_op->on_notify_finish = - Objecter::LingerOp::OpComp::create( - objecter->service.get_executor(), - [c = std::make_unique<CB_notify_Finish>(client->cct, oncomplete, - objecter, linger_op, - preply_bl, preply_buf, - preply_buf_len)] - (bs::error_code ec, cb::list&& bl) { - std::move(*c)(ec, std::move(bl)); - }); - Context *onack = new C_aio_notify_Ack(client->cct, oncomplete); + C_notify_Finish *onnotify = new C_notify_Finish(client->cct, oncomplete, + objecter, linger_op, + preply_bl, preply_buf, + preply_buf_len); + Context *onack = new C_aio_notify_Ack(client->cct, onnotify, oncomplete); uint32_t timeout = notify_timeout; if (timeout_ms) @@ -1934,7 +1900,7 @@ void librados::IoCtxImpl::C_aio_stat_Ack::finish(int r) } if (c->callback_complete) { - boost::asio::defer(c->io->client->finish_strand, CB_AioComplete(c)); + c->io->client->finisher.queue(new C_AioComplete(c)); } c->put_unlock(); @@ -1962,7 +1928,7 @@ void librados::IoCtxImpl::C_aio_stat2_Ack::finish(int r) } if (c->callback_complete) { - boost::asio::defer(c->io->client->finish_strand, CB_AioComplete(c)); + c->io->client->finisher.queue(new C_AioComplete(c)); } c->put_unlock(); @@ -1998,7 +1964,7 @@ void librados::IoCtxImpl::C_aio_Complete::finish(int r) if (c->callback_complete || c->callback_safe) { - boost::asio::defer(c->io->client->finish_strand, CB_AioComplete(c)); + c->io->client->finisher.queue(new C_AioComplete(c)); } if (c->aio_write_seq) { @@ -2062,7 +2028,6 @@ int librados::IoCtxImpl::application_enable(const std::string& app_name, r = c->get_return_value(); c->release(); - c->put(); if (r < 0) { return r; } @@ -2078,10 +2043,7 @@ void librados::IoCtxImpl::application_enable_async(const std::string& app_name, // preserved until Luminous is configured as minimim version. if (!client->get_required_monitor_features().contains_all( ceph::features::mon::FEATURE_LUMINOUS)) { - boost::asio::defer(client->finish_strand, - [cb = CB_PoolAsync_Safe(c)]() mutable { - cb(-EOPNOTSUPP); - }); + client->finisher.queue(new C_PoolAsync_Safe(c), -EOPNOTSUPP); return; } @@ -2099,7 +2061,7 @@ void librados::IoCtxImpl::application_enable_async(const std::string& app_name, cmds.push_back(cmd.str()); bufferlist inbl; client->mon_command_async(cmds, inbl, nullptr, nullptr, - make_lambda_context(CB_PoolAsync_Safe(c))); + new C_PoolAsync_Safe(c)); } int librados::IoCtxImpl::application_list(std::set<std::string> *app_names) diff --git a/src/librados/ListObjectImpl.h b/src/librados/ListObjectImpl.h index 7396c12108d..95c2e21a4ec 100644 --- a/src/librados/ListObjectImpl.h +++ b/src/librados/ListObjectImpl.h @@ -11,15 +11,13 @@ * Foundation. See file COPYING. * */ +#include <string> #ifndef CEPH_LIBRADOS_LISTOBJECTIMPL_H #define CEPH_LIBRADOS_LISTOBJECTIMPL_H -#include <string> #include <include/rados/librados.hpp> -#include "include/cmp.h" - namespace librados { struct ListObjectImpl { std::string nspace; diff --git a/src/librados/PoolAsyncCompletionImpl.h b/src/librados/PoolAsyncCompletionImpl.h index 73420fe359c..b52d7fada20 100644 --- a/src/librados/PoolAsyncCompletionImpl.h +++ b/src/librados/PoolAsyncCompletionImpl.h @@ -16,9 +16,7 @@ #define CEPH_LIBRADOS_POOLASYNCCOMPLETIONIMPL_H #include "common/ceph_mutex.h" - -#include <boost/intrusive_ptr.hpp> - +#include "include/Context.h" #include "include/rados/librados.h" #include "include/rados/librados.hpp" @@ -31,68 +29,67 @@ namespace librados { bool released = false; bool done = false; - rados_callback_t callback = nullptr; - void *callback_arg = nullptr; + rados_callback_t callback = 0; + void *callback_arg = nullptr;; PoolAsyncCompletionImpl() = default; int set_callback(void *cb_arg, rados_callback_t cb) { - std::scoped_lock l(lock); + std::scoped_lock l{lock}; callback = cb; callback_arg = cb_arg; return 0; } int wait() { - std::unique_lock l(lock); - while (!done) - cond.wait(l); + std::unique_lock l{lock}; + cond.wait(l, [this] { return done;}); return 0; } int is_complete() { - std::scoped_lock l(lock); + std::scoped_lock l{lock}; return done; } int get_return_value() { - std::scoped_lock l(lock); + std::scoped_lock l{lock}; return rval; } void get() { - std::scoped_lock l(lock); + std::scoped_lock l{lock}; ceph_assert(ref > 0); ref++; } void release() { - std::scoped_lock l(lock); + lock.lock(); ceph_assert(!released); released = true; + put_unlock(); } void put() { - std::unique_lock l(lock); + lock.lock(); + put_unlock(); + } + void put_unlock() { + ceph_assert(ref > 0); int n = --ref; - l.unlock(); + lock.unlock(); if (!n) delete this; } }; - inline void intrusive_ptr_add_ref(PoolAsyncCompletionImpl* p) { - p->get(); - } - inline void intrusive_ptr_release(PoolAsyncCompletionImpl* p) { - p->put(); - } - - class CB_PoolAsync_Safe { - boost::intrusive_ptr<PoolAsyncCompletionImpl> p; + class C_PoolAsync_Safe : public Context { + PoolAsyncCompletionImpl *c; public: - explicit CB_PoolAsync_Safe(boost::intrusive_ptr<PoolAsyncCompletionImpl> p) - : p(p) {} - ~CB_PoolAsync_Safe() = default; - - void operator()(int r) { - auto c(std::move(p)); - std::unique_lock l(c->lock); + explicit C_PoolAsync_Safe(PoolAsyncCompletionImpl *_c) : c(_c) { + c->get(); + } + ~C_PoolAsync_Safe() override { + c->put(); + } + + void finish(int r) override { + c->lock.lock(); c->rval = r; c->done = true; c->cond.notify_all(); @@ -100,10 +97,12 @@ namespace librados { if (c->callback) { rados_callback_t cb = c->callback; void *cb_arg = c->callback_arg; - l.unlock(); - cb(c.get(), cb_arg); - l.lock(); + c->lock.unlock(); + cb(c, cb_arg); + c->lock.lock(); } + + c->lock.unlock(); } }; } diff --git a/src/librados/RadosClient.cc b/src/librados/RadosClient.cc index 15fef61f7ea..372419816d8 100644 --- a/src/librados/RadosClient.cc +++ b/src/librados/RadosClient.cc @@ -28,7 +28,6 @@ #include "common/ceph_json.h" #include "common/errno.h" #include "common/ceph_json.h" -#include "common/async/waiter.h" #include "include/buffer.h" #include "include/stringify.h" #include "include/util.h" @@ -57,13 +56,22 @@ #undef dout_prefix #define dout_prefix *_dout << "librados: " -namespace ca = ceph::async; -namespace cb = ceph::buffer; -namespace bc = boost::container; -namespace bs = boost::system; - librados::RadosClient::RadosClient(CephContext *cct_) - : Dispatcher(cct_->get()) {} + : Dispatcher(cct_->get()), + cct_deleter{cct_, [](CephContext *p) {p->put();}}, + conf(cct_->_conf), + state(DISCONNECTED), + monclient(cct_), + mgrclient(cct_, nullptr, &monclient.monmap), + messenger(NULL), + instance_id(0), + objecter(NULL), + timer(cct, lock), + refcnt(1), + log_last_version(0), log_cb(NULL), log_cb2(NULL), log_cb_arg(NULL), + finisher(cct, "radosclient", "fn-radosclient") +{ +} int64_t librados::RadosClient::lookup_pool(const char *name) { @@ -225,7 +233,7 @@ int librados::RadosClient::connect() } { - MonClient mc_bootstrap(cct, poolctx); + MonClient mc_bootstrap(cct); err = mc_bootstrap.get_monmap_and_config(); if (err < 0) return err; @@ -233,8 +241,6 @@ int librados::RadosClient::connect() common_init_finish(cct); - poolctx.start(cct->_conf.get_val<std::uint64_t>("librados_thread_count")); - // get monmap err = monclient.build_initial_monmap(); if (err < 0) @@ -255,9 +261,9 @@ int librados::RadosClient::connect() ldout(cct, 1) << "starting objecter" << dendl; objecter = new (std::nothrow) Objecter(cct, messenger, &monclient, - poolctx, - cct->_conf->rados_mon_op_timeout, - cct->_conf->rados_osd_op_timeout); + &finisher, + cct->_conf->rados_mon_op_timeout, + cct->_conf->rados_osd_op_timeout); if (!objecter) goto out; objecter->set_balanced_budget(); @@ -312,6 +318,10 @@ int librados::RadosClient::connect() objecter->start(); lock.lock(); + timer.init(); + + finisher.start(); + state = CONNECTED; instance_id = monclient.get_global_id(); @@ -354,9 +364,12 @@ void librados::RadosClient::shutdown() // make sure watch callbacks are flushed watch_flush(); } + finisher.wait_for_empty(); + finisher.stop(); } state = DISCONNECTED; instance_id = 0; + timer.shutdown(); // will drop+retake lock l.unlock(); if (need_objecter) { objecter->shutdown(); @@ -368,40 +381,41 @@ void librados::RadosClient::shutdown() messenger->shutdown(); messenger->wait(); } - poolctx.stop(); ldout(cct, 1) << "shutdown" << dendl; } int librados::RadosClient::watch_flush() { ldout(cct, 10) << __func__ << " enter" << dendl; - ca::waiter<> w; - objecter->linger_callback_flush(w); - - w.wait(); + ceph::mutex mylock = ceph::make_mutex("RadosClient::watch_flush::mylock"); + ceph::condition_variable cond; + bool done; + objecter->linger_callback_flush(new C_SafeCond(mylock, cond, &done)); + std::unique_lock l{mylock}; + cond.wait(l, [&done] { return done; }); ldout(cct, 10) << __func__ << " exit" << dendl; return 0; } -struct CB_aio_watch_flush_Complete { +struct C_aio_watch_flush_Complete : public Context { librados::RadosClient *client; librados::AioCompletionImpl *c; - CB_aio_watch_flush_Complete(librados::RadosClient *_client, librados::AioCompletionImpl *_c) + C_aio_watch_flush_Complete(librados::RadosClient *_client, librados::AioCompletionImpl *_c) : client(_client), c(_c) { c->get(); } - void operator()() { + void finish(int r) override { c->lock.lock(); - c->rval = 0; + c->rval = r; c->complete = true; c->cond.notify_all(); if (c->callback_complete || c->callback_safe) { - boost::asio::defer(client->finish_strand, librados::CB_AioComplete(c)); + client->finisher.queue(new librados::C_AioComplete(c)); } c->put_unlock(); } @@ -410,7 +424,8 @@ struct CB_aio_watch_flush_Complete { int librados::RadosClient::async_watch_flush(AioCompletionImpl *c) { ldout(cct, 10) << __func__ << " enter" << dendl; - objecter->linger_callback_flush(CB_aio_watch_flush_Complete(this, c)); + Context *oncomplete = new C_aio_watch_flush_Complete(this, c); + objecter->linger_callback_flush(oncomplete); ldout(cct, 10) << __func__ << " exit" << dendl; return 0; } @@ -588,10 +603,15 @@ int librados::RadosClient::wait_for_osdmap() int librados::RadosClient::wait_for_latest_osdmap() { - ca::waiter<bs::error_code> w; - objecter->wait_for_latest_osdmap(w); - auto ec = w.wait(); - return ceph::from_error_code(ec); + ceph::mutex mylock = ceph::make_mutex("RadosClient::wait_for_latest_osdmap"); + ceph::condition_variable cond; + bool done; + + objecter->wait_for_latest_osdmap(new C_SafeCond(mylock, cond, &done)); + + std::unique_lock l{mylock}; + cond.wait(l, [&done] {return done;}); + return 0; } int librados::RadosClient::pool_list(std::list<std::pair<int64_t, string> >& v) @@ -609,24 +629,20 @@ int librados::RadosClient::pool_list(std::list<std::pair<int64_t, string> >& v) int librados::RadosClient::get_pool_stats(std::list<string>& pools, map<string,::pool_stat_t> *result, - bool *pper_pool) + bool *per_pool) { - ca::waiter<bs::error_code, - bc::flat_map<std::string, ::pool_stat_t>, bool> w; - - std::vector<std::string> v(pools.begin(), pools.end()); - objecter->get_pool_stats(v, w); - - auto [ec, res, per_pool] = w.wait(); - if (ec) - return ceph::from_error_code(ec); + ceph::mutex mylock = ceph::make_mutex("RadosClient::get_pool_stats::mylock"); + ceph::condition_variable cond; + bool done; + int ret = 0; - if (per_pool) - *pper_pool = per_pool; - if (result) - result->insert(res.begin(), res.end()); + objecter->get_pool_stats(pools, result, per_pool, + new C_SafeCond(mylock, cond, &done, + &ret)); - return 0; + unique_lock l{mylock}; + cond.wait(l, [&done] { return done;}); + return ret; } bool librados::RadosClient::get_pool_is_selfmanaged_snaps_mode( @@ -688,10 +704,14 @@ int librados::RadosClient::pool_create(string& name, ceph::condition_variable cond; bool done; Context *onfinish = new C_SafeCond(mylock, cond, &done, &reply); - objecter->create_pool(name, onfinish, crush_rule); + reply = objecter->create_pool(name, onfinish, crush_rule); - std::unique_lock l{mylock}; - cond.wait(l, [&done] { return done; }); + if (reply < 0) { + delete onfinish; + } else { + std::unique_lock l{mylock}; + cond.wait(l, [&done] { return done; }); + } return reply; } @@ -703,8 +723,11 @@ int librados::RadosClient::pool_create_async(string& name, if (r < 0) return r; - Context *onfinish = make_lambda_context(CB_PoolAsync_Safe(c)); - objecter->create_pool(name, onfinish, crush_rule); + Context *onfinish = new C_PoolAsync_Safe(c); + r = objecter->create_pool(name, onfinish, crush_rule); + if (r < 0) { + delete onfinish; + } return r; } @@ -743,10 +766,14 @@ int librados::RadosClient::pool_delete(const char *name) bool done; int ret; Context *onfinish = new C_SafeCond(mylock, cond, &done, &ret); - objecter->delete_pool(name, onfinish); + ret = objecter->delete_pool(name, onfinish); - std::unique_lock l{mylock}; - cond.wait(l, [&done] { return done;}); + if (ret < 0) { + delete onfinish; + } else { + std::unique_lock l{mylock}; + cond.wait(l, [&done] { return done;}); + } return ret; } @@ -756,8 +783,11 @@ int librados::RadosClient::pool_delete_async(const char *name, PoolAsyncCompleti if (r < 0) return r; - Context *onfinish = make_lambda_context(CB_PoolAsync_Safe(c)); - objecter->delete_pool(name, onfinish); + Context *onfinish = new C_PoolAsync_Safe(c); + r = objecter->delete_pool(name, onfinish); + if (r < 0) { + delete onfinish; + } return r; } @@ -813,20 +843,7 @@ void librados::RadosClient::mon_command_async(const vector<string>& cmd, Context *on_finish) { std::lock_guard l{lock}; - monclient.start_mon_command(cmd, inbl, - [outs, outbl, - on_finish = std::unique_ptr<Context>(on_finish)] - (bs::error_code e, - std::string&& s, - ceph::bufferlist&& b) mutable { - if (outs) - *outs = std::move(s); - if (outbl) - *outbl = std::move(b); - if (on_finish) - on_finish.release()->complete( - ceph::from_error_code(e)); - }); + monclient.start_mon_command(cmd, inbl, outbl, outs, on_finish); } int librados::RadosClient::mgr_command(const vector<string>& cmd, @@ -880,68 +897,80 @@ int librados::RadosClient::mon_command(int rank, const vector<string>& cmd, const bufferlist &inbl, bufferlist *outbl, string *outs) { - ca::waiter<bs::error_code, std::string, ceph::bufferlist> w; - monclient.start_mon_command(rank, cmd, inbl, w); - auto&& [ec, s, bl] = w.wait(); - - if (outs) - *outs = std::move(s); - if (outbl) - *outbl = std::move(bl); - - return ceph::from_error_code(ec); + ceph::mutex mylock = ceph::make_mutex("RadosClient::mon_command::mylock"); + ceph::condition_variable cond; + bool done; + int rval; + { + std::lock_guard l{mylock}; + monclient.start_mon_command(rank, cmd, inbl, outbl, outs, + new C_SafeCond(mylock, cond, &done, &rval)); + } + std::unique_lock l{mylock}; + cond.wait(l, [&done] { return done;}); + return rval; } int librados::RadosClient::mon_command(string name, const vector<string>& cmd, const bufferlist &inbl, bufferlist *outbl, string *outs) { - ca::waiter<bs::error_code, std::string, ceph::bufferlist> w; - monclient.start_mon_command(name, cmd, inbl, w); - auto&& [ec, s, bl] = w.wait(); - - if (outs) - *outs = std::move(s); - if (outbl) - *outbl = std::move(bl); - - return ceph::from_error_code(ec); + ceph::mutex mylock = ceph::make_mutex("RadosClient::mon_command::mylock"); + ceph::condition_variable cond; + bool done; + int rval; + { + std::lock_guard l{mylock}; + monclient.start_mon_command(name, cmd, inbl, outbl, outs, + new C_SafeCond(mylock, cond, &done, &rval)); + } + std::unique_lock l{mylock}; + cond.wait(l, [&done] { return done;}); + return rval; } int librados::RadosClient::osd_command(int osd, vector<string>& cmd, const bufferlist& inbl, bufferlist *poutbl, string *prs) { + ceph::mutex mylock = ceph::make_mutex("RadosClient::osd_command::mylock"); + ceph::condition_variable cond; + bool done; + int ret; ceph_tid_t tid; if (osd < 0) return -EINVAL; - - ca::waiter<bs::error_code, std::string, cb::list> w; - // XXX do anything with tid? - objecter->osd_command(osd, std::move(cmd), cb::list(inbl), &tid, w); - auto [ec, s, bl] = w.wait(); - if (poutbl) - *poutbl = std::move(bl); - if (prs) - *prs = std::move(s); - return ceph::from_error_code(ec); + { + std::lock_guard l{mylock}; + // XXX do anything with tid? + objecter->osd_command(osd, cmd, inbl, &tid, poutbl, prs, + new C_SafeCond(mylock, cond, &done, &ret)); + } + std::unique_lock l{mylock}; + cond.wait(l, [&done] { return done;}); + return ret; } int librados::RadosClient::pg_command(pg_t pgid, vector<string>& cmd, const bufferlist& inbl, bufferlist *poutbl, string *prs) { + ceph::mutex mylock = ceph::make_mutex("RadosClient::pg_command::mylock"); + ceph::condition_variable cond; + bool done; + int ret; ceph_tid_t tid; - ca::waiter<bs::error_code, std::string, cb::list> w; - objecter->pg_command(pgid, std::move(cmd), inbl, &tid, w); - auto [ec, s, bl] = w.wait(); - if (poutbl) - *poutbl = std::move(bl); - if (prs) - *prs = std::move(s); - return ceph::from_error_code(ec); + + { + std::lock_guard l{lock}; + objecter->pg_command(pgid, cmd, inbl, &tid, poutbl, prs, + new C_SafeCond(mylock, cond, &done, &ret)); + } + std::unique_lock l{mylock}; + cond.wait(l, [&done] { return done;}); + return ret; } int librados::RadosClient::monitor_log(const string& level, @@ -1140,24 +1169,3 @@ int librados::RadosClient::get_inconsistent_pgs(int64_t pool_id, } return 0; } - -namespace { -const char *config_keys[] = { - "librados_thread_count", - NULL -}; -} - -const char** librados::RadosClient::get_tracked_conf_keys() const -{ - return config_keys; -} - -void librados::RadosClient::handle_conf_change(const ConfigProxy& conf, - const std::set<std::string> &changed) -{ - if (changed.count("librados_thread_count")) { - poolctx.stop(); - poolctx.start(conf.get_val<std::uint64_t>("librados_thread_count")); - } -} diff --git a/src/librados/RadosClient.h b/src/librados/RadosClient.h index eb97a765faf..0f2b153def4 100644 --- a/src/librados/RadosClient.h +++ b/src/librados/RadosClient.h @@ -14,57 +14,48 @@ #ifndef CEPH_LIBRADOS_RADOSCLIENT_H #define CEPH_LIBRADOS_RADOSCLIENT_H -#include <functional> -#include <memory> -#include <string> - -#include "msg/Dispatcher.h" - -#include "common/async/context_pool.h" #include "common/config_fwd.h" #include "common/Cond.h" +#include "common/Timer.h" #include "common/ceph_mutex.h" #include "common/ceph_time.h" -#include "common/config_obs.h" #include "include/rados/librados.h" #include "include/rados/librados.hpp" #include "mon/MonClient.h" #include "mgr/MgrClient.h" +#include "msg/Dispatcher.h" #include "IoCtxImpl.h" +struct AuthAuthorizer; struct Context; class CephContext; +struct Connection; class Message; class MLog; class Messenger; class AioCompletionImpl; -class librados::RadosClient : public Dispatcher, - public md_config_obs_t +class librados::RadosClient : public Dispatcher { -public: - using Dispatcher::cct; -private: std::unique_ptr<CephContext, - std::function<void(CephContext*)> > cct_deleter{ - cct, [](CephContext *p) {p->put();}}; + std::function<void(CephContext*)> > cct_deleter; public: - const ConfigProxy& conf{cct->_conf}; - ceph::async::io_context_pool poolctx; + using Dispatcher::cct; + const ConfigProxy& conf; private: enum { DISCONNECTED, CONNECTING, CONNECTED, - } state{DISCONNECTED}; + } state; - MonClient monclient{cct, poolctx}; - MgrClient mgrclient{cct, nullptr, &monclient.monmap}; - Messenger *messenger{nullptr}; + MonClient monclient; + MgrClient mgrclient; + Messenger *messenger; - uint64_t instance_id{0}; + uint64_t instance_id; bool _dispatch(Message *m); bool ms_dispatch(Message *m) override; @@ -74,16 +65,17 @@ private: void ms_handle_remote_reset(Connection *con) override; bool ms_handle_refused(Connection *con) override; - Objecter *objecter{nullptr}; + Objecter *objecter; ceph::mutex lock = ceph::make_mutex("librados::RadosClient::lock"); ceph::condition_variable cond; - int refcnt{1}; + SafeTimer timer; + int refcnt; - version_t log_last_version{0}; - rados_log_callback_t log_cb{nullptr}; - rados_log_callback2_t log_cb2{nullptr}; - void *log_cb_arg{nullptr}; + version_t log_last_version; + rados_log_callback_t log_cb; + rados_log_callback2_t log_cb2; + void *log_cb_arg; string log_watch; bool service_daemon = false; @@ -93,11 +85,11 @@ private: int wait_for_osdmap(); public: - boost::asio::io_context::strand finish_strand{poolctx.get_io_context()}; + Finisher finisher; - explicit RadosClient(CephContext *cct); + explicit RadosClient(CephContext *cct_); ~RadosClient() override; - int ping_monitor(std::string mon_id, std::string *result); + int ping_monitor(string mon_id, string *result); int connect(); void shutdown(); @@ -185,9 +177,6 @@ public: mon_feature_t get_required_monitor_features() const; int get_inconsistent_pgs(int64_t pool_id, std::vector<std::string>* pgs); - const char** get_tracked_conf_keys() const override; - void handle_conf_change(const ConfigProxy& conf, - const std::set <std::string> &changed) override; }; #endif diff --git a/src/librados/librados_c.cc b/src/librados/librados_c.cc index bbdd9120955..41cdbf6a42f 100644 --- a/src/librados/librados_c.cc +++ b/src/librados/librados_c.cc @@ -10,7 +10,6 @@ #include "common/common_init.h" #include "common/TracepointProvider.h" #include "common/hobject.h" -#include "common/async/waiter.h" #include "include/rados/librados.h" #include "include/types.h" #include <include/stringify.h> @@ -2005,14 +2004,15 @@ extern "C" int _rados_object_list(rados_ioctx_t io, // Zero out items so that they will be safe to free later memset(result_items, 0, sizeof(rados_object_list_item) * result_item_count); + std::list<librados::ListObjectImpl> result; + hobject_t next_hash; + bufferlist filter_bl; if (filter_buf != nullptr) { filter_bl.append(filter_buf, filter_buf_len); } - ceph::async::waiter<boost::system::error_code, - std::vector<librados::ListObjectImpl>, - hobject_t> w; + C_SaferCond cond; ctx->objecter->enumerate_objects( ctx->poolid, ctx->oloc.nspace, @@ -2020,22 +2020,24 @@ extern "C" int _rados_object_list(rados_ioctx_t io, *((hobject_t*)finish), result_item_count, filter_bl, - w); + &result, + &next_hash, + &cond); hobject_t *next_hobj = (hobject_t*)(*next); ceph_assert(next_hobj); - auto [ec, result, next_hash] = w.wait(); - - if (ec) { + int r = cond.wait(); + if (r < 0) { *next_hobj = hobject_t::get_max(); - return ceph::from_error_code(ec); + return r; } ceph_assert(result.size() <= result_item_count); // Don't overflow! int k = 0; - for (auto i = result.begin(); i != result.end(); ++i) { + for (std::list<librados::ListObjectImpl>::iterator i = result.begin(); + i != result.end(); ++i) { rados_object_list_item &item = result_items[k++]; do_out_buffer(i->oid, &item.oid, &item.oid_length); do_out_buffer(i->nspace, &item.nspace, &item.nspace_length); @@ -2512,7 +2514,7 @@ struct AioGetxattrData { bufferlist bl; char* user_buf; size_t len; - struct librados::CB_AioCompleteAndSafe user_completion; + struct librados::C_AioCompleteAndSafe user_completion; }; static void rados_aio_getxattr_complete(rados_completion_t c, void *arg) { @@ -2527,7 +2529,7 @@ static void rados_aio_getxattr_complete(rados_completion_t c, void *arg) { rc = cdata->bl.length(); } } - cdata->user_completion(rc); + cdata->user_completion.finish(rc); delete cdata; } @@ -2566,7 +2568,7 @@ struct AioGetxattrsData { } librados::RadosXattrsIter *it; rados_xattrs_iter_t *iter; - struct librados::CB_AioCompleteAndSafe user_completion; + struct librados::C_AioCompleteAndSafe user_completion; }; } @@ -2574,12 +2576,12 @@ static void rados_aio_getxattrs_complete(rados_completion_t c, void *arg) { AioGetxattrsData *cdata = reinterpret_cast<AioGetxattrsData*>(arg); int rc = _rados_aio_get_return_value(c); if (rc) { - cdata->user_completion(rc); + cdata->user_completion.finish(rc); } else { cdata->it->i = cdata->it->attrset.begin(); *cdata->iter = cdata->it; cdata->it = 0; - cdata->user_completion(0); + cdata->user_completion.finish(0); } delete cdata; } @@ -3149,7 +3151,7 @@ LIBRADOS_C_API_BASE_DEFAULT(rados_write_op_assert_version); extern "C" void _rados_write_op_assert_exists(rados_write_op_t write_op) { tracepoint(librados, rados_write_op_assert_exists_enter, write_op); - ((::ObjectOperation *)write_op)->stat(nullptr, nullptr, nullptr); + ((::ObjectOperation *)write_op)->stat(NULL, (ceph::real_time *)NULL, NULL); tracepoint(librados, rados_write_op_assert_exists_exit); } LIBRADOS_C_API_BASE_DEFAULT(rados_write_op_assert_exists); @@ -3574,7 +3576,7 @@ LIBRADOS_C_API_BASE_DEFAULT(rados_read_op_assert_version); extern "C" void _rados_read_op_assert_exists(rados_read_op_t read_op) { tracepoint(librados, rados_read_op_assert_exists_enter, read_op); - ((::ObjectOperation *)read_op)->stat(nullptr, nullptr, nullptr); + ((::ObjectOperation *)read_op)->stat(NULL, (ceph::real_time *)NULL, NULL); tracepoint(librados, rados_read_op_assert_exists_exit); } LIBRADOS_C_API_BASE_DEFAULT(rados_read_op_assert_exists); @@ -3800,7 +3802,7 @@ extern "C" void _rados_read_op_getxattrs(rados_read_op_t read_op, tracepoint(librados, rados_read_op_getxattrs_enter, read_op, prval); librados::RadosXattrsIter *xattrs_iter = new librados::RadosXattrsIter; ((::ObjectOperation *)read_op)->getxattrs(&xattrs_iter->attrset, prval); - ((::ObjectOperation *)read_op)->set_handler(new C_XattrsIter(xattrs_iter)); + ((::ObjectOperation *)read_op)->add_handler(new C_XattrsIter(xattrs_iter)); *iter = xattrs_iter; tracepoint(librados, rados_read_op_getxattrs_exit, *iter); } @@ -3824,7 +3826,7 @@ extern "C" void _rados_read_op_omap_get_vals(rados_read_op_t read_op, &omap_iter->values, nullptr, prval); - ((::ObjectOperation *)read_op)->set_handler(new C_OmapIter(omap_iter)); + ((::ObjectOperation *)read_op)->add_handler(new C_OmapIter(omap_iter)); *iter = omap_iter; tracepoint(librados, rados_read_op_omap_get_vals_exit, *iter); } @@ -3849,7 +3851,7 @@ extern "C" void _rados_read_op_omap_get_vals2(rados_read_op_t read_op, &omap_iter->values, (bool*)pmore, prval); - ((::ObjectOperation *)read_op)->set_handler(new C_OmapIter(omap_iter)); + ((::ObjectOperation *)read_op)->add_handler(new C_OmapIter(omap_iter)); *iter = omap_iter; tracepoint(librados, rados_read_op_omap_get_vals_exit, *iter); } @@ -3881,7 +3883,7 @@ extern "C" void _rados_read_op_omap_get_keys(rados_read_op_t read_op, ((::ObjectOperation *)read_op)->omap_get_keys( start_after ? start_after : "", max_return, &ctx->keys, nullptr, prval); - ((::ObjectOperation *)read_op)->set_handler(ctx); + ((::ObjectOperation *)read_op)->add_handler(ctx); *iter = omap_iter; tracepoint(librados, rados_read_op_omap_get_keys_exit, *iter); } @@ -3901,7 +3903,7 @@ extern "C" void _rados_read_op_omap_get_keys2(rados_read_op_t read_op, start_after ? start_after : "", max_return, &ctx->keys, (bool*)pmore, prval); - ((::ObjectOperation *)read_op)->set_handler(ctx); + ((::ObjectOperation *)read_op)->add_handler(ctx); *iter = omap_iter; tracepoint(librados, rados_read_op_omap_get_keys_exit, *iter); } @@ -3916,7 +3918,7 @@ static void internal_rados_read_op_omap_get_vals_by_keys(rados_read_op_t read_op ((::ObjectOperation *)read_op)->omap_get_vals_by_keys(to_get, &omap_iter->values, prval); - ((::ObjectOperation *)read_op)->set_handler(new C_OmapIter(omap_iter)); + ((::ObjectOperation *)read_op)->add_handler(new C_OmapIter(omap_iter)); *iter = omap_iter; } diff --git a/src/librados/librados_cxx.cc b/src/librados/librados_cxx.cc index 4e240fe0c02..a021c26280d 100644 --- a/src/librados/librados_cxx.cc +++ b/src/librados/librados_cxx.cc @@ -21,7 +21,6 @@ #include "common/common_init.h" #include "common/TracepointProvider.h" #include "common/hobject.h" -#include "common/async/waiter.h" #include "include/rados/librados.h" #include "include/rados/librados.hpp" #include "include/types.h" @@ -156,11 +155,10 @@ void librados::ObjectOperation::assert_exists() { ceph_assert(impl); ::ObjectOperation *o = &impl->o; - o->stat(nullptr, nullptr, nullptr); + o->stat(NULL, (ceph::real_time*) NULL, NULL); } -void librados::ObjectOperation::exec(const char *cls, const char *method, - bufferlist& inbl) +void librados::ObjectOperation::exec(const char *cls, const char *method, bufferlist& inbl) { ceph_assert(impl); ::ObjectOperation *o = &impl->o; @@ -1972,7 +1970,7 @@ struct AioGetxattrDataPP { AioGetxattrDataPP(librados::AioCompletionImpl *c, bufferlist *_bl) : bl(_bl), completion(c) {} bufferlist *bl; - struct librados::CB_AioCompleteAndSafe completion; + struct librados::C_AioCompleteAndSafe completion; }; static void rados_aio_getxattr_completepp(rados_completion_t c, void *arg) { @@ -1981,7 +1979,7 @@ static void rados_aio_getxattr_completepp(rados_completion_t c, void *arg) { if (rc >= 0) { rc = cdata->bl->length(); } - cdata->completion(rc); + cdata->completion.finish(rc); delete cdata; } @@ -3004,9 +3002,9 @@ int librados::IoCtx::object_list(const ObjectCursor &start, ceph_assert(next != nullptr); result->clear(); - ceph::async::waiter<boost::system::error_code, - std::vector<librados::ListObjectImpl>, - hobject_t> w; + C_SaferCond cond; + hobject_t next_hash; + std::list<librados::ListObjectImpl> obj_result; io_ctx_impl->objecter->enumerate_objects( io_ctx_impl->poolid, io_ctx_impl->oloc.nspace, @@ -3014,17 +3012,19 @@ int librados::IoCtx::object_list(const ObjectCursor &start, *((hobject_t*)finish.c_cursor), result_item_count, filter, - w); + &obj_result, + &next_hash, + &cond); - auto [ec, obj_result, next_hash] = w.wait(); - if (ec) { + int r = cond.wait(); + if (r < 0) { next->set((rados_object_list_cursor)(new hobject_t(hobject_t::get_max()))); - return ceph::from_error_code(ec); + return r; } next->set((rados_object_list_cursor)(new hobject_t(next_hash))); - for (auto i = obj_result.begin(); + for (std::list<librados::ListObjectImpl>::iterator i = obj_result.begin(); i != obj_result.end(); ++i) { ObjectItem oi; oi.oid = i->oid; diff --git a/src/libradosstriper/MultiAioCompletionImpl.cc b/src/libradosstriper/MultiAioCompletionImpl.cc index acf9e0b6b8b..901bb136664 100644 --- a/src/libradosstriper/MultiAioCompletionImpl.cc +++ b/src/libradosstriper/MultiAioCompletionImpl.cc @@ -58,3 +58,13 @@ void libradosstriper::MultiAioCompletionImpl::finish_adding_requests() if (!pending_safe) safe(); } + +void intrusive_ptr_add_ref(libradosstriper::MultiAioCompletionImpl* ptr) +{ + ptr->get(); +} + +void intrusive_ptr_release(libradosstriper::MultiAioCompletionImpl* ptr) +{ + ptr->put(); +} diff --git a/src/libradosstriper/MultiAioCompletionImpl.h b/src/libradosstriper/MultiAioCompletionImpl.h index 3ac3aae4492..32f7b9a84cf 100644 --- a/src/libradosstriper/MultiAioCompletionImpl.h +++ b/src/libradosstriper/MultiAioCompletionImpl.h @@ -20,9 +20,7 @@ #include "common/ceph_mutex.h" #include "include/radosstriper/libradosstriper.hpp" -namespace libradosstriper { - -struct MultiAioCompletionImpl { +struct libradosstriper::MultiAioCompletionImpl { ceph::mutex lock = ceph::make_mutex("MultiAioCompletionImpl lock", false); ceph::condition_variable cond; @@ -153,17 +151,10 @@ struct MultiAioCompletionImpl { void complete_request(ssize_t r); void safe_request(ssize_t r); void finish_adding_requests(); -}; -inline void intrusive_ptr_add_ref(MultiAioCompletionImpl* ptr) -{ - ptr->get(); -} +}; -inline void intrusive_ptr_release(MultiAioCompletionImpl* ptr) -{ - ptr->put(); -} -} +void intrusive_ptr_add_ref(libradosstriper::MultiAioCompletionImpl*); +void intrusive_ptr_release(libradosstriper::MultiAioCompletionImpl*); #endif // CEPH_LIBRADOSSTRIPERSTRIPER_MULTIAIOCOMPLETIONIMPL_H diff --git a/src/libradosstriper/RadosStriperImpl.h b/src/libradosstriper/RadosStriperImpl.h index 8226a9ba2a2..160db7b6f8d 100644 --- a/src/libradosstriper/RadosStriperImpl.h +++ b/src/libradosstriper/RadosStriperImpl.h @@ -17,8 +17,6 @@ #include <string> -#include <boost/intrusive_ptr.hpp> - #include "include/rados/librados.h" #include "include/rados/librados.hpp" #include "include/radosstriper/libradosstriper.h" @@ -28,7 +26,6 @@ #include "librados/IoCtxImpl.h" #include "librados/AioCompletionImpl.h" #include "common/RefCountedObj.h" -#include "common/ceph_context.h" namespace libradosstriper { diff --git a/src/librbd/Journal.cc b/src/librbd/Journal.cc index 4a32d93c94b..66849c461fa 100644 --- a/src/librbd/Journal.cc +++ b/src/librbd/Journal.cc @@ -1645,7 +1645,7 @@ int Journal<I>::check_resync_requested(bool *do_resync) { decode(client_data, bl_it); } catch (const buffer::error &err) { lderr(cct) << this << " " << __func__ << ": " - << "failed to decode client data: " << err.what() << dendl; + << "failed to decode client data: " << err << dendl; return -EINVAL; } diff --git a/src/mds/CDir.cc b/src/mds/CDir.cc index 540c8461b05..771eb4a890a 100644 --- a/src/mds/CDir.cc +++ b/src/mds/CDir.cc @@ -1903,9 +1903,9 @@ void CDir::_omap_fetched(bufferlist& hdrbl, map<string, bufferlist>& omap, decode(got_fnode, p); } catch (const buffer::error &err) { derr << "Corrupt fnode in dirfrag " << dirfrag() - << ": " << err.what() << dendl; + << ": " << err << dendl; clog->warn() << "Corrupt fnode header in " << dirfrag() << ": " - << err.what() << " (" << get_path() << ")"; + << err << " (" << get_path() << ")"; go_bad(complete); return; } @@ -1971,7 +1971,7 @@ void CDir::_omap_fetched(bufferlist& hdrbl, map<string, bufferlist>& omap, } catch (const buffer::error &err) { cache->mds->clog->warn() << "Corrupt dentry '" << dname << "' in " "dir frag " << dirfrag() << ": " - << err.what() << "(" << get_path() << ")"; + << err << "(" << get_path() << ")"; // Remember that this dentry is damaged. Subsequent operations // that try to act directly on it will get their EIOs, but this @@ -2200,7 +2200,7 @@ void CDir::_omap_commit(int op_prio) // don't create new dirfrag blindly if (!is_new() && !state_test(CDir::STATE_FRAGMENTING)) - op.stat(nullptr, nullptr, nullptr); + op.stat(NULL, (ceph::real_time*) NULL, NULL); if (!to_set.empty()) op.omap_set(to_set); @@ -2238,7 +2238,7 @@ void CDir::_omap_commit(int op_prio) // don't create new dirfrag blindly if (!is_new() && !state_test(CDir::STATE_FRAGMENTING)) - op.stat(nullptr, nullptr, nullptr); + op.stat(NULL, (ceph::real_time*)NULL, NULL); /* * save the header at the last moment.. If we were to send it off before other diff --git a/src/mds/CInode.cc b/src/mds/CInode.cc index 8e917aad64c..e3c4ef1e24a 100644 --- a/src/mds/CInode.cc +++ b/src/mds/CInode.cc @@ -1286,7 +1286,7 @@ void CInode::_fetched(bufferlist& bl, bufferlist& bl2, Context *fin) fin->complete(0); } } catch (buffer::error &err) { - derr << "Corrupt inode " << ino() << ": " << err.what() << dendl; + derr << "Corrupt inode " << ino() << ": " << err << dendl; fin->complete(-EINVAL); return; } diff --git a/src/mds/MDCache.cc b/src/mds/MDCache.cc index 2a9248ab558..c32118dd48c 100644 --- a/src/mds/MDCache.cc +++ b/src/mds/MDCache.cc @@ -8607,7 +8607,7 @@ void MDCache::_open_ino_backtrace_fetched(inodeno_t ino, bufferlist& bl, int err decode(backtrace, bl); } catch (const buffer::error &decode_exc) { derr << "corrupt backtrace on ino x0" << std::hex << ino - << std::dec << ": " << decode_exc.what() << dendl; + << std::dec << ": " << decode_exc << dendl; open_ino_finish(ino, info, -EIO); return; } diff --git a/src/mds/MDSDaemon.cc b/src/mds/MDSDaemon.cc index eb7626d64e5..45356177b99 100644 --- a/src/mds/MDSDaemon.cc +++ b/src/mds/MDSDaemon.cc @@ -61,8 +61,7 @@ #define dout_prefix *_dout << "mds." << name << ' ' // cons/des -MDSDaemon::MDSDaemon(std::string_view n, Messenger *m, MonClient *mc, - boost::asio::io_context& ioctx) : +MDSDaemon::MDSDaemon(std::string_view n, Messenger *m, MonClient *mc) : Dispatcher(m->cct), timer(m->cct, mds_lock), gss_ktfile_client(m->cct->_conf.get_val<std::string>("gss_ktab_client_file")), @@ -70,7 +69,6 @@ MDSDaemon::MDSDaemon(std::string_view n, Messenger *m, MonClient *mc, name(n), messenger(m), monc(mc), - ioctx(ioctx), mgrc(m->cct, m, &mc->monmap), log_client(m->cct, messenger, &mc->monmap, LogClient::NO_FLAGS), starttime(mono_clock::now()) @@ -847,12 +845,10 @@ void MDSDaemon::handle_mds_map(const cref_t<MMDSMap> &m) // Did I previously not hold a rank? Initialize! if (mds_rank == NULL) { - mds_rank = new MDSRankDispatcher( - whoami, mds_lock, clog, - timer, beacon, mdsmap, messenger, monc, &mgrc, - new LambdaContext([this](int r){respawn();}), - new LambdaContext([this](int r){suicide();}), - ioctx); + mds_rank = new MDSRankDispatcher(whoami, mds_lock, clog, + timer, beacon, mdsmap, messenger, monc, &mgrc, + new LambdaContext([this](int r){respawn();}), + new LambdaContext([this](int r){suicide();})); dout(10) << __func__ << ": initializing MDS rank " << mds_rank->get_nodeid() << dendl; mds_rank->init(); diff --git a/src/mds/MDSDaemon.h b/src/mds/MDSDaemon.h index 1b9e79c4543..a4568ee9c73 100644 --- a/src/mds/MDSDaemon.h +++ b/src/mds/MDSDaemon.h @@ -42,9 +42,7 @@ class MonClient; class MDSDaemon : public Dispatcher { public: - MDSDaemon(std::string_view n, Messenger *m, MonClient *mc, - boost::asio::io_context& ioctx); - + MDSDaemon(std::string_view n, Messenger *m, MonClient *mc); ~MDSDaemon() override; mono_time get_starttime() const { @@ -136,7 +134,6 @@ class MDSDaemon : public Dispatcher { Messenger *messenger; MonClient *monc; - boost::asio::io_context& ioctx; MgrClient mgrc; std::unique_ptr<MDSMap> mdsmap; LogClient log_client; diff --git a/src/mds/MDSRank.cc b/src/mds/MDSRank.cc index f214416555b..924768f6bbe 100644 --- a/src/mds/MDSRank.cc +++ b/src/mds/MDSRank.cc @@ -16,7 +16,6 @@ #include "common/debug.h" #include "common/errno.h" -#include "common/async/waiter.h" #include "messages/MClientRequestForward.h" #include "messages/MMDSLoadTargets.h" @@ -485,11 +484,10 @@ MDSRank::MDSRank( MonClient *monc_, MgrClient *mgrc, Context *respawn_hook_, - Context *suicide_hook_, - boost::asio::io_context& ioctx) : + Context *suicide_hook_) : cct(msgr->cct), mds_lock(mds_lock_), clog(clog_), timer(timer_), mdsmap(mdsmap_), - objecter(new Objecter(g_ceph_context, msgr, monc_, ctxpool, 0, 0)), + objecter(new Objecter(g_ceph_context, msgr, monc_, nullptr, 0, 0)), damage_table(whoami_), sessionmap(this), op_tracker(g_ceph_context, g_conf()->mds_enable_op_tracker, g_conf()->osd_num_op_tracker_shard), @@ -580,7 +578,6 @@ MDSRank::~MDSRank() void MDSRankDispatcher::init() { - ctxpool.start(cct->_conf.get_val<std::uint64_t>("mds_asio_thread_count")); objecter->init(); messenger->add_dispatcher_head(objecter); @@ -829,7 +826,6 @@ void MDSRankDispatcher::shutdown() objecter->shutdown(); monc->shutdown(); - ctxpool.finish(); op_tracker.on_shutdown(); @@ -1654,6 +1650,7 @@ void MDSRank::calc_recovery_set() dout(1) << " recovery set is " << rs << dendl; } + void MDSRank::replay_start() { dout(1) << "replay_start" << dendl; @@ -1664,13 +1661,18 @@ void MDSRank::replay_start() calc_recovery_set(); // Check if we need to wait for a newer OSD map before starting - auto fin = new C_IO_Wrapper( - this, new C_MDS_BootStart(this, MDS_BOOT_INITIAL)); - objecter->wait_for_map( - mdsmap->get_last_failure_osd_epoch(), lambdafy(fin)); - - dout(1) << " waiting for osdmap " << mdsmap->get_last_failure_osd_epoch() - << " (which blacklists prior instance)" << dendl; + Context *fin = new C_IO_Wrapper(this, new C_MDS_BootStart(this, MDS_BOOT_INITIAL)); + bool const ready = objecter->wait_for_map( + mdsmap->get_last_failure_osd_epoch(), + fin); + + if (ready) { + delete fin; + boot_start(); + } else { + dout(1) << " waiting for osdmap " << mdsmap->get_last_failure_osd_epoch() + << " (which blacklists prior instance)" << dendl; + } } @@ -1721,11 +1723,23 @@ void MDSRank::standby_replay_restart() /* We are transitioning out of standby: wait for OSD map update before making final pass */ dout(1) << "standby_replay_restart (final takeover pass)" << dendl; - auto fin = new C_IO_Wrapper( - this, new C_MDS_StandbyReplayRestart(this)); - objecter->wait_for_map(mdsmap->get_last_failure_osd_epoch(), lambdafy(fin)); - dout(1) << " waiting for osdmap " << mdsmap->get_last_failure_osd_epoch() - << " (which blacklists prior instance)" << dendl; + Context *fin = new C_IO_Wrapper(this, new C_MDS_StandbyReplayRestart(this)); + bool ready = objecter->wait_for_map(mdsmap->get_last_failure_osd_epoch(), fin); + if (ready) { + delete fin; + mdlog->get_journaler()->reread_head_and_probe( + new C_MDS_StandbyReplayRestartFinish( + this, + mdlog->get_journaler()->get_read_pos())); + + dout(1) << " opening purge_queue (async)" << dendl; + purge_queue.open(NULL); + dout(1) << " opening open_file_table (async)" << dendl; + mdcache->open_file_table.load(nullptr); + } else { + dout(1) << " waiting for osdmap " << mdsmap->get_last_failure_osd_epoch() + << " (which blacklists prior instance)" << dendl; + } } } @@ -2438,10 +2452,12 @@ int MDSRankDispatcher::handle_asok_command(std::string_view command, std::lock_guard l(mds_lock); set_osd_epoch_barrier(target_epoch); } - ceph::async::waiter<boost::system::error_code> w; - objecter->wait_for_map(target_epoch, w); - dout(4) << __func__ << ": waiting for OSD epoch " << target_epoch << dendl; - w.wait(); + C_SaferCond cond; + bool already_got = objecter->wait_for_map(target_epoch, &cond); + if (!already_got) { + dout(4) << __func__ << ": waiting for OSD epoch " << target_epoch << dendl; + cond.wait(); + } } else if (command == "session ls") { std::lock_guard l(mds_lock); @@ -3388,7 +3404,7 @@ bool MDSRank::evict_client(int64_t session_id, Context *on_blacklist_done = new LambdaContext([this, fn](int r) { objecter->wait_for_latest_osdmap( - lambdafy((new C_OnFinisher( + new C_OnFinisher( new LambdaContext([this, fn](int r) { std::lock_guard l(mds_lock); auto epoch = objecter->with_osdmap([](const OSDMap &o){ @@ -3399,7 +3415,7 @@ bool MDSRank::evict_client(int64_t session_id, fn(); }), finisher) - ))); + ); }); dout(4) << "Sending mon blacklist command: " << cmd[0] << dendl; @@ -3466,10 +3482,9 @@ MDSRankDispatcher::MDSRankDispatcher( MonClient *monc_, MgrClient *mgrc, Context *respawn_hook_, - Context *suicide_hook_, - boost::asio::io_context& ictx) + Context *suicide_hook_) : MDSRank(whoami_, mds_lock_, clog_, timer_, beacon_, mdsmap_, - msgr, monc_, mgrc, respawn_hook_, suicide_hook_, ictx) + msgr, monc_, mgrc, respawn_hook_, suicide_hook_) { g_conf().add_observer(this); } @@ -3646,7 +3661,6 @@ const char** MDSRankDispatcher::get_tracked_conf_keys() const "mds_recall_warning_decay_rate", "mds_request_load_average_decay_rate", "mds_session_cache_liveness_decay_rate", - "mds_asio_thread_count", NULL }; return KEYS; @@ -3688,11 +3702,6 @@ void MDSRankDispatcher::handle_conf_change(const ConfigProxy& conf, const std::s mdcache->handle_conf_change(changed, *mdsmap); purge_queue.handle_conf_change(changed, *mdsmap); })); - - if (changed.count("mds_asio_thread_count")) { - ctxpool.stop(); - ctxpool.start(conf.get_val<std::uint64_t>("mds_asio_thread_count")); - } } void MDSRank::get_task_status(std::map<std::string, std::string> *status) { diff --git a/src/mds/MDSRank.h b/src/mds/MDSRank.h index fac6b08e47e..4187ee7c5ec 100644 --- a/src/mds/MDSRank.h +++ b/src/mds/MDSRank.h @@ -17,7 +17,6 @@ #include <string_view> -#include "common/async/context_pool.h" #include "common/DecayCounter.h" #include "common/LogClient.h" #include "common/Timer.h" @@ -152,8 +151,7 @@ class MDSRank { MonClient *monc_, MgrClient *mgrc, Context *respawn_hook_, - Context *suicide_hook_, - boost::asio::io_context& ictx); + Context *suicide_hook_); mds_rank_t get_nodeid() const { return whoami; } int64_t get_metadata_pool(); @@ -356,7 +354,6 @@ class MDSRank { std::unique_ptr<MDSMap> &mdsmap; /* MDSDaemon::mdsmap */ - ceph::async::io_context_pool ctxpool; Objecter *objecter; // sub systems @@ -630,8 +627,7 @@ public: MonClient *monc_, MgrClient *mgrc, Context *respawn_hook_, - Context *suicide_hook_, - boost::asio::io_context& ictx); + Context *suicide_hook_); void init(); void tick(); diff --git a/src/mds/PurgeQueue.h b/src/mds/PurgeQueue.h index 7e3f093c3d8..7f42ac05be9 100644 --- a/src/mds/PurgeQueue.h +++ b/src/mds/PurgeQueue.h @@ -16,7 +16,6 @@ #define PURGE_QUEUE_H_ #include "include/compact_set.h" -#include "common/Finisher.h" #include "mds/MDSMap.h" #include "osdc/Journaler.h" diff --git a/src/mds/Server.cc b/src/mds/Server.cc index c1017e96d31..2e50ccbdb7d 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -5347,18 +5347,29 @@ int Server::check_layout_vxattr(MDRequestRef& mdr, if (req_epoch > epoch) { // well, our map is older. consult mds. - auto fin = new C_IO_Wrapper(mds, new C_MDS_RetryRequest(mdcache, mdr)); + Context *fin = new C_IO_Wrapper(mds, new C_MDS_RetryRequest(mdcache, mdr)); + + if (!mds->objecter->wait_for_map(req_epoch, fin)) + return r; // wait, fin will retry this request later + + delete fin; + + // now we have at least as new a map as the client, try again. + mds->objecter->with_osdmap([&](const OSDMap& osdmap) { + r = parse_layout_vxattr(name, value, osdmap, layout); + epoch = osdmap.get_epoch(); + }); + + ceph_assert(epoch >= req_epoch); // otherwise wait_for_map() told a lie - mds->objecter->wait_for_map(req_epoch, lambdafy(fin)); - return r; } else if (req_epoch == 0 && !mdr->waited_for_osdmap) { // For compatibility with client w/ old code, we still need get the // latest map. One day if COMPACT_VERSION of MClientRequest >=3, // we can remove those code. mdr->waited_for_osdmap = true; - mds->objecter->wait_for_latest_osdmap(std::ref(*new C_IO_Wrapper( - mds, new C_MDS_RetryRequest(mdcache, mdr)))); + mds->objecter->wait_for_latest_osdmap(new C_IO_Wrapper( + mds, new C_MDS_RetryRequest(mdcache, mdr))); return r; } } diff --git a/src/messages/MGetPoolStats.h b/src/messages/MGetPoolStats.h index 6b64e4feee2..51bc134a21f 100644 --- a/src/messages/MGetPoolStats.h +++ b/src/messages/MGetPoolStats.h @@ -21,10 +21,10 @@ class MGetPoolStats : public PaxosServiceMessage { public: uuid_d fsid; - std::vector<std::string> pools; + std::list<std::string> pools; MGetPoolStats() : PaxosServiceMessage{MSG_GETPOOLSTATS, 0} {} - MGetPoolStats(const uuid_d& f, ceph_tid_t t, std::vector<std::string>& ls, version_t l) : + MGetPoolStats(const uuid_d& f, ceph_tid_t t, std::list<std::string>& ls, version_t l) : PaxosServiceMessage{MSG_GETPOOLSTATS, l}, fsid(f), pools(ls) { set_tid(t); diff --git a/src/messages/MGetPoolStatsReply.h b/src/messages/MGetPoolStatsReply.h index 063b6f7cb28..ff474d3d5db 100644 --- a/src/messages/MGetPoolStatsReply.h +++ b/src/messages/MGetPoolStatsReply.h @@ -22,7 +22,7 @@ class MGetPoolStatsReply : public PaxosServiceMessage { public: uuid_d fsid; - boost::container::flat_map<std::string, pool_stat_t> pool_stats; + std::map<std::string,pool_stat_t> pool_stats; bool per_pool = false; MGetPoolStatsReply() : PaxosServiceMessage{MSG_GETPOOLSTATSREPLY, 0, diff --git a/src/messages/MOSDOp.h b/src/messages/MOSDOp.h index 5301f0a43b2..43bd4005469 100644 --- a/src/messages/MOSDOp.h +++ b/src/messages/MOSDOp.h @@ -30,10 +30,8 @@ * */ -class MOSDOpReply; +class OSD; -namespace _mosdop { -template<typename V> class MOSDOp : public MOSDFastDispatchOp { private: static constexpr int HEAD_VERSION = 8; @@ -56,7 +54,7 @@ private: std::atomic<bool> final_decode_needed; // public: - V ops; + std::vector<OSDOp> ops; private: snapid_t snap_seq; std::vector<snapid_t> snaps; @@ -66,7 +64,7 @@ private: osd_reqid_t reqid; // reqid explicitly set by sender public: - friend MOSDOpReply; + friend class MOSDOpReply; ceph_tid_t get_client_tid() { return header.tid; } void set_snapid(const snapid_t& s) { @@ -600,9 +598,6 @@ private: template<class T, typename... Args> friend boost::intrusive_ptr<T> ceph::make_message(Args&&... args); }; -} - -using MOSDOp = _mosdop::MOSDOp<std::vector<OSDOp>>; #endif diff --git a/src/mgr/BaseMgrModule.cc b/src/mgr/BaseMgrModule.cc index d18b35e947e..b340f74f1a1 100644 --- a/src/mgr/BaseMgrModule.cc +++ b/src/mgr/BaseMgrModule.cc @@ -154,9 +154,10 @@ ceph_send_command(BaseMgrModule *self, PyObject *args) // can wait for those. auto c = new LambdaContext([command_c, self](int command_r){ self->py_modules->get_objecter().wait_for_latest_osdmap( - [command_c, command_r](boost::system::error_code) { - command_c->complete(command_r); - }); + new LambdaContext([command_c, command_r](int wait_r){ + command_c->complete(command_r); + }) + ); }); self->py_modules->get_monc().start_mon_command( @@ -184,12 +185,9 @@ ceph_send_command(BaseMgrModule *self, PyObject *args) {cmd_json}, {}, &tid, - [command_c, f = &self->py_modules->cmd_finisher] - (boost::system::error_code ec, std::string s, ceph::buffer::list bl) { - command_c->outs = std::move(s); - command_c->outbl = std::move(bl); - f->queue(command_c); - }); + &command_c->outbl, + &command_c->outs, + new C_OnFinisher(command_c, &self->py_modules->cmd_finisher)); } else if (std::string(type) == "mds") { int r = self->py_modules->get_client().mds_command( name, @@ -222,12 +220,9 @@ ceph_send_command(BaseMgrModule *self, PyObject *args) {cmd_json}, {}, &tid, - [command_c, f = &self->py_modules->cmd_finisher] - (boost::system::error_code ec, std::string s, ceph::buffer::list bl) { - command_c->outs = std::move(s); - command_c->outbl = std::move(bl); - f->queue(command_c); - }); + &command_c->outbl, + &command_c->outs, + new C_OnFinisher(command_c, &self->py_modules->cmd_finisher)); PyEval_RestoreThread(tstate); return nullptr; } else { diff --git a/src/mgr/MgrContext.h b/src/mgr/MgrContext.h index c6e647365b5..bec51a36871 100644 --- a/src/mgr/MgrContext.h +++ b/src/mgr/MgrContext.h @@ -17,7 +17,6 @@ #include <memory> #include "common/ceph_json.h" -#include "common/Cond.h" #include "mon/MonClient.h" class Command diff --git a/src/mgr/MgrStandby.cc b/src/mgr/MgrStandby.cc index 913009e7e10..b021a182971 100644 --- a/src/mgr/MgrStandby.cc +++ b/src/mgr/MgrStandby.cc @@ -38,7 +38,7 @@ MgrStandby::MgrStandby(int argc, const char **argv) : Dispatcher(g_ceph_context), - monc{g_ceph_context, poolctx}, + monc{g_ceph_context}, client_messenger(Messenger::create( g_ceph_context, cct->_conf.get_val<std::string>("ms_type"), @@ -46,7 +46,7 @@ MgrStandby::MgrStandby(int argc, const char **argv) : "mgr", getpid(), 0)), - objecter{g_ceph_context, client_messenger.get(), &monc, poolctx, 0, 0}, + objecter{g_ceph_context, client_messenger.get(), &monc, NULL, 0, 0}, client{client_messenger.get(), &monc, &objecter}, mgrc(g_ceph_context, client_messenger.get(), &monc.monmap), log_client(g_ceph_context, client_messenger.get(), &monc.monmap, LogClient::NO_FLAGS), @@ -115,8 +115,6 @@ int MgrStandby::init() client_messenger->add_dispatcher_tail(&client); client_messenger->start(); - poolctx.start(2); - // Initialize MonClient if (monc.build_initial_monmap() < 0) { client_messenger->shutdown(); @@ -171,7 +169,6 @@ int MgrStandby::init() // this method. monc.set_passthrough_monmap(); - poolctx.start(1); client_t whoami = monc.get_global_id(); client_messenger->set_myname(entity_name_t::MGR(whoami.v)); monc.set_log_client(&log_client); @@ -282,31 +279,17 @@ void MgrStandby::shutdown() } py_module_registry.shutdown(); - // stop sending beacon first, i use monc to talk with monitors - timer.shutdown(); - // client uses monc and objecter - client.shutdown(); - mgrc.shutdown(); - // Stop asio threads, so leftover events won't call into shut down - // monclient/objecter. - poolctx.finish(); - // stop monc, so mon won't be able to instruct me to shutdown/activate after - // the active_mgr is stopped - monc.shutdown(); - if (active_mgr) { - active_mgr->shutdown(); - } + // objecter is used by monc and active_mgr objecter.shutdown(); // client_messenger is used by all of them, so stop it in the end client_messenger->shutdown(); })); - // objecter is used by monc and active_mgr - objecter.shutdown(); - // client_messenger is used by all of them, so stop it in the end - client_messenger->shutdown(); - poolctx.finish(); + // Then stop the finisher to ensure its enqueued contexts aren't going + // to touch references to the things we're about to tear down + finisher.wait_for_empty(); + finisher.stop(); } void MgrStandby::respawn() diff --git a/src/mgr/MgrStandby.h b/src/mgr/MgrStandby.h index cac31a57640..d79fef2d5e5 100644 --- a/src/mgr/MgrStandby.h +++ b/src/mgr/MgrStandby.h @@ -16,7 +16,6 @@ #define MGR_STANDBY_H_ #include "auth/Auth.h" -#include "common/async/context_pool.h" #include "common/Finisher.h" #include "common/Timer.h" #include "common/LogClient.h" @@ -40,7 +39,6 @@ public: const std::set <std::string> &changed) override; protected: - ceph::async::io_context_pool poolctx; MonClient monc; std::unique_ptr<Messenger> client_messenger; Objecter objecter; diff --git a/src/mon/AuthMonitor.cc b/src/mon/AuthMonitor.cc index aee0e33a4ea..3cb261b412a 100644 --- a/src/mon/AuthMonitor.cc +++ b/src/mon/AuthMonitor.cc @@ -1773,7 +1773,7 @@ bool AuthMonitor::_upgrade_format_to_dumpling() // set daemon profiles if ((p->first.is_osd() || p->first.is_mds()) && mon_caps == "allow rwx") { - new_caps = string("allow profile ") + std::string(p->first.get_type_name()); + new_caps = string("allow profile ") + p->first.get_type_name(); } // update bootstrap keys diff --git a/src/mon/ConfigMap.cc b/src/mon/ConfigMap.cc index 696b18edbc4..b7343ce4264 100644 --- a/src/mon/ConfigMap.cc +++ b/src/mon/ConfigMap.cc @@ -115,7 +115,7 @@ ConfigMap::generate_entity_map( vector<pair<string,Section*>> sections = { make_pair("global", &global) }; auto p = by_type.find(name.get_type_name()); if (p != by_type.end()) { - sections.emplace_back(name.get_type_name(), &p->second); + sections.push_back(make_pair(name.get_type_name(), &p->second)); } vector<std::string> name_bits; boost::split(name_bits, name.to_str(), [](char c){ return c == '.'; }); diff --git a/src/mon/ConfigMap.h b/src/mon/ConfigMap.h index 2b16c43eef3..17b52af1d1d 100644 --- a/src/mon/ConfigMap.h +++ b/src/mon/ConfigMap.h @@ -97,8 +97,8 @@ struct Section { struct ConfigMap { Section global; - std::map<std::string,Section, std::less<>> by_type; - std::map<std::string,Section, std::less<>> by_id; + std::map<std::string,Section> by_type; + std::map<std::string,Section> by_id; Section *find_section(const std::string& name) { if (name == "global") { diff --git a/src/mon/MonClient.cc b/src/mon/MonClient.cc index 63e3d5cfa3c..dbb4287a2a2 100644 --- a/src/mon/MonClient.cc +++ b/src/mon/MonClient.cc @@ -26,7 +26,6 @@ #include "messages/MMonGetMap.h" #include "messages/MMonGetVersion.h" -#include "messages/MMonGetMap.h" #include "messages/MMonGetVersionReply.h" #include "messages/MMonMap.h" #include "messages/MConfig.h" @@ -47,7 +46,6 @@ #include "common/LogClient.h" #include "MonClient.h" -#include "error_code.h" #include "MonMap.h" #include "auth/Auth.h" @@ -60,16 +58,14 @@ #undef dout_prefix #define dout_prefix *_dout << "monclient" << (_hunting() ? "(hunting)":"") << ": " -namespace bs = boost::system; using std::string; -using namespace std::literals; -MonClient::MonClient(CephContext *cct_, boost::asio::io_context& service) : +MonClient::MonClient(CephContext *cct_) : Dispatcher(cct_), AuthServer(cct_), messenger(NULL), timer(cct_, monc_lock), - service(service), + finisher(cct_), initialized(false), log_client(NULL), more_log_pending(false), @@ -99,7 +95,7 @@ int MonClient::get_monmap() { ldout(cct, 10) << __func__ << dendl; std::unique_lock l(monc_lock); - + sub.want("monmap", 0, 0); if (!_opened()) _reopen_session(); @@ -436,18 +432,13 @@ void MonClient::handle_monmap(MMonMap *m) void MonClient::handle_config(MConfig *m) { ldout(cct,10) << __func__ << " " << *m << dendl; - // Take the sledgehammer approach to ensuring we don't depend on - // anything in MonClient. - boost::asio::defer(finish_strand, - [m, cct = boost::intrusive_ptr<CephContext>(cct), - config_notify_cb = config_notify_cb, - config_cb = config_cb]() { - cct->_conf.set_mon_vals(cct.get(), m->config, config_cb); - if (config_notify_cb) { - config_notify_cb(); - } - m->put(); - }); + finisher.queue(new LambdaContext([this, m](int r) { + cct->_conf.set_mon_vals(cct, m->config, config_cb); + if (config_notify_cb) { + config_notify_cb(); + } + m->put(); + })); got_config = true; map_cond.notify_all(); } @@ -487,6 +478,7 @@ int MonClient::init() messenger->add_dispatcher_head(this); timer.init(); + finisher.start(); schedule_tick(); return 0; @@ -498,10 +490,10 @@ void MonClient::shutdown() monc_lock.lock(); stopping = true; while (!version_requests.empty()) { - ceph::async::defer(std::move(version_requests.begin()->second), - monc_errc::shutting_down, 0, 0); + version_requests.begin()->second->context->complete(-ECANCELED); ldout(cct, 20) << __func__ << " canceling and discarding version request " - << version_requests.begin()->first << dendl; + << version_requests.begin()->second << dendl; + delete version_requests.begin()->second; version_requests.erase(version_requests.begin()); } while (!mon_commands.empty()) { @@ -519,6 +511,8 @@ void MonClient::shutdown() monc_lock.unlock(); if (initialized) { + finisher.wait_for_empty(); + finisher.stop(); initialized = false; } monc_lock.lock(); @@ -702,8 +696,8 @@ void MonClient::_reopen_session(int rank) // throw out version check requests while (!version_requests.empty()) { - ceph::async::defer(std::move(version_requests.begin()->second), - monc_errc::session_reset, 0, 0); + finisher.queue(version_requests.begin()->second->context, -EAGAIN); + delete version_requests.begin()->second; version_requests.erase(version_requests.begin()); } @@ -1087,9 +1081,10 @@ void MonClient::_send_command(MonCommand *r) if (r->is_tell()) { ++r->send_attempts; if (r->send_attempts > cct->_conf->mon_client_directed_command_retry) { - _finish_command(r, monc_errc::mon_unavailable, "mon unavailable", {}); + _finish_command(r, -ENXIO, "mon unavailable"); return; } + // tell-style command if (monmap.min_mon_release >= ceph_release_t::octopus) { if (r->target_con) { @@ -1099,7 +1094,7 @@ void MonClient::_send_command(MonCommand *r) if (r->target_rank >= (int)monmap.size()) { ldout(cct, 10) << " target " << r->target_rank << " >= max mon " << monmap.size() << dendl; - _finish_command(r, monc_errc::rank_dne, "mon rank dne"sv, {}); + _finish_command(r, -ENOENT, "mon rank dne"); return; } r->target_con = messenger->connect_to_mon( @@ -1108,7 +1103,7 @@ void MonClient::_send_command(MonCommand *r) if (!monmap.contains(r->target_name)) { ldout(cct, 10) << " target " << r->target_name << " not present in monmap" << dendl; - _finish_command(r, monc_errc::mon_dne, "mon dne"sv, {}); + _finish_command(r, -ENOENT, "mon dne"); return; } r->target_con = messenger->connect_to_mon( @@ -1143,7 +1138,7 @@ void MonClient::_send_command(MonCommand *r) if (r->target_rank >= (int)monmap.size()) { ldout(cct, 10) << " target " << r->target_rank << " >= max mon " << monmap.size() << dendl; - _finish_command(r, monc_errc::rank_dne, "mon rank dne"sv, {}); + _finish_command(r, -ENOENT, "mon rank dne"); return; } _reopen_session(r->target_rank); @@ -1158,7 +1153,7 @@ void MonClient::_send_command(MonCommand *r) if (!monmap.contains(r->target_name)) { ldout(cct, 10) << " target " << r->target_name << " not present in monmap" << dendl; - _finish_command(r, monc_errc::mon_dne, "mon dne"sv, {}); + _finish_command(r, -ENOENT, "mon dne"); return; } _reopen_session(monmap.get_rank(r->target_name)); @@ -1229,10 +1224,9 @@ void MonClient::handle_mon_command_ack(MMonCommandAck *ack) } ldout(cct, 10) << __func__ << " " << r->tid << " " << r->cmd << dendl; - auto ec = ack->r < 0 ? bs::error_code(-ack->r, mon_category()) - : bs::error_code(); - _finish_command(r, ec, ack->rs, - std::move(ack->get_data())); + if (r->poutbl) + r->poutbl->claim(ack->get_data()); + _finish_command(r, ack->r, ack->rs); ack->put(); } @@ -1257,9 +1251,9 @@ void MonClient::handle_command_reply(MCommandReply *reply) } ldout(cct, 10) << __func__ << " " << r->tid << " " << r->cmd << dendl; - auto ec = reply->r < 0 ? bs::error_code(-reply->r, mon_category()) - : bs::error_code(); - _finish_command(r, ec, reply->rs, std::move(reply->get_data())); + if (r->poutbl) + r->poutbl->claim(reply->get_data()); + _finish_command(r, reply->r, reply->rs); reply->put(); } @@ -1276,17 +1270,19 @@ int MonClient::_cancel_mon_command(uint64_t tid) ldout(cct, 10) << __func__ << " tid " << tid << dendl; MonCommand *cmd = it->second; - _finish_command(cmd, monc_errc::timed_out, "timed out"sv, {}); + _finish_command(cmd, -ETIMEDOUT, ""); return 0; } -void MonClient::_finish_command(MonCommand *r, bs::error_code ret, - std::string_view rs, ceph::buffer::list&& bl) +void MonClient::_finish_command(MonCommand *r, int ret, string rs) { - ldout(cct, 10) << __func__ << " " << r->tid << " = " << ret << " " << rs - << dendl; - ceph::async::defer(std::move(r->onfinish), ret, std::string(rs), - std::move(bl)); + ldout(cct, 10) << __func__ << " " << r->tid << " = " << ret << " " << rs << dendl; + if (r->prval) + *(r->prval) = ret; + if (r->prs) + *(r->prs) = rs; + if (r->onfinish) + finisher.queue(r->onfinish, ret); if (r->target_con) { r->target_con->mark_down(); } @@ -1294,8 +1290,117 @@ void MonClient::_finish_command(MonCommand *r, bs::error_code ret, delete r; } +void MonClient::start_mon_command(const std::vector<string>& cmd, + const ceph::buffer::list& inbl, + ceph::buffer::list *outbl, string *outs, + Context *onfinish) +{ + ldout(cct,10) << __func__ << " cmd=" << cmd << dendl; + std::lock_guard l(monc_lock); + if (!initialized || stopping) { + if (onfinish) { + onfinish->complete(-ECANCELED); + } + return; + } + MonCommand *r = new MonCommand(++last_mon_command_tid); + r->cmd = cmd; + r->inbl = inbl; + r->poutbl = outbl; + r->prs = outs; + r->onfinish = onfinish; + if (cct->_conf->rados_mon_op_timeout > 0) { + class C_CancelMonCommand : public Context + { + uint64_t tid; + MonClient *monc; + public: + C_CancelMonCommand(uint64_t tid, MonClient *monc) : tid(tid), monc(monc) {} + void finish(int r) override { + monc->_cancel_mon_command(tid); + } + }; + r->ontimeout = new C_CancelMonCommand(r->tid, this); + timer.add_event_after(cct->_conf->rados_mon_op_timeout, r->ontimeout); + } + mon_commands[r->tid] = r; + _send_command(r); +} + +void MonClient::start_mon_command(const string &mon_name, + const std::vector<string>& cmd, + const ceph::buffer::list& inbl, + ceph::buffer::list *outbl, string *outs, + Context *onfinish) +{ + ldout(cct,10) << __func__ << " mon." << mon_name << " cmd=" << cmd << dendl; + std::lock_guard l(monc_lock); + if (!initialized || stopping) { + if (onfinish) { + onfinish->complete(-ECANCELED); + } + return; + } + MonCommand *r = new MonCommand(++last_mon_command_tid); + + // detect/tolerate mon *rank* passed as a string + string err; + int rank = strict_strtoll(mon_name.c_str(), 10, &err); + if (err.size() == 0 && rank >= 0) { + ldout(cct,10) << __func__ << " interpreting name '" << mon_name + << "' as rank " << rank << dendl; + r->target_rank = rank; + } else { + r->target_name = mon_name; + } + r->cmd = cmd; + r->inbl = inbl; + r->poutbl = outbl; + r->prs = outs; + r->onfinish = onfinish; + mon_commands[r->tid] = r; + _send_command(r); +} + +void MonClient::start_mon_command(int rank, + const std::vector<string>& cmd, + const ceph::buffer::list& inbl, + ceph::buffer::list *outbl, string *outs, + Context *onfinish) +{ + ldout(cct,10) << __func__ << " rank " << rank << " cmd=" << cmd << dendl; + std::lock_guard l(monc_lock); + if (!initialized || stopping) { + if (onfinish) { + onfinish->complete(-ECANCELED); + } + return; + } + MonCommand *r = new MonCommand(++last_mon_command_tid); + r->target_rank = rank; + r->cmd = cmd; + r->inbl = inbl; + r->poutbl = outbl; + r->prs = outs; + r->onfinish = onfinish; + mon_commands[r->tid] = r; + _send_command(r); +} + // --------- +void MonClient::get_version(string map, version_t *newest, version_t *oldest, Context *onfinish) +{ + version_req_d *req = new version_req_d(onfinish, newest, oldest); + ldout(cct, 10) << "get_version " << map << " req " << req << dendl; + std::lock_guard l(monc_lock); + auto m = ceph::make_message<MMonGetVersion>(); + m->what = map; + m->handle = ++version_req_id; + version_requests[m->handle] = req; + _send_mon_message(std::move(m)); +} + void MonClient::handle_get_version_reply(MMonGetVersionReply* m) { ceph_assert(ceph_mutex_is_locked(monc_lock)); @@ -1304,12 +1409,15 @@ void MonClient::handle_get_version_reply(MMonGetVersionReply* m) ldout(cct, 0) << __func__ << " version request with handle " << m->handle << " not found" << dendl; } else { - auto req = std::move(iter->second); - ldout(cct, 10) << __func__ << " finishing " << iter->first << " version " - << m->version << dendl; + version_req_d *req = iter->second; + ldout(cct, 10) << __func__ << " finishing " << req << " version " << m->version << dendl; version_requests.erase(iter); - ceph::async::defer(std::move(req), bs::error_code(), - m->version, m->oldest_version); + if (req->newest) + *req->newest = m->version; + if (req->oldest) + *req->oldest = m->oldest_version; + finisher.queue(req->context, 0); + delete req; } m->put(); } @@ -1479,8 +1587,7 @@ int MonClient::handle_auth_bad_method( allowed_methods, allowed_modes); if (r < 0) { - auto ec = bs::error_code(-r, mon_category()); - _finish_command(i.second, ec, "auth failed"sv, {}); + _finish_command(i.second, r, "auth failed"); } return r; } @@ -1889,97 +1996,3 @@ void MonClient::register_config_callback(md_config_t::config_callback fn) { md_config_t::config_callback MonClient::get_config_callback() { return config_cb; } - -class monc_error_category : public ceph::converting_category { -public: - monc_error_category(){} - const char* name() const noexcept override; - std::string message(int ev) const override; - bs::error_condition default_error_condition(int ev) const noexcept - override; - bool equivalent(int ev, const bs::error_condition& c) const - noexcept override; - using ceph::converting_category::equivalent; - int from_code(int ev) const noexcept override; -}; - -const char* monc_error_category::name() const noexcept { - return "monc"; -} - -std::string monc_error_category::message(int ev) const { - if (ev == 0) - return "No error"; - - switch (static_cast<monc_errc>(ev)) { - case monc_errc::shutting_down: // Command failed due to MonClient shutting down - return "Command failed due to MonClient shutting down"; - case monc_errc::session_reset: - return "Monitor session was reset"; - case monc_errc::rank_dne: - return "Requested monitor rank does not exist"; - case monc_errc::mon_dne: - return "Requested monitor does not exist"; - case monc_errc::timed_out: - return "Monitor operation timed out"; - case monc_errc::mon_unavailable: - return "Monitor unavailable"; - } - - return "Unknown error"; -} - -bs::error_condition monc_error_category::default_error_condition(int ev) const noexcept { - switch (static_cast<monc_errc>(ev)) { - case monc_errc::shutting_down: - return bs::errc::operation_canceled; - case monc_errc::session_reset: - return bs::errc::resource_unavailable_try_again; - case monc_errc::rank_dne: - [[fallthrough]]; - case monc_errc::mon_dne: - return ceph::errc::not_in_map; - case monc_errc::timed_out: - return bs::errc::timed_out; - case monc_errc::mon_unavailable: - return bs::errc::no_such_device; - } - return { ev, *this }; -} - -bool monc_error_category::equivalent(int ev, const bs::error_condition& c) const noexcept { - switch (static_cast<monc_errc>(ev)) { - case monc_errc::rank_dne: - [[fallthrough]]; - case monc_errc::mon_dne: - return c == bs::errc::no_such_file_or_directory; - default: - return default_error_condition(ev) == c; - } -} - -int monc_error_category::from_code(int ev) const noexcept { - if (ev == 0) - return 0; - - switch (static_cast<monc_errc>(ev)) { - case monc_errc::shutting_down: - return -ECANCELED; - case monc_errc::session_reset: - return -EAGAIN; - case monc_errc::rank_dne: - [[fallthrough]]; - case monc_errc::mon_dne: - return -ENOENT; - case monc_errc::timed_out: - return -ETIMEDOUT; - case monc_errc::mon_unavailable: - return -ENXIO; - } - return -EDOM; -} - -const bs::error_category& monc_category() noexcept { - static const monc_error_category c; - return c; -} diff --git a/src/mon/MonClient.h b/src/mon/MonClient.h index 2d97440df8f..52c55fb18f3 100644 --- a/src/mon/MonClient.h +++ b/src/mon/MonClient.h @@ -27,10 +27,9 @@ #include "MonMap.h" #include "MonSub.h" -#include "common/async/completion.h" #include "common/Timer.h" +#include "common/Finisher.h" #include "common/config.h" -#include "messages/MMonGetVersion.h" #include "auth/AuthClient.h" #include "auth/AuthServer.h" @@ -38,8 +37,11 @@ class MMonMap; class MConfig; class MMonGetVersionReply; +struct MMonSubscribeAck; class MMonCommandAck; +struct MAuthReply; class LogClient; +class AuthAuthorizer; class AuthClientHandler; class AuthRegistry; class KeyRing; @@ -139,6 +141,7 @@ private: struct MonClientPinger : public Dispatcher, public AuthClient { + ceph::mutex lock = ceph::make_mutex("MonClientPinger::lock"); ceph::condition_variable ping_recvd_cond; std::string *result; @@ -237,52 +240,11 @@ struct MonClientPinger : public Dispatcher, } }; -const boost::system::error_category& monc_category() noexcept; - -enum class monc_errc { - shutting_down = 1, // Command failed due to MonClient shutting down - session_reset, // Monitor session was reset - rank_dne, // Requested monitor rank does not exist - mon_dne, // Requested monitor does not exist - timed_out, // Monitor operation timed out - mon_unavailable // Monitor unavailable -}; - -namespace boost { -namespace system { -template<> -struct is_error_code_enum<::monc_errc> { - static const bool value = true; -}; -} -} - -// explicit conversion: -inline boost::system::error_code make_error_code(monc_errc e) noexcept { - return { static_cast<int>(e), monc_category() }; -} - -// implicit conversion: -inline boost::system::error_condition make_error_condition(monc_errc e) - noexcept { - return { static_cast<int>(e), monc_category() }; -} - -const boost::system::error_category& monc_category() noexcept; class MonClient : public Dispatcher, public AuthClient, public AuthServer /* for mgr, osd, mds */ { - static constexpr auto dout_subsys = ceph_subsys_monc; public: - // Error, Newest, Oldest - using VersionSig = void(boost::system::error_code, version_t, version_t); - using VersionCompletion = ceph::async::Completion<VersionSig>; - - using CommandSig = void(boost::system::error_code, std::string, - ceph::buffer::list); - using CommandCompletion = ceph::async::Completion<CommandSig>; - MonMap monmap; std::map<std::string,std::string> config_mgr; @@ -297,8 +259,7 @@ private: mutable ceph::mutex monc_lock = ceph::make_mutex("MonClient::monc_lock"); SafeTimer timer; - boost::asio::io_context& service; - boost::asio::io_context::strand finish_strand{service}; + Finisher finisher; bool initialized; bool stopping = false; @@ -343,6 +304,7 @@ private: double reopen_interval_multiplier; Dispatcher *handle_authentication_dispatcher = nullptr; + bool _opened() const; bool _hunting() const; void _start_hunting(); @@ -399,7 +361,7 @@ public: bool more, uint32_t auth_method, const ceph::buffer::list& bl, - ceph::buffer::list *reply) override; + ceph::buffer::list *reply); void set_entity_name(EntityName name) { entity_name = name; } void set_handle_authentication_dispatcher(Dispatcher *d) { @@ -448,12 +410,12 @@ public: std::lock_guard l(monc_lock); return sub.inc_want(what, start, flags); } - + std::unique_ptr<KeyRing> keyring; std::unique_ptr<RotatingKeyRing> rotating_secrets; public: - MonClient(CephContext *cct_, boost::asio::io_context& service); + explicit MonClient(CephContext *cct_); MonClient(const MonClient &) = delete; MonClient& operator=(const MonClient &) = delete; ~MonClient() override; @@ -549,206 +511,66 @@ private: struct MonCommand { // for tell only std::string target_name; - int target_rank = -1; + int target_rank; ConnectionRef target_con; std::unique_ptr<MonConnection> target_session; unsigned send_attempts = 0; ///< attempt count for legacy mons utime_t last_send_attempt; + uint64_t tid; std::vector<std::string> cmd; ceph::buffer::list inbl; - std::unique_ptr<CommandCompletion> onfinish; - std::optional<boost::asio::steady_timer> cancel_timer; - - MonCommand(MonClient& monc, uint64_t t, std::unique_ptr<CommandCompletion> onfinish) - : tid(t), onfinish(std::move(onfinish)) { - auto timeout = ceph::maybe_timespan(monc.cct->_conf->rados_mon_op_timeout); - if (timeout) { - cancel_timer.emplace(monc.service, *timeout); - cancel_timer->async_wait( - [this, &monc](boost::system::error_code ec) { - if (ec) - return; - std::scoped_lock l(monc.monc_lock); - monc._cancel_mon_command(tid); - }); - } - } + ceph::buffer::list *poutbl; + std::string *prs; + int *prval; + Context *onfinish, *ontimeout; + + explicit MonCommand(uint64_t t) + : target_rank(-1), + tid(t), + poutbl(NULL), prs(NULL), prval(NULL), onfinish(NULL), ontimeout(NULL) + {} bool is_tell() const { return target_name.size() || target_rank >= 0; } }; - friend MonCommand; std::map<uint64_t,MonCommand*> mon_commands; void _send_command(MonCommand *r); void _check_tell_commands(); void _resend_mon_commands(); int _cancel_mon_command(uint64_t tid); - void _finish_command(MonCommand *r, boost::system::error_code ret, std::string_view rs, - bufferlist&& bl); + void _finish_command(MonCommand *r, int ret, std::string rs); void _finish_auth(); void handle_mon_command_ack(MMonCommandAck *ack); void handle_command_reply(MCommandReply *reply); public: - template<typename CompletionToken> - auto start_mon_command(const std::vector<std::string>& cmd, - const ceph::buffer::list& inbl, - CompletionToken&& token) { - ldout(cct,10) << __func__ << " cmd=" << cmd << dendl; - boost::asio::async_completion<CompletionToken, CommandSig> init(token); - { - std::scoped_lock l(monc_lock); - auto h = CommandCompletion::create(service.get_executor(), - std::move(init.completion_handler)); - if (!initialized || stopping) { - ceph::async::post(std::move(h), monc_errc::shutting_down, std::string{}, - bufferlist{}); - } else { - auto r = new MonCommand(*this, ++last_mon_command_tid, std::move(h)); - r->cmd = cmd; - r->inbl = inbl; - mon_commands.emplace(r->tid, r); - _send_command(r); - } - } - return init.result.get(); - } - - template<typename CompletionToken> - auto start_mon_command(int mon_rank, const std::vector<std::string>& cmd, - const ceph::buffer::list& inbl, CompletionToken&& token) { - ldout(cct,10) << __func__ << " cmd=" << cmd << dendl; - boost::asio::async_completion<CompletionToken, CommandSig> init(token); - { - std::scoped_lock l(monc_lock); - auto h = CommandCompletion::create(service.get_executor(), - std::move(init.completion_handler)); - if (!initialized || stopping) { - ceph::async::post(std::move(h), monc_errc::shutting_down, std::string{}, - bufferlist{}); - } else { - auto r = new MonCommand(*this, ++last_mon_command_tid, std::move(h)); - r->target_rank = mon_rank; - r->cmd = cmd; - r->inbl = inbl; - mon_commands.emplace(r->tid, r); - _send_command(r); - } - } - return init.result.get(); - } - - template<typename CompletionToken> - auto start_mon_command(const std::string& mon_name, - const std::vector<std::string>& cmd, - const ceph::buffer::list& inbl, - CompletionToken&& token) { - ldout(cct,10) << __func__ << " cmd=" << cmd << dendl; - boost::asio::async_completion<CompletionToken, CommandSig> init(token); - { - std::scoped_lock l(monc_lock); - auto h = CommandCompletion::create(service.get_executor(), - std::move(init.completion_handler)); - if (!initialized || stopping) { - ceph::async::post(std::move(h), monc_errc::shutting_down, std::string{}, - bufferlist{}); - } else { - auto r = new MonCommand(*this, ++last_mon_command_tid, std::move(h)); - // detect/tolerate mon *rank* passed as a string - std::string err; - int rank = strict_strtoll(mon_name.c_str(), 10, &err); - if (err.size() == 0 && rank >= 0) { - ldout(cct,10) << __func__ << " interpreting name '" << mon_name - << "' as rank " << rank << dendl; - r->target_rank = rank; - } else { - r->target_name = mon_name; - } - r->cmd = cmd; - r->inbl = inbl; - mon_commands.emplace(r->tid, r); - _send_command(r); - } - } - return init.result.get(); - } - - class ContextVerter { - std::string* outs; - ceph::bufferlist* outbl; - Context* onfinish; - - public: - ContextVerter(std::string* outs, ceph::bufferlist* outbl, Context* onfinish) - : outs(outs), outbl(outbl), onfinish(onfinish) {} - ~ContextVerter() = default; - ContextVerter(const ContextVerter&) = default; - ContextVerter& operator =(const ContextVerter&) = default; - ContextVerter(ContextVerter&&) = default; - ContextVerter& operator =(ContextVerter&&) = default; - - void operator()(boost::system::error_code e, - std::string s, - ceph::bufferlist bl) { - if (outs) - *outs = std::move(s); - if (outbl) - *outbl = std::move(bl); - if (onfinish) - onfinish->complete(ceph::from_error_code(e)); - } - }; - - void start_mon_command(const vector<string>& cmd, const bufferlist& inbl, - bufferlist *outbl, string *outs, - Context *onfinish) { - start_mon_command(cmd, inbl, ContextVerter(outs, outbl, onfinish)); - } + void start_mon_command(const std::vector<std::string>& cmd, const ceph::buffer::list& inbl, + ceph::buffer::list *outbl, std::string *outs, + Context *onfinish); void start_mon_command(int mon_rank, - const vector<string>& cmd, const bufferlist& inbl, - bufferlist *outbl, string *outs, - Context *onfinish) { - start_mon_command(mon_rank, cmd, inbl, ContextVerter(outs, outbl, onfinish)); - } - void start_mon_command(const string &mon_name, ///< mon name, with mon. prefix - const vector<string>& cmd, const bufferlist& inbl, - bufferlist *outbl, string *outs, - Context *onfinish) { - start_mon_command(mon_name, cmd, inbl, ContextVerter(outs, outbl, onfinish)); - } - + const std::vector<std::string>& cmd, const ceph::buffer::list& inbl, + ceph::buffer::list *outbl, std::string *outs, + Context *onfinish); + void start_mon_command(const std::string &mon_name, ///< mon name, with mon. prefix + const std::vector<std::string>& cmd, const ceph::buffer::list& inbl, + ceph::buffer::list *outbl, std::string *outs, + Context *onfinish); // version requests public: /** * get latest known version(s) of cluster map * - * @param map string name of map (e.g., 'osdmap') - * @param token context that will be triggered on completion - * @return (via Completion) {} on success, - * boost::system::errc::resource_unavailable_try_again if we need to - * resubmit our request + * @param map std::string name of map (e.g., 'osdmap') + * @param newest pointer where newest map version will be stored + * @param oldest pointer where oldest map version will be stored + * @param onfinish context that will be triggered on completion + * @return (via context) 0 on success, -EAGAIN if we need to resubmit our request */ - template<typename CompletionToken> - auto get_version(std::string&& map, CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, VersionSig> init(token); - { - std::scoped_lock l(monc_lock); - auto m = ceph::make_message<MMonGetVersion>(); - m->what = std::move(map); - m->handle = ++version_req_id; - version_requests.emplace(m->handle, - VersionCompletion::create( - service.get_executor(), - std::move(init.completion_handler))); - _send_mon_message(m); - } - return init.result.get(); - } - + void get_version(std::string map, version_t *newest, version_t *oldest, Context *onfinish); /** * Run a callback within our lock, with a reference * to the MonMap @@ -767,10 +589,16 @@ public: md_config_t::config_callback get_config_callback(); private: + struct version_req_d { + Context *context; + version_t *newest, *oldest; + version_req_d(Context *con, version_t *n, version_t *o) : context(con),newest(n), oldest(o) {} + }; - std::map<ceph_tid_t, std::unique_ptr<VersionCompletion>> version_requests; + std::map<ceph_tid_t, version_req_d*> version_requests; ceph_tid_t version_req_id; void handle_get_version_reply(MMonGetVersionReply* m); + md_config_t::config_callback config_cb; std::function<void(void)> config_notify_cb; }; diff --git a/src/mon/MonMap.cc b/src/mon/MonMap.cc index 95b92ec8f4a..d63bada0fd6 100644 --- a/src/mon/MonMap.cc +++ b/src/mon/MonMap.cc @@ -658,7 +658,7 @@ int MonMap::init_with_config_file(const ConfigProxy& conf, using namespace seastar; -seastar::future<> MonMap::read_monmap(const std::string& monmap) +future<> MonMap::read_monmap(const std::string& monmap) { return open_file_dma(monmap, open_flags::ro).then([this] (file f) { return f.size().then([this, f = std::move(f)](size_t s) { @@ -673,7 +673,7 @@ seastar::future<> MonMap::read_monmap(const std::string& monmap) }); } -seastar::future<> MonMap::init_with_dns_srv(bool for_mkfs, const std::string& name) +future<> MonMap::init_with_dns_srv(bool for_mkfs, const std::string& name) { string domain; string service = name; @@ -750,7 +750,7 @@ seastar::future<> MonMap::build_monmap(const crimson::common::ConfigProxy& conf, }); } -seastar::future<> MonMap::build_initial(const crimson::common::ConfigProxy& conf, bool for_mkfs) +future<> MonMap::build_initial(const crimson::common::ConfigProxy& conf, bool for_mkfs) { // file? if (const auto monmap = conf.get_val<std::string>("monmap"); diff --git a/src/mon/error_code.cc b/src/mon/error_code.cc deleted file mode 100644 index 67ff736da78..00000000000 --- a/src/mon/error_code.cc +++ /dev/null @@ -1,64 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2019 Red Hat <contact@redhat.com> - * Author: Adam C. Emerson <aemerson@redhat.com> - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#include <string> - -#include "common/error_code.h" -#include "common/errno.h" -#include "error_code.h" - -namespace bs = boost::system; - -class mon_error_category : public ceph::converting_category { -public: - mon_error_category(){} - const char* name() const noexcept override; - std::string message(int ev) const override; - bs::error_condition default_error_condition(int ev) const noexcept - override; - bool equivalent(int ev, const bs::error_condition& c) const - noexcept override; - using ceph::converting_category::equivalent; - int from_code(int ev) const noexcept override; -}; - -const char* mon_error_category::name() const noexcept { - return "mon"; -} - -std::string mon_error_category::message(int ev) const { - if (ev == 0) - return "No error"; - - return cpp_strerror(ev); -} - -bs::error_condition -mon_error_category::default_error_condition(int ev) const noexcept { - return { ev, bs::generic_category() }; -} - -bool mon_error_category::equivalent(int ev,const bs::error_condition& c) const noexcept { - return default_error_condition(ev) == c; -} - -int mon_error_category::from_code(int ev) const noexcept { - return -ev; -} - -const bs::error_category& mon_category() noexcept { - static const mon_error_category c; - return c; -} diff --git a/src/mon/error_code.h b/src/mon/error_code.h deleted file mode 100644 index c247c68f98d..00000000000 --- a/src/mon/error_code.h +++ /dev/null @@ -1,47 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2019 Red Hat <contact@redhat.com> - * Author: Adam C. Emerson <aemerson@redhat.com> - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#pragma once - -#include <boost/system/error_code.hpp> - -#include "include/rados.h" - -const boost::system::error_category& mon_category() noexcept; - -// The Monitor, like the OSD, mostly replies with POSIX error codes. - -enum mon_errc { -}; - -namespace boost { -namespace system { -template<> -struct is_error_code_enum<::mon_errc> { - static const bool value = true; -}; -} -} - -// explicit conversion: -inline boost::system::error_code make_error_code(mon_errc e) noexcept { - return { e, mon_category() }; -} - -// implicit conversion: -inline boost::system::error_condition make_error_condition(mon_errc e) - noexcept { - return { e, mon_category() }; -} diff --git a/src/mount/conf.cc b/src/mount/conf.cc index 0ec86b29fcb..228f53e7218 100644 --- a/src/mount/conf.cc +++ b/src/mount/conf.cc @@ -6,17 +6,13 @@ #include <cstring> #include <map> -#include "common/async/context_pool.h" #include "common/ceph_context.h" #include "common/ceph_argparse.h" -#include "common/config.h" #include "global/global_init.h" - +#include "common/config.h" #include "auth/KeyRing.h" -#include "mon/MonClient.h" - #include "mount.ceph.h" - +#include "mon/MonClient.h" extern "C" void mount_ceph_get_config_info(const char *config_file, const char *name, @@ -44,8 +40,7 @@ extern "C" void mount_ceph_get_config_info(const char *config_file, conf.parse_env(cct->get_module_type()); // environment variables override conf.apply_changes(nullptr); - ceph::async::io_context_pool ioc(1); - MonClient monc = MonClient(cct.get(), ioc); + MonClient monc = MonClient(cct.get()); err = monc.build_initial_monmap(); if (err) goto scrape_keyring; diff --git a/src/msg/MessageRef.h b/src/msg/MessageRef.h index 4f30f0b352a..5eb3655cb84 100644 --- a/src/msg/MessageRef.h +++ b/src/msg/MessageRef.h @@ -133,6 +133,8 @@ class MOSDForceRecovery; class MOSDFull; class MOSDMap; class MOSDMarkMeDown; +class MOSDOp; +class MOSDOpReply; class MOSDPeeringOp; class MOSDPGBackfill; class MOSDPGBackfillRemove; diff --git a/src/msg/async/ProtocolV2.cc b/src/msg/async/ProtocolV2.cc index aa864cf3311..fe2158289a5 100644 --- a/src/msg/async/ProtocolV2.cc +++ b/src/msg/async/ProtocolV2.cc @@ -44,7 +44,7 @@ void ProtocolV2::run_continuation(CtRef continuation) { try { CONTINUATION_RUN(continuation) } catch (const buffer::error &e) { - lderr(cct) << __func__ << " failed decoding of frame header: " << e.what() + lderr(cct) << __func__ << " failed decoding of frame header: " << e << dendl; _fault(); } catch (const ceph::crypto::onwire::MsgAuthError &e) { diff --git a/src/osd/OSD.cc b/src/osd/OSD.cc index 446ddfbad87..4c85cd82f98 100644 --- a/src/osd/OSD.cc +++ b/src/osd/OSD.cc @@ -51,7 +51,6 @@ #include "common/ceph_releases.h" #include "common/ceph_time.h" #include "common/version.h" -#include "common/async/waiter.h" #include "common/pick_address.h" #include "common/blkdev.h" #include "common/numa.h" @@ -221,7 +220,7 @@ CompatSet OSD::get_osd_compat_set() { return compat; } -OSDService::OSDService(OSD *osd, ceph::async::io_context_pool& poolctx) : +OSDService::OSDService(OSD *osd) : osd(osd), cct(osd->cct), whoami(osd->whoami), store(osd->store), @@ -249,8 +248,7 @@ OSDService::OSDService(OSD *osd, ceph::async::io_context_pool& poolctx) : last_recalibrate(ceph_clock_now()), promote_max_objects(0), promote_max_bytes(0), - poolctx(poolctx), - objecter(new Objecter(osd->client_messenger->cct, osd->objecter_messenger, osd->monc, poolctx, 0, 0)), + objecter(new Objecter(osd->client_messenger->cct, osd->objecter_messenger, osd->monc, NULL, 0, 0)), m_objecter_finishers(cct->_conf->osd_objecter_finishers), watch_timer(osd->client_messenger->cct, watch_lock), next_notif_id(0), @@ -2148,8 +2146,7 @@ OSD::OSD(CephContext *cct_, ObjectStore *store_, Messenger *hb_back_serverm, Messenger *osdc_messenger, MonClient *mc, - const std::string &dev, const std::string &jdev, - ceph::async::io_context_pool& poolctx) : + const std::string &dev, const std::string &jdev) : Dispatcher(cct_), tick_timer(cct, osd_lock), tick_timer_without_osd_lock(cct, tick_timer_lock), @@ -2196,7 +2193,7 @@ OSD::OSD(CephContext *cct_, ObjectStore *store_, up_thru_wanted(0), requested_full_first(0), requested_full_last(0), - service(this, poolctx) + service(this) { if (!gss_ktfile_client.empty()) { @@ -6223,12 +6220,12 @@ bool OSD::ms_handle_refused(Connection *con) return true; } -struct CB_OSD_GetVersion { +struct C_OSD_GetVersion : public Context { OSD *osd; - explicit CB_OSD_GetVersion(OSD *o) : osd(o) {} - void operator ()(boost::system::error_code ec, version_t newest, - version_t oldest) { - if (!ec) + uint64_t oldest, newest; + explicit C_OSD_GetVersion(OSD *o) : osd(o), oldest(0), newest(0) {} + void finish(int r) override { + if (r >= 0) osd->_got_mon_epochs(oldest, newest); } }; @@ -6248,7 +6245,8 @@ void OSD::start_boot() set_state(STATE_PREBOOT); dout(10) << "start_boot - have maps " << superblock.oldest_map << ".." << superblock.newest_map << dendl; - monc->get_version("osdmap", CB_OSD_GetVersion(this)); + C_OSD_GetVersion *c = new C_OSD_GetVersion(this); + monc->get_version("osdmap", &c->newest, &c->oldest, c); } void OSD::_got_mon_epochs(epoch_t oldest, epoch_t newest) @@ -9828,10 +9826,6 @@ void OSD::handle_conf_change(const ConfigProxy& conf, dout(0) << __func__ << ": scrub interval change" << dendl; } check_config(); - if (changed.count("osd_asio_thread_count")) { - service.poolctx.stop(); - service.poolctx.start(conf.get_val<std::uint64_t>("osd_asio_thread_count")); - } } void OSD::update_log_config() @@ -9878,9 +9872,9 @@ void OSD::get_latest_osdmap() { dout(10) << __func__ << " -- start" << dendl; - ceph::async::waiter<boost::system::error_code> w; - service.objecter->wait_for_latest_osdmap(w); - w.wait(); + C_SaferCond cond; + service.objecter->wait_for_latest_osdmap(&cond); + cond.wait(); dout(10) << __func__ << " -- finish" << dendl; } diff --git a/src/osd/OSD.h b/src/osd/OSD.h index 174c9dac645..56f6149180a 100644 --- a/src/osd/OSD.h +++ b/src/osd/OSD.h @@ -19,7 +19,6 @@ #include "msg/Dispatcher.h" -#include "common/async/context_pool.h" #include "common/Timer.h" #include "common/WorkQueue.h" #include "common/AsyncReserver.h" @@ -91,6 +90,7 @@ struct C_FinishSplits; struct C_OpenPGs; class LogChannel; class CephContext; +class MOSDOp; class MOSDPGCreate2; class MOSDPGQuery; @@ -517,7 +517,6 @@ public: void promote_throttle_recalibrate(); // -- Objecter, for tiering reads/writes from/to other OSDs -- - ceph::async::io_context_pool& poolctx; Objecter *objecter; int m_objecter_finishers; vector<Finisher*> objecter_finishers; @@ -905,7 +904,7 @@ public: void dump_live_pgids(); #endif - OSDService(OSD *osd, ceph::async::io_context_pool& poolctx); + explicit OSDService(OSD *osd); ~OSDService(); }; @@ -1834,7 +1833,7 @@ protected: void send_full_update(); - friend struct CB_OSD_GetVersion; + friend struct C_OSD_GetVersion; // -- alive -- epoch_t up_thru_wanted; @@ -2008,8 +2007,7 @@ private: Messenger *hb_front_server, Messenger *hb_back_server, Messenger *osdc_messenger, - MonClient *mc, const std::string &dev, const std::string &jdev, - ceph::async::io_context_pool& poolctx); + MonClient *mc, const std::string &dev, const std::string &jdev); ~OSD() override; // static bits diff --git a/src/osd/OSDMap.h b/src/osd/OSDMap.h index f87e38f45f7..f0055611b27 100644 --- a/src/osd/OSDMap.h +++ b/src/osd/OSDMap.h @@ -571,7 +571,7 @@ private: mempool::osdmap::map<int64_t,pg_pool_t> pools; mempool::osdmap::map<int64_t,std::string> pool_name; mempool::osdmap::map<std::string, std::map<std::string,std::string>> erasure_code_profiles; - mempool::osdmap::map<std::string,int64_t, std::less<>> name_pool; + mempool::osdmap::map<std::string,int64_t> name_pool; std::shared_ptr< mempool::osdmap::vector<uuid_d> > osd_uuid; mempool::osdmap::vector<osd_xinfo_t> osd_xinfo; @@ -1299,7 +1299,7 @@ public: return new_purged_snaps; } - int64_t lookup_pg_pool_name(std::string_view name) const { + int64_t lookup_pg_pool_name(const std::string& name) const { auto p = name_pool.find(name); if (p == name_pool.end()) return -ENOENT; diff --git a/src/osd/PG.h b/src/osd/PG.h index e372f8896d7..1ed490a0a9a 100644 --- a/src/osd/PG.h +++ b/src/osd/PG.h @@ -61,6 +61,7 @@ class OSD; class OSDService; class OSDShard; class OSDShardPGSlot; +class MOSDOp; class MOSDPGScan; class MOSDPGBackfill; class MOSDPGInfo; diff --git a/src/osd/PrimaryLogPG.cc b/src/osd/PrimaryLogPG.cc index da3f52be83f..e06fa6c8c55 100644 --- a/src/osd/PrimaryLogPG.cc +++ b/src/osd/PrimaryLogPG.cc @@ -11406,7 +11406,7 @@ SnapSetContext *PrimaryLogPG::get_snapset_context( try { ssc->snapset.decode(bvp); } catch (buffer::error& e) { - dout(0) << __func__ << " Can't decode snapset: " << e.what() << dendl; + dout(0) << __func__ << " Can't decode snapset: " << e << dendl; return NULL; } ssc->exists = true; diff --git a/src/osd/PrimaryLogPG.h b/src/osd/PrimaryLogPG.h index 59ff68bfac9..a350714bbfc 100644 --- a/src/osd/PrimaryLogPG.h +++ b/src/osd/PrimaryLogPG.h @@ -40,6 +40,8 @@ class PrimaryLogPG; class PGLSFilter; class HitSet; struct TierAgentState; +class MOSDOp; +class MOSDOpReply; class OSDService; void intrusive_ptr_add_ref(PrimaryLogPG *pg); diff --git a/src/osd/error_code.cc b/src/osd/error_code.cc deleted file mode 100644 index 074064dd074..00000000000 --- a/src/osd/error_code.cc +++ /dev/null @@ -1,78 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2019 Red Hat <contact@redhat.com> - * Author: Adam C. Emerson <aemerson@redhat.com> - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#include <string> - -#include "common/error_code.h" -#include "common/errno.h" -#include "error_code.h" - -class osd_error_category : public ceph::converting_category { -public: - osd_error_category(){} - const char* name() const noexcept override; - std::string message(int ev) const override; - boost::system::error_condition default_error_condition(int ev) const noexcept - override; - bool equivalent(int ev, const boost::system::error_condition& c) const - noexcept override; - using ceph::converting_category::equivalent; - int from_code(int ev) const noexcept override; -}; - -const char* osd_error_category::name() const noexcept { - return "osd"; -} - -std::string osd_error_category::message(int ev) const { - if (ev == 0) - return "No error"; - - switch (static_cast<osd_errc>(ev)) { - case osd_errc::old_snapc: - return "ORDERSNAP flag set; writer has old snapc"; - case osd_errc::blacklisted: - return "Blacklisted"; - } - - return cpp_strerror(ev); -} - -boost::system::error_condition osd_error_category::default_error_condition(int ev) const noexcept { - if (ev == static_cast<int>(osd_errc::old_snapc) || - ev == static_cast<int>(osd_errc::blacklisted)) - return { ev, *this }; - else - return { ev, boost::system::generic_category() }; -} - -bool osd_error_category::equivalent(int ev, const boost::system::error_condition& c) const noexcept { - switch (static_cast<osd_errc>(ev)) { - case osd_errc::old_snapc: - return c == boost::system::errc::invalid_argument; - case osd_errc::blacklisted: - return c == boost::system::errc::operation_not_permitted; - } - return default_error_condition(ev) == c; -} - -int osd_error_category::from_code(int ev) const noexcept { - return -ev; -} - -const boost::system::error_category& osd_category() noexcept { - static const osd_error_category c; - return c; -} diff --git a/src/osd/error_code.h b/src/osd/error_code.h deleted file mode 100644 index f7385692190..00000000000 --- a/src/osd/error_code.h +++ /dev/null @@ -1,51 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2019 Red Hat <contact@redhat.com> - * Author: Adam C. Emerson <aemerson@redhat.com> - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#pragma once - -#include <boost/system/error_code.hpp> - -#include "include/rados.h" - -const boost::system::error_category& osd_category() noexcept; - -// Since the OSD mostly uses POSIX error codes plus a couple -// additions, this will be a degenerate error category for now that -// mostly forwards to POSIX. - -enum class osd_errc { - old_snapc = 85, /* ORDERSNAP flag set; writer has old snapc*/ - blacklisted = 108 /* blacklisted */ -}; - -namespace boost { -namespace system { -template<> -struct is_error_code_enum<::osd_errc> { - static const bool value = true; -}; -} -} - -// explicit conversion: -inline boost::system::error_code make_error_code(osd_errc e) noexcept { - return { static_cast<int>(e), osd_category() }; -} - -// implicit conversion: -inline boost::system::error_condition make_error_condition(osd_errc e) - noexcept { - return { static_cast<int>(e), osd_category() }; -} diff --git a/src/osd/osd_types.cc b/src/osd/osd_types.cc index 70250c12443..7cf74108ae7 100644 --- a/src/osd/osd_types.cc +++ b/src/osd/osd_types.cc @@ -1679,7 +1679,7 @@ bool pg_pool_t::is_removed_snap(snapid_t s) const return removed_snaps.contains(s); } -snapid_t pg_pool_t::snap_exists(std::string_view s) const +snapid_t pg_pool_t::snap_exists(const char *s) const { for (auto p = snaps.cbegin(); p != snaps.cend(); ++p) if (p->second.name == s) @@ -6766,6 +6766,26 @@ ostream& operator<<(ostream& out, const OSDOp& op) } +void OSDOp::split_osd_op_vector_in_data(vector<OSDOp>& ops, ceph::buffer::list& in) +{ + ceph::buffer::list::iterator datap = in.begin(); + for (unsigned i = 0; i < ops.size(); i++) { + if (ops[i].op.payload_len) { + datap.copy(ops[i].op.payload_len, ops[i].indata); + } + } +} + +void OSDOp::merge_osd_op_vector_in_data(vector<OSDOp>& ops, ceph::buffer::list& out) +{ + for (unsigned i = 0; i < ops.size(); i++) { + if (ops[i].indata.length()) { + ops[i].op.payload_len = ops[i].indata.length(); + out.append(ops[i].indata); + } + } +} + void OSDOp::split_osd_op_vector_out_data(vector<OSDOp>& ops, ceph::buffer::list& in) { auto datap = in.begin(); @@ -6786,6 +6806,35 @@ void OSDOp::merge_osd_op_vector_out_data(vector<OSDOp>& ops, ceph::buffer::list& } } +void OSDOp::clear_data(vector<OSDOp>& ops) +{ + for (unsigned i = 0; i < ops.size(); i++) { + OSDOp& op = ops[i]; + op.outdata.clear(); + if (ceph_osd_op_type_attr(op.op.op) && + op.op.xattr.name_len && + op.indata.length() >= op.op.xattr.name_len) { + ceph::buffer::ptr bp(op.op.xattr.name_len); + ceph::buffer::list bl; + bl.append(bp); + bl.copy_in(0, op.op.xattr.name_len, op.indata); + op.indata.claim(bl); + } else if (ceph_osd_op_type_exec(op.op.op) && + op.op.cls.class_len && + op.indata.length() > + (op.op.cls.class_len + op.op.cls.method_len)) { + __u8 len = op.op.cls.class_len + op.op.cls.method_len; + ceph::buffer::ptr bp(len); + ceph::buffer::list bl; + bl.append(bp); + bl.copy_in(0, len, op.indata); + op.indata.claim(bl); + } else { + op.indata.clear(); + } + } +} + int prepare_info_keymap( CephContext* cct, map<string,bufferlist> *km, diff --git a/src/osd/osd_types.h b/src/osd/osd_types.h index 6e482ee8dbf..1976456c6ca 100644 --- a/src/osd/osd_types.h +++ b/src/osd/osd_types.h @@ -256,10 +256,10 @@ namespace std { // does it go in. struct object_locator_t { // You specify either the hash or the key -- not both - std::int64_t pool; ///< pool id - std::string key; ///< key string (if non-empty) + int64_t pool; ///< pool id + std::string key; ///< key std::string (if non-empty) std::string nspace; ///< namespace - std::int64_t hash; ///< hash position (if >= 0) + int64_t hash; ///< hash position (if >= 0) explicit object_locator_t() : pool(-1), hash(-1) {} @@ -267,11 +267,11 @@ struct object_locator_t { : pool(po), hash(-1) {} explicit object_locator_t(int64_t po, int64_t ps) : pool(po), hash(ps) {} - explicit object_locator_t(int64_t po, std::string_view ns) + explicit object_locator_t(int64_t po, std::string ns) : pool(po), nspace(ns), hash(-1) {} - explicit object_locator_t(int64_t po, std::string_view ns, int64_t ps) + explicit object_locator_t(int64_t po, std::string ns, int64_t ps) : pool(po), nspace(ns), hash(ps) {} - explicit object_locator_t(int64_t po, std::string_view ns, std::string_view s) + explicit object_locator_t(int64_t po, std::string ns, std::string s) : pool(po), key(s), nspace(ns), hash(-1) {} explicit object_locator_t(const hobject_t& soid) : pool(soid.pool), key(soid.get_key()), nspace(soid.nspace), hash(-1) {} @@ -1692,7 +1692,7 @@ public: bool is_unmanaged_snaps_mode() const; bool is_removed_snap(snapid_t s) const; - snapid_t snap_exists(std::string_view s) const; + snapid_t snap_exists(const char *s) const; void add_snap(const char *n, utime_t stamp); uint64_t add_unmanaged_snap(bool preoctopus_compat); void remove_snap(snapid_t s); @@ -3949,16 +3949,7 @@ struct OSDOp { * @param ops [out] vector of OSDOps * @param in [in] combined data buffer */ - template<typename V> - static void split_osd_op_vector_in_data(V& ops, - ceph::buffer::list& in) { - ceph::buffer::list::iterator datap = in.begin(); - for (unsigned i = 0; i < ops.size(); i++) { - if (ops[i].op.payload_len) { - datap.copy(ops[i].op.payload_len, ops[i].indata); - } - } - } + static void split_osd_op_vector_in_data(std::vector<OSDOp>& ops, ceph::buffer::list& in); /** * merge indata members of a vector of OSDOp into a single ceph::buffer::list @@ -3969,15 +3960,7 @@ struct OSDOp { * @param ops [in] vector of OSDOps * @param out [out] combined data buffer */ - template<typename V> - static void merge_osd_op_vector_in_data(V& ops, ceph::buffer::list& out) { - for (unsigned i = 0; i < ops.size(); i++) { - if (ops[i].indata.length()) { - ops[i].op.payload_len = ops[i].indata.length(); - out.append(ops[i].indata); - } - } - } + static void merge_osd_op_vector_in_data(std::vector<OSDOp>& ops, ceph::buffer::list& out); /** * split a ceph::buffer::list into constituent outdata members of a vector of OSDOps @@ -4000,37 +3983,11 @@ struct OSDOp { * * @param ops [in] vector of OSDOps */ - template<typename V> - static void clear_data(V& ops) { - for (unsigned i = 0; i < ops.size(); i++) { - OSDOp& op = ops[i]; - op.outdata.clear(); - if (ceph_osd_op_type_attr(op.op.op) && - op.op.xattr.name_len && - op.indata.length() >= op.op.xattr.name_len) { - ceph::buffer::ptr bp(op.op.xattr.name_len); - ceph::buffer::list bl; - bl.append(bp); - bl.copy_in(0, op.op.xattr.name_len, op.indata); - op.indata.claim(bl); - } else if (ceph_osd_op_type_exec(op.op.op) && - op.op.cls.class_len && - op.indata.length() > - (op.op.cls.class_len + op.op.cls.method_len)) { - __u8 len = op.op.cls.class_len + op.op.cls.method_len; - ceph::buffer::ptr bp(len); - ceph::buffer::list bl; - bl.append(bp); - bl.copy_in(0, len, op.indata); - op.indata.claim(bl); - } else { - op.indata.clear(); - } - } - } + static void clear_data(std::vector<OSDOp>& ops); }; std::ostream& operator<<(std::ostream& out, const OSDOp& op); + struct pg_log_op_return_item_t { int32_t rval; bufferlist bl; @@ -5002,14 +4959,14 @@ using pg_missing_tracker_t = pg_missing_set<true>; */ struct pg_nls_response_t { collection_list_handle_t handle; - std::vector<librados::ListObjectImpl> entries; + std::list<librados::ListObjectImpl> entries; void encode(ceph::buffer::list& bl) const { ENCODE_START(1, 1, bl); encode(handle, bl); __u32 n = (__u32)entries.size(); encode(n, bl); - for (auto i = entries.begin(); i != entries.end(); ++i) { + for (std::list<librados::ListObjectImpl>::const_iterator i = entries.begin(); i != entries.end(); ++i) { encode(i->nspace, bl); encode(i->oid, bl); encode(i->locator, bl); @@ -5034,7 +4991,7 @@ struct pg_nls_response_t { void dump(ceph::Formatter *f) const { f->dump_stream("handle") << handle; f->open_array_section("entries"); - for (auto p = entries.begin(); p != entries.end(); ++p) { + for (std::list<librados::ListObjectImpl>::const_iterator p = entries.begin(); p != entries.end(); ++p) { f->open_object_section("object"); f->dump_string("namespace", p->nspace); f->dump_string("object", p->oid); diff --git a/src/osdc/CMakeLists.txt b/src/osdc/CMakeLists.txt index 551b105f893..6dd97b39362 100644 --- a/src/osdc/CMakeLists.txt +++ b/src/osdc/CMakeLists.txt @@ -2,7 +2,6 @@ set(osdc_files Filer.cc ObjectCacher.cc Objecter.cc - error_code.cc Striper.cc) add_library(osdc STATIC ${osdc_files}) if(WITH_EVENTTRACE) diff --git a/src/osdc/Filer.cc b/src/osdc/Filer.cc index 4a2aeb88077..83370d8c08b 100644 --- a/src/osdc/Filer.cc +++ b/src/osdc/Filer.cc @@ -415,7 +415,7 @@ void Filer::truncate(inodeno_t ino, if (num_objs == 1) { vector<ObjectExtent> extents; Striper::file_to_extents(cct, ino, layout, offset, len, 0, extents); - osdc_opvec ops(1); + vector<OSDOp> ops(1); ops[0].op.op = CEPH_OSD_OP_TRIMTRUNC; ops[0].op.extent.truncate_seq = truncate_seq; ops[0].op.extent.truncate_size = extents[0].offset; @@ -474,7 +474,7 @@ void Filer::_do_truncate_range(TruncRange *tr, int fin) // Issue objecter ops outside tr->lock to avoid lock dependency loop for (const auto& p : extents) { - osdc_opvec ops(1); + vector<OSDOp> ops(1); ops[0].op.op = CEPH_OSD_OP_TRIMTRUNC; ops[0].op.extent.truncate_size = p.offset; ops[0].op.extent.truncate_seq = tr->truncate_seq; diff --git a/src/osdc/Objecter.cc b/src/osdc/Objecter.cc index f1c9552fb57..37dc01d0144 100644 --- a/src/osdc/Objecter.cc +++ b/src/osdc/Objecter.cc @@ -12,16 +12,13 @@ * */ -#include <algorithm> #include <cerrno> #include "Objecter.h" #include "osd/OSDMap.h" -#include "osd/error_code.h" #include "Filer.h" #include "mon/MonClient.h" -#include "mon/error_code.h" #include "msg/Messenger.h" #include "msg/Message.h" @@ -48,16 +45,12 @@ #include "messages/MWatchNotify.h" -#include "common/Cond.h" #include "common/config.h" #include "common/perf_counters.h" #include "common/scrub_types.h" #include "include/str_list.h" #include "common/errno.h" #include "common/EventTrace.h" -#include "common/async/waiter.h" -#include "error_code.h" - using std::list; using std::make_pair; @@ -88,11 +81,6 @@ using ceph::shunique_lock; using ceph::acquire_shared; using ceph::acquire_unique; -namespace bc = boost::container; -namespace bs = boost::system; -namespace ca = ceph::async; -namespace cb = ceph::buffer; - #define dout_subsys ceph_subsys_objecter #undef dout_prefix #define dout_prefix *_dout << messenger->get_myname() << ".objecter " @@ -106,7 +94,6 @@ enum { l_osdc_op_send_bytes, l_osdc_op_resend, l_osdc_op_reply, - l_osdc_oplen_avg, l_osdc_op, l_osdc_op_r, @@ -177,11 +164,6 @@ enum { l_osdc_last, }; -namespace { -inline bs::error_code osdcode(int r) { - return (r < 0) ? bs::error_code(-r, osd_category()) : bs::error_code(); -} -} // config obs ---------------------------- @@ -197,19 +179,55 @@ public: int call(std::string_view command, const cmdmap_t& cmdmap, Formatter *f, std::ostream& ss, - cb::list& out) override; + ceph::buffer::list& out) override; +}; + +/** + * This is a more limited form of C_Contexts, but that requires + * a ceph_context which we don't have here. + */ +class ObjectOperation::C_TwoContexts : public Context { + Context *first; + Context *second; +public: + C_TwoContexts(Context *first, Context *second) : + first(first), second(second) {} + void finish(int r) override { + first->complete(r); + second->complete(r); + first = NULL; + second = NULL; + } + + ~C_TwoContexts() override { + delete first; + delete second; + } }; -std::unique_lock<std::mutex> Objecter::OSDSession::get_lock(object_t& oid) +void ObjectOperation::add_handler(Context *extra) { + size_t last = out_handler.size() - 1; + Context *orig = out_handler[last]; + if (orig) { + Context *wrapper = new C_TwoContexts(orig, extra); + out_handler[last] = wrapper; + } else { + out_handler[last] = extra; + } +} + +Objecter::OSDSession::unique_completion_lock Objecter::OSDSession::get_lock( + object_t& oid) { if (oid.name.empty()) - return {}; + return unique_completion_lock(); static constexpr uint32_t HASH_PRIME = 1021; uint32_t h = ceph_str_hash_linux(oid.name.c_str(), oid.name.size()) % HASH_PRIME; - return {completion_locks[h % num_locks], std::defer_lock}; + return unique_completion_lock(completion_locks[h % num_locks], + std::defer_lock); } const char** Objecter::get_tracked_conf_keys() const @@ -251,7 +269,6 @@ void Objecter::init() pcb.add_u64_counter(l_osdc_op_send_bytes, "op_send_bytes", "Sent data", NULL, 0, unit_t(UNIT_BYTES)); pcb.add_u64_counter(l_osdc_op_resend, "op_resend", "Resent operations"); pcb.add_u64_counter(l_osdc_op_reply, "op_reply", "Operation reply"); - pcb.add_u64_avg(l_osdc_oplen_avg, "oplen_avg", "Average length of operation vector"); pcb.add_u64_counter(l_osdc_op, "op", "Operations"); pcb.add_u64_counter(l_osdc_op_r, "op_r", "Read operations", "rd", @@ -367,7 +384,7 @@ void Objecter::init() } m_request_state_hook = new RequestStateHook(this); - auto admin_socket = cct->get_admin_socket(); + AdminSocket* admin_socket = cct->get_admin_socket(); int ret = admin_socket->register_command("objecter_requests", m_request_state_hook, "show in-progress osd requests"); @@ -414,54 +431,57 @@ void Objecter::shutdown() cct->_conf.remove_observer(this); wl.lock(); + map<int,OSDSession*>::iterator p; while (!osd_sessions.empty()) { - auto p = osd_sessions.begin(); + p = osd_sessions.begin(); close_session(p->second); } while(!check_latest_map_lingers.empty()) { - auto i = check_latest_map_lingers.begin(); + map<uint64_t, LingerOp*>::iterator i = check_latest_map_lingers.begin(); i->second->put(); check_latest_map_lingers.erase(i->first); } while(!check_latest_map_ops.empty()) { - auto i = check_latest_map_ops.begin(); + map<ceph_tid_t, Op*>::iterator i = check_latest_map_ops.begin(); i->second->put(); check_latest_map_ops.erase(i->first); } while(!check_latest_map_commands.empty()) { - auto i = check_latest_map_commands.begin(); + map<ceph_tid_t, CommandOp*>::iterator i + = check_latest_map_commands.begin(); i->second->put(); check_latest_map_commands.erase(i->first); } while(!poolstat_ops.empty()) { - auto i = poolstat_ops.begin(); + map<ceph_tid_t,PoolStatOp*>::iterator i = poolstat_ops.begin(); delete i->second; poolstat_ops.erase(i->first); } while(!statfs_ops.empty()) { - auto i = statfs_ops.begin(); + map<ceph_tid_t, StatfsOp*>::iterator i = statfs_ops.begin(); delete i->second; statfs_ops.erase(i->first); } while(!pool_ops.empty()) { - auto i = pool_ops.begin(); + map<ceph_tid_t, PoolOp*>::iterator i = pool_ops.begin(); delete i->second; pool_ops.erase(i->first); } ldout(cct, 20) << __func__ << " clearing up homeless session..." << dendl; while(!homeless_session->linger_ops.empty()) { - auto i = homeless_session->linger_ops.begin(); + std::map<uint64_t, LingerOp*>::iterator i + = homeless_session->linger_ops.begin(); ldout(cct, 10) << " linger_op " << i->first << dendl; LingerOp *lop = i->second; { - std::unique_lock swl(homeless_session->lock); + OSDSession::unique_lock swl(homeless_session->lock); _session_linger_op_remove(homeless_session, lop); } linger_ops.erase(lop->linger_id); @@ -470,22 +490,23 @@ void Objecter::shutdown() } while(!homeless_session->ops.empty()) { - auto i = homeless_session->ops.begin(); + std::map<ceph_tid_t, Op*>::iterator i = homeless_session->ops.begin(); ldout(cct, 10) << " op " << i->first << dendl; - auto op = i->second; + Op *op = i->second; { - std::unique_lock swl(homeless_session->lock); + OSDSession::unique_lock swl(homeless_session->lock); _session_op_remove(homeless_session, op); } op->put(); } while(!homeless_session->command_ops.empty()) { - auto i = homeless_session->command_ops.begin(); + std::map<ceph_tid_t, CommandOp*>::iterator i + = homeless_session->command_ops.begin(); ldout(cct, 10) << " command_op " << i->first << dendl; - auto cop = i->second; + CommandOp *cop = i->second; { - std::unique_lock swl(homeless_session->lock); + OSDSession::unique_lock swl(homeless_session->lock); _session_command_op_remove(homeless_session, cop); } cop->put(); @@ -511,7 +532,7 @@ void Objecter::shutdown() // This is safe because we guarantee no concurrent calls to // shutdown() with the ::initialized check at start. if (m_request_state_hook) { - auto admin_socket = cct->get_admin_socket(); + AdminSocket* admin_socket = cct->get_admin_socket(); admin_socket->unregister_commands(m_request_state_hook); delete m_request_state_hook; m_request_state_hook = NULL; @@ -519,13 +540,14 @@ void Objecter::shutdown() } void Objecter::_send_linger(LingerOp *info, - ceph::shunique_lock<ceph::shared_mutex>& sul) + shunique_lock& sul) { ceph_assert(sul.owns_lock() && sul.mutex() == &rwlock); - std::unique_ptr<Op::OpComp> oncommit; - osdc_opvec opv; - std::shared_lock watchl(info->watch_lock); - cb::list *poutbl = nullptr; + + vector<OSDOp> opv; + Context *oncommit = NULL; + LingerOp::shared_lock watchl(info->watch_lock); + ceph::buffer::list *poutbl = NULL; if (info->registered && info->is_watch) { ldout(cct, 15) << "send_linger " << info->linger_id << " reconnect" << dendl; @@ -534,28 +556,22 @@ void Objecter::_send_linger(LingerOp *info, opv.back().op.watch.cookie = info->get_cookie(); opv.back().op.watch.op = CEPH_OSD_WATCH_OP_RECONNECT; opv.back().op.watch.gen = ++info->register_gen; - oncommit = Op::OpComp::create(service.get_executor(), - CB_Linger_Reconnect(this, info)); + oncommit = new C_Linger_Reconnect(this, info); } else { ldout(cct, 15) << "send_linger " << info->linger_id << " register" << dendl; opv = info->ops; - // TODO Augment ca::Completion with an equivalent of - // target so we can handle these cases better. - auto c = std::make_unique<CB_Linger_Commit>(this, info); + C_Linger_Commit *c = new C_Linger_Commit(this, info); if (!info->is_watch) { info->notify_id = 0; poutbl = &c->outbl; } - oncommit = Op::OpComp::create(service.get_executor(), - [c = std::move(c)](bs::error_code ec) mutable { - std::move(*c)(ec); - }); + oncommit = c; } watchl.unlock(); - auto o = new Op(info->target.base_oid, info->target.base_oloc, - std::move(opv), info->target.flags | CEPH_OSD_FLAG_READ, - std::move(oncommit), info->pobjver); + Op *o = new Op(info->target.base_oid, info->target.base_oloc, + opv, info->target.flags | CEPH_OSD_FLAG_READ, + oncommit, info->pobjver); o->outbl = poutbl; o->snapid = info->snap; o->snapc = info->snapc; @@ -570,9 +586,9 @@ void Objecter::_send_linger(LingerOp *info, if (info->register_tid) { // repeat send. cancel old registration op, if any. - std::unique_lock sl(info->session->lock); + OSDSession::unique_lock sl(info->session->lock); if (info->session->ops.count(info->register_tid)) { - auto o = info->session->ops[info->register_tid]; + Op *o = info->session->ops[info->register_tid]; _op_cancel_map_check(o); _cancel_linger_op(o); } @@ -584,20 +600,17 @@ void Objecter::_send_linger(LingerOp *info, logger->inc(l_osdc_linger_send); } -void Objecter::_linger_commit(LingerOp *info, bs::error_code ec, - cb::list& outbl) +void Objecter::_linger_commit(LingerOp *info, int r, ceph::buffer::list& outbl) { - std::unique_lock wl(info->watch_lock); + LingerOp::unique_lock wl(info->watch_lock); ldout(cct, 10) << "_linger_commit " << info->linger_id << dendl; if (info->on_reg_commit) { - info->on_reg_commit->defer(std::move(info->on_reg_commit), - ec, cb::list{}); - info->on_reg_commit.reset(); + info->on_reg_commit->complete(r); + info->on_reg_commit = NULL; } - if (ec && info->on_notify_finish) { - info->on_notify_finish->defer(std::move(info->on_notify_finish), - ec, cb::list{}); - info->on_notify_finish.reset(); + if (r < 0 && info->on_notify_finish) { + info->on_notify_finish->complete(r); + info->on_notify_finish = nullptr; } // only tell the user the first time we do this @@ -612,29 +625,27 @@ void Objecter::_linger_commit(LingerOp *info, bs::error_code ec, ldout(cct, 10) << "_linger_commit notify_id=" << info->notify_id << dendl; } - catch (cb::error& e) { + catch (ceph::buffer::error& e) { } } } -class CB_DoWatchError { +struct C_DoWatchError : public Context { Objecter *objecter; Objecter::LingerOp *info; - bs::error_code ec; -public: - CB_DoWatchError(Objecter *o, Objecter::LingerOp *i, - bs::error_code ec) - : objecter(o), info(i), ec(ec) { + int err; + C_DoWatchError(Objecter *o, Objecter::LingerOp *i, int r) + : objecter(o), info(i), err(r) { info->get(); info->_queued_async(); } - void operator()() { - std::unique_lock wl(objecter->rwlock); + void finish(int r) override { + Objecter::unique_lock wl(objecter->rwlock); bool canceled = info->canceled; wl.unlock(); if (!canceled) { - info->handle(ec, 0, info->get_cookie(), 0, {}); + info->watch_context->handle_error(info->get_cookie(), err); } info->finished_async(); @@ -642,27 +653,27 @@ public: } }; -bs::error_code Objecter::_normalize_watch_error(bs::error_code ec) +int Objecter::_normalize_watch_error(int r) { // translate ENOENT -> ENOTCONN so that a delete->disconnection // notification and a failure to reconnect because we raced with // the delete appear the same to the user. - if (ec == bs::errc::no_such_file_or_directory) - ec = bs::error_code(ENOTCONN, osd_category()); - return ec; + if (r == -ENOENT) + r = -ENOTCONN; + return r; } -void Objecter::_linger_reconnect(LingerOp *info, bs::error_code ec) +void Objecter::_linger_reconnect(LingerOp *info, int r) { - ldout(cct, 10) << __func__ << " " << info->linger_id << " = " << ec + ldout(cct, 10) << __func__ << " " << info->linger_id << " = " << r << " (last_error " << info->last_error << ")" << dendl; - if (ec) { - std::unique_lock wl(info->watch_lock); + if (r < 0) { + LingerOp::unique_lock wl(info->watch_lock); if (!info->last_error) { - ec = _normalize_watch_error(ec); - info->last_error = ec; - if (info->handle) { - boost::asio::defer(finish_strand, CB_DoWatchError(this, info, ec)); + r = _normalize_watch_error(r); + info->last_error = r; + if (info->watch_context) { + finisher->queue(new C_DoWatchError(this, info, r)); } } wl.unlock(); @@ -688,48 +699,43 @@ void Objecter::_send_linger_ping(LingerOp *info) ldout(cct, 10) << __func__ << " " << info->linger_id << " now " << now << dendl; - osdc_opvec opv(1); + vector<OSDOp> opv(1); opv[0].op.op = CEPH_OSD_OP_WATCH; opv[0].op.watch.cookie = info->get_cookie(); opv[0].op.watch.op = CEPH_OSD_WATCH_OP_PING; opv[0].op.watch.gen = info->register_gen; - auto onack = new CB_Linger_Ping(this, info); + C_Linger_Ping *onack = new C_Linger_Ping(this, info); Op *o = new Op(info->target.base_oid, info->target.base_oloc, - std::move(opv), info->target.flags | CEPH_OSD_FLAG_READ, - Op::OpComp::create(service.get_executor(), - [c = std::unique_ptr<CB_Linger_Ping>(onack)] - (bs::error_code ec) mutable { - std::move(*c)(ec); - }), - nullptr, nullptr); + opv, info->target.flags | CEPH_OSD_FLAG_READ, + onack, NULL, NULL); o->target = info->target; o->should_resend = false; _send_op_account(o); o->tid = ++last_tid; _session_op_assign(info->session, o); - onack->sent = now; _send_op(o); info->ping_tid = o->tid; + onack->sent = now; logger->inc(l_osdc_linger_ping); } -void Objecter::_linger_ping(LingerOp *info, bs::error_code ec, ceph::coarse_mono_time sent, +void Objecter::_linger_ping(LingerOp *info, int r, ceph::coarse_mono_time sent, uint32_t register_gen) { - std::unique_lock l(info->watch_lock); + LingerOp::unique_lock l(info->watch_lock); ldout(cct, 10) << __func__ << " " << info->linger_id - << " sent " << sent << " gen " << register_gen << " = " << ec + << " sent " << sent << " gen " << register_gen << " = " << r << " (last_error " << info->last_error << " register_gen " << info->register_gen << ")" << dendl; if (info->register_gen == register_gen) { - if (!ec) { + if (r == 0) { info->watch_valid_thru = sent; - } else if (ec && !info->last_error) { - ec = _normalize_watch_error(ec); - info->last_error = ec; - if (info->handle) { - boost::asio::defer(finish_strand, CB_DoWatchError(this, info, ec)); + } else if (r < 0 && !info->last_error) { + r = _normalize_watch_error(r); + info->last_error = r; + if (info->watch_context) { + finisher->queue(new C_DoWatchError(this, info, r)); } } } else { @@ -737,10 +743,9 @@ void Objecter::_linger_ping(LingerOp *info, bs::error_code ec, ceph::coarse_mono } } -tl::expected<ceph::timespan, - bs::error_code> Objecter::linger_check(LingerOp *info) +int Objecter::linger_check(LingerOp *info) { - std::shared_lock l(info->watch_lock); + LingerOp::shared_lock l(info->watch_lock); ceph::coarse_mono_time stamp = info->watch_valid_thru; if (!info->watch_pending_async.empty()) @@ -751,9 +756,10 @@ tl::expected<ceph::timespan, << " err " << info->last_error << " age " << age << dendl; if (info->last_error) - return tl::unexpected(info->last_error); + return info->last_error; // return a safe upper bound (we are truncating to ms) - return age; + return + 1 + std::chrono::duration_cast<std::chrono::milliseconds>(age).count(); } void Objecter::linger_cancel(LingerOp *info) @@ -769,7 +775,7 @@ void Objecter::_linger_cancel(LingerOp *info) ldout(cct, 20) << __func__ << " linger_id=" << info->linger_id << dendl; if (!info->canceled) { OSDSession *s = info->session; - std::unique_lock sl(s->lock); + OSDSession::unique_lock sl(s->lock); _session_linger_op_remove(s, info); sl.unlock(); @@ -790,7 +796,7 @@ Objecter::LingerOp *Objecter::linger_register(const object_t& oid, const object_locator_t& oloc, int flags) { - auto info = new LingerOp(this); + LingerOp *info = new LingerOp(this); info->target.base_oid = oid; info->target.base_oloc = oloc; if (info->target.base_oloc.key == oid) @@ -818,8 +824,8 @@ ceph_tid_t Objecter::linger_watch(LingerOp *info, ObjectOperation& op, const SnapContext& snapc, real_time mtime, - cb::list& inbl, - decltype(info->on_reg_commit)&& oncommit, + ceph::buffer::list& inbl, + Context *oncommit, version_t *objver) { info->is_watch = true; @@ -828,8 +834,9 @@ ceph_tid_t Objecter::linger_watch(LingerOp *info, info->target.flags |= CEPH_OSD_FLAG_WRITE; info->ops = op.ops; info->inbl = inbl; + info->poutbl = NULL; info->pobjver = objver; - info->on_reg_commit = std::move(oncommit); + info->on_reg_commit = oncommit; info->ctx_budget = take_linger_budget(info); @@ -837,34 +844,34 @@ ceph_tid_t Objecter::linger_watch(LingerOp *info, _linger_submit(info, sul); logger->inc(l_osdc_linger_active); - op.clear(); return info->linger_id; } ceph_tid_t Objecter::linger_notify(LingerOp *info, ObjectOperation& op, - snapid_t snap, cb::list& inbl, - decltype(LingerOp::on_reg_commit)&& onfinish, + snapid_t snap, ceph::buffer::list& inbl, + ceph::buffer::list *poutbl, + Context *onfinish, version_t *objver) { info->snap = snap; info->target.flags |= CEPH_OSD_FLAG_READ; info->ops = op.ops; info->inbl = inbl; + info->poutbl = poutbl; info->pobjver = objver; - info->on_reg_commit = std::move(onfinish); - info->ctx_budget = take_linger_budget(info); + info->on_reg_commit = onfinish; + info->ctx_budget = take_linger_budget(info); + shunique_lock sul(rwlock, ceph::acquire_unique); _linger_submit(info, sul); logger->inc(l_osdc_linger_active); - op.clear(); return info->linger_id; } -void Objecter::_linger_submit(LingerOp *info, - ceph::shunique_lock<ceph::shared_mutex>& sul) +void Objecter::_linger_submit(LingerOp *info, shunique_lock& sul) { ceph_assert(sul.owns_lock() && sul.mutex() == &rwlock); ceph_assert(info->linger_id); @@ -877,7 +884,7 @@ void Objecter::_linger_submit(LingerOp *info, // Create LingerOp<->OSDSession relation int r = _get_session(info->target.osd, &s, sul); ceph_assert(r == 0); - unique_lock sl(s->lock); + OSDSession::unique_lock sl(s->lock); _session_linger_op_assign(s, info); sl.unlock(); put_session(s); @@ -885,17 +892,17 @@ void Objecter::_linger_submit(LingerOp *info, _send_linger(info, sul); } -struct CB_DoWatchNotify { +struct C_DoWatchNotify : public Context { Objecter *objecter; Objecter::LingerOp *info; MWatchNotify *msg; - CB_DoWatchNotify(Objecter *o, Objecter::LingerOp *i, MWatchNotify *m) + C_DoWatchNotify(Objecter *o, Objecter::LingerOp *i, MWatchNotify *m) : objecter(o), info(i), msg(m) { info->get(); info->_queued_async(); msg->get(); } - void operator()() { + void finish(int r) override { objecter->_do_watch_notify(info, msg); } }; @@ -912,13 +919,12 @@ void Objecter::handle_watch_notify(MWatchNotify *m) ldout(cct, 7) << __func__ << " cookie " << m->cookie << " dne" << dendl; return; } - std::unique_lock wl(info->watch_lock); + LingerOp::unique_lock wl(info->watch_lock); if (m->opcode == CEPH_WATCH_EVENT_DISCONNECT) { if (!info->last_error) { - info->last_error = bs::error_code(ENOTCONN, osd_category()); - if (info->handle) { - boost::asio::defer(finish_strand, CB_DoWatchError(this, info, - info->last_error)); + info->last_error = -ENOTCONN; + if (info->watch_context) { + finisher->queue(new C_DoWatchError(this, info, -ENOTCONN)); } } } else if (!info->is_watch) { @@ -930,16 +936,15 @@ void Objecter::handle_watch_notify(MWatchNotify *m) ldout(cct, 10) << __func__ << " reply notify " << m->notify_id << " != " << info->notify_id << ", ignoring" << dendl; } else if (info->on_notify_finish) { - info->on_notify_finish->defer( - std::move(info->on_notify_finish), - osdcode(m->return_code), std::move(m->get_data())); + info->notify_result_bl->claim(m->get_data()); + info->on_notify_finish->complete(m->return_code); // if we race with reconnect we might get a second notify; only // notify the caller once! - info->on_notify_finish = nullptr; + info->on_notify_finish = NULL; } } else { - boost::asio::defer(finish_strand, CB_DoWatchNotify(this, info, m)); + finisher->queue(new C_DoWatchNotify(this, info, m)); } } @@ -957,14 +962,15 @@ void Objecter::_do_watch_notify(LingerOp *info, MWatchNotify *m) // notify completion? ceph_assert(info->is_watch); - ceph_assert(info->handle); + ceph_assert(info->watch_context); ceph_assert(m->opcode != CEPH_WATCH_EVENT_DISCONNECT); l.unlock(); switch (m->opcode) { case CEPH_WATCH_EVENT_NOTIFY: - info->handle({}, m->notify_id, m->cookie, m->notifier_gid, std::move(m->bl)); + info->watch_context->handle_notify(m->notify_id, m->cookie, + m->notifier_gid, m->bl); break; } @@ -1030,18 +1036,18 @@ void Objecter::_scan_requests( map<ceph_tid_t, Op*>& need_resend, list<LingerOp*>& need_resend_linger, map<ceph_tid_t, CommandOp*>& need_resend_command, - ceph::shunique_lock<ceph::shared_mutex>& sul) + shunique_lock& sul) { ceph_assert(sul.owns_lock() && sul.mutex() == &rwlock); list<LingerOp*> unregister_lingers; - std::unique_lock sl(s->lock); + OSDSession::unique_lock sl(s->lock); // check for changed linger mappings (_before_ regular ops) - auto lp = s->linger_ops.begin(); + map<ceph_tid_t,LingerOp*>::iterator lp = s->linger_ops.begin(); while (lp != s->linger_ops.end()) { - auto op = lp->second; + LingerOp *op = lp->second; ceph_assert(op->session == s); // check_linger_pool_dne() may touch linger_ops; prevent iterator // invalidation @@ -1074,7 +1080,7 @@ void Objecter::_scan_requests( } // check for changed request mappings - auto p = s->ops.begin(); + map<ceph_tid_t,Op*>::iterator p = s->ops.begin(); while (p != s->ops.end()) { Op *op = p->second; ++p; // check_op_pool_dne() may touch ops; prevent iterator invalidation @@ -1103,9 +1109,9 @@ void Objecter::_scan_requests( } // commands - auto cp = s->command_ops.begin(); + map<ceph_tid_t,CommandOp*>::iterator cp = s->command_ops.begin(); while (cp != s->command_ops.end()) { - auto c = cp->second; + CommandOp *c = cp->second; ++cp; ldout(cct, 10) << " checking command " << c->tid << dendl; bool force_resend_writes = cluster_full; @@ -1134,7 +1140,7 @@ void Objecter::_scan_requests( sl.unlock(); - for (auto iter = unregister_lingers.begin(); + for (list<LingerOp*>::iterator iter = unregister_lingers.begin(); iter != unregister_lingers.end(); ++iter) { _linger_cancel(*iter); @@ -1144,7 +1150,7 @@ void Objecter::_scan_requests( void Objecter::handle_osd_map(MOSDMap *m) { - ceph::shunique_lock sul(rwlock, acquire_unique); + shunique_lock sul(rwlock, acquire_unique); if (!initialized) return; @@ -1161,7 +1167,8 @@ void Objecter::handle_osd_map(MOSDMap *m) bool was_pausewr = osdmap->test_flag(CEPH_OSDMAP_PAUSEWR) || cluster_full || _osdmap_has_pool_full(); map<int64_t, bool> pool_full_map; - for (auto it = osdmap->get_pools().begin(); + for (map<int64_t, pg_pool_t>::const_iterator it + = osdmap->get_pools().begin(); it != osdmap->get_pools().end(); ++it) pool_full_map[it->first] = _osdmap_pool_full(it->second); @@ -1234,9 +1241,9 @@ void Objecter::handle_osd_map(MOSDMap *m) _scan_requests(homeless_session, skipped_map, cluster_full, &pool_full_map, need_resend, need_resend_linger, need_resend_command, sul); - for (auto p = osd_sessions.begin(); + for (map<int,OSDSession*>::iterator p = osd_sessions.begin(); p != osd_sessions.end(); ) { - auto s = p->second; + OSDSession *s = p->second; _scan_requests(s, skipped_map, cluster_full, &pool_full_map, need_resend, need_resend_linger, need_resend_command, sul); @@ -1255,7 +1262,7 @@ void Objecter::handle_osd_map(MOSDMap *m) } else { // first map. we want the full thing. if (m->maps.count(m->get_last())) { - for (auto p = osd_sessions.begin(); + for (map<int,OSDSession*>::iterator p = osd_sessions.begin(); p != osd_sessions.end(); ++p) { OSDSession *s = p->second; _scan_requests(s, false, false, NULL, need_resend, @@ -1306,10 +1313,10 @@ void Objecter::handle_osd_map(MOSDMap *m) } // resend requests - for (auto p = need_resend.begin(); + for (map<ceph_tid_t, Op*>::iterator p = need_resend.begin(); p != need_resend.end(); ++p) { - auto op = p->second; - auto s = op->session; + Op *op = p->second; + OSDSession *s = op->session; bool mapped_session = false; if (!s) { int r = _map_session(&op->target, &s, sul); @@ -1318,7 +1325,7 @@ void Objecter::handle_osd_map(MOSDMap *m) } else { get_session(s); } - std::unique_lock sl(s->lock); + OSDSession::unique_lock sl(s->lock); if (mapped_session) { _session_op_assign(s, op); } @@ -1334,7 +1341,7 @@ void Objecter::handle_osd_map(MOSDMap *m) sl.unlock(); put_session(s); } - for (auto p = need_resend_linger.begin(); + for (list<LingerOp*>::iterator p = need_resend_linger.begin(); p != need_resend_linger.end(); ++p) { LingerOp *op = *p; ceph_assert(op->session); @@ -1343,9 +1350,9 @@ void Objecter::handle_osd_map(MOSDMap *m) _send_linger(op, sul); } } - for (auto p = need_resend_command.begin(); + for (map<ceph_tid_t,CommandOp*>::iterator p = need_resend_command.begin(); p != need_resend_command.end(); ++p) { - auto c = p->second; + CommandOp *c = p->second; if (c->target.osd >= 0) { _assign_command_session(c, sul); if (c->session && !c->session->is_homeless()) { @@ -1357,12 +1364,14 @@ void Objecter::handle_osd_map(MOSDMap *m) _dump_active(); // finish any Contexts that were waiting on a map update - auto p = waiting_for_map.begin(); + map<epoch_t,list< pair< Context*, int > > >::iterator p = + waiting_for_map.begin(); while (p != waiting_for_map.end() && p->first <= osdmap->get_epoch()) { //go through the list and call the onfinish methods - for (auto& [c, ec] : p->second) { - ca::post(std::move(c), ec); + for (list<pair<Context*, int> >::iterator i = p->second.begin(); + i != p->second.end(); ++i) { + i->first->complete(i->second); } waiting_for_map.erase(p++); } @@ -1428,20 +1437,19 @@ void Objecter::emit_blacklist_events(const OSDMap &old_osd_map, // op pool check -void Objecter::CB_Op_Map_Latest::operator()(bs::error_code e, - version_t latest, version_t) +void Objecter::C_Op_Map_Latest::finish(int r) { - if (e == bs::errc::resource_unavailable_try_again || - e == bs::errc::operation_canceled) + if (r == -EAGAIN || r == -ECANCELED) return; lgeneric_subdout(objecter->cct, objecter, 10) - << "op_map_latest r=" << e << " tid=" << tid + << "op_map_latest r=" << r << " tid=" << tid << " latest " << latest << dendl; - unique_lock wl(objecter->rwlock); + Objecter::unique_lock wl(objecter->rwlock); - auto iter = objecter->check_latest_map_ops.find(tid); + map<ceph_tid_t, Op*>::iterator iter = + objecter->check_latest_map_ops.find(tid); if (iter == objecter->check_latest_map_ops.end()) { lgeneric_subdout(objecter->cct, objecter, 10) << "op_map_latest op "<< tid << " not found" << dendl; @@ -1457,7 +1465,7 @@ void Objecter::CB_Op_Map_Latest::operator()(bs::error_code e, if (op->map_dne_bound == 0) op->map_dne_bound = latest; - unique_lock sl(op->session->lock, defer_lock); + OSDSession::unique_lock sl(op->session->lock, defer_lock); objecter->_check_op_pool_dne(op, &sl); op->put(); @@ -1511,7 +1519,7 @@ int Objecter::pool_snap_list(int64_t poolid, vector<uint64_t> *snaps) const pg_pool_t *pi = osdmap->get_pg_pool(poolid); if (!pi) return -ENOENT; - for (auto p = pi->snaps.begin(); + for (map<snapid_t,pool_snap_info_t>::const_iterator p = pi->snaps.begin(); p != pi->snaps.end(); ++p) { snaps->push_back(p->first); @@ -1520,7 +1528,7 @@ int Objecter::pool_snap_list(int64_t poolid, vector<uint64_t> *snaps) } // sl may be unlocked. -void Objecter::_check_op_pool_dne(Op *op, std::unique_lock<ceph::shared_mutex> *sl) +void Objecter::_check_op_pool_dne(Op *op, unique_lock *sl) { // rwlock is locked unique @@ -1543,9 +1551,9 @@ void Objecter::_check_op_pool_dne(Op *op, std::unique_lock<ceph::shared_mutex> * ldout(cct, 10) << "check_op_pool_dne tid " << op->tid << " concluding pool " << op->target.base_pgid.pool() << " dne" << dendl; - if (op->has_completion()) { + if (op->onfinish) { num_in_flight--; - op->complete(osdc_errc::pool_dne, -ENOENT); + op->onfinish->complete(-ENOENT); } OSDSession *s = op->session; @@ -1576,14 +1584,16 @@ void Objecter::_send_op_map_check(Op *op) if (check_latest_map_ops.count(op->tid) == 0) { op->get(); check_latest_map_ops[op->tid] = op; - monc->get_version("osdmap", CB_Op_Map_Latest(this, op->tid)); + C_Op_Map_Latest *c = new C_Op_Map_Latest(this, op->tid); + monc->get_version("osdmap", &c->latest, NULL, c); } } void Objecter::_op_cancel_map_check(Op *op) { // rwlock is locked unique - auto iter = check_latest_map_ops.find(op->tid); + map<ceph_tid_t, Op*>::iterator iter = + check_latest_map_ops.find(op->tid); if (iter != check_latest_map_ops.end()) { Op *op = iter->second; op->put(); @@ -1593,24 +1603,22 @@ void Objecter::_op_cancel_map_check(Op *op) // linger pool check -void Objecter::CB_Linger_Map_Latest::operator()(bs::error_code e, - version_t latest, - version_t) +void Objecter::C_Linger_Map_Latest::finish(int r) { - if (e == bs::errc::resource_unavailable_try_again || - e == bs::errc::operation_canceled) { + if (r == -EAGAIN || r == -ECANCELED) { // ignore callback; we will retry in resend_mon_ops() return; } unique_lock wl(objecter->rwlock); - auto iter = objecter->check_latest_map_lingers.find(linger_id); + map<uint64_t, LingerOp*>::iterator iter = + objecter->check_latest_map_lingers.find(linger_id); if (iter == objecter->check_latest_map_lingers.end()) { return; } - auto op = iter->second; + LingerOp *op = iter->second; objecter->check_latest_map_lingers.erase(iter); if (op->map_dne_bound == 0) @@ -1645,15 +1653,13 @@ void Objecter::_check_linger_pool_dne(LingerOp *op, bool *need_unregister) } if (op->map_dne_bound > 0) { if (osdmap->get_epoch() >= op->map_dne_bound) { - std::unique_lock wl{op->watch_lock}; + LingerOp::unique_lock wl{op->watch_lock}; if (op->on_reg_commit) { - op->on_reg_commit->defer(std::move(op->on_reg_commit), - osdc_errc::pool_dne, cb::list{}); + op->on_reg_commit->complete(-ENOENT); op->on_reg_commit = nullptr; } if (op->on_notify_finish) { - op->on_notify_finish->defer(std::move(op->on_notify_finish), - osdc_errc::pool_dne, cb::list{}); + op->on_notify_finish->complete(-ENOENT); op->on_notify_finish = nullptr; } *need_unregister = true; @@ -1669,7 +1675,8 @@ void Objecter::_send_linger_map_check(LingerOp *op) if (check_latest_map_lingers.count(op->linger_id) == 0) { op->get(); check_latest_map_lingers[op->linger_id] = op; - monc->get_version("osdmap", CB_Linger_Map_Latest(this, op->linger_id)); + C_Linger_Map_Latest *c = new C_Linger_Map_Latest(this, op->linger_id); + monc->get_version("osdmap", &c->latest, NULL, c); } } @@ -1677,7 +1684,8 @@ void Objecter::_linger_cancel_map_check(LingerOp *op) { // rwlock is locked unique - auto iter = check_latest_map_lingers.find(op->linger_id); + map<uint64_t, LingerOp*>::iterator iter = + check_latest_map_lingers.find(op->linger_id); if (iter != check_latest_map_lingers.end()) { LingerOp *op = iter->second; op->put(); @@ -1687,29 +1695,28 @@ void Objecter::_linger_cancel_map_check(LingerOp *op) // command pool check -void Objecter::CB_Command_Map_Latest::operator()(bs::error_code e, - version_t latest, version_t) +void Objecter::C_Command_Map_Latest::finish(int r) { - if (e == bs::errc::resource_unavailable_try_again || - e == bs::errc::operation_canceled) { + if (r == -EAGAIN || r == -ECANCELED) { // ignore callback; we will retry in resend_mon_ops() return; } unique_lock wl(objecter->rwlock); - auto iter = objecter->check_latest_map_commands.find(tid); + map<uint64_t, CommandOp*>::iterator iter = + objecter->check_latest_map_commands.find(tid); if (iter == objecter->check_latest_map_commands.end()) { return; } - auto c = iter->second; + CommandOp *c = iter->second; objecter->check_latest_map_commands.erase(iter); if (c->map_dne_bound == 0) c->map_dne_bound = latest; - unique_lock sul(c->session->lock); + OSDSession::unique_lock sul(c->session->lock); objecter->_check_command_map_dne(c); sul.unlock(); @@ -1727,8 +1734,7 @@ void Objecter::_check_command_map_dne(CommandOp *c) << dendl; if (c->map_dne_bound > 0) { if (osdmap->get_epoch() >= c->map_dne_bound) { - _finish_command(c, osdcode(c->map_check_error), - std::move(c->map_check_error_str), {}); + _finish_command(c, c->map_check_error, c->map_check_error_str); } } else { _send_command_map_check(c); @@ -1744,7 +1750,8 @@ void Objecter::_send_command_map_check(CommandOp *c) if (check_latest_map_commands.count(c->tid) == 0) { c->get(); check_latest_map_commands[c->tid] = c; - monc->get_version("osdmap", CB_Command_Map_Latest(this, c->tid)); + C_Command_Map_Latest *f = new C_Command_Map_Latest(this, c->tid); + monc->get_version("osdmap", &f->latest, NULL, f); } } @@ -1752,9 +1759,10 @@ void Objecter::_command_cancel_map_check(CommandOp *c) { // rwlock is locked uniqe - auto iter = check_latest_map_commands.find(c->tid); + map<uint64_t, CommandOp*>::iterator iter = + check_latest_map_commands.find(c->tid); if (iter != check_latest_map_commands.end()) { - auto c = iter->second; + CommandOp *c = iter->second; c->put(); check_latest_map_commands.erase(iter); } @@ -1767,8 +1775,7 @@ void Objecter::_command_cancel_map_check(CommandOp *c) * @returns 0 on success, or -EAGAIN if the lock context requires * promotion to write. */ -int Objecter::_get_session(int osd, OSDSession **session, - shunique_lock<ceph::shared_mutex>& sul) +int Objecter::_get_session(int osd, OSDSession **session, shunique_lock& sul) { ceph_assert(sul && sul.mutex() == &rwlock); @@ -1779,9 +1786,9 @@ int Objecter::_get_session(int osd, OSDSession **session, return 0; } - auto p = osd_sessions.find(osd); + map<int,OSDSession*>::iterator p = osd_sessions.find(osd); if (p != osd_sessions.end()) { - auto s = p->second; + OSDSession *s = p->second; s->get(); *session = s; ldout(cct, 20) << __func__ << " s=" << s << " osd=" << osd << " " @@ -1791,7 +1798,7 @@ int Objecter::_get_session(int osd, OSDSession **session, if (!sul.owns_lock()) { return -EAGAIN; } - auto s = new OSDSession(cct, osd); + OSDSession *s = new OSDSession(cct, osd); osd_sessions[osd] = s; s->con = messenger->connect_to_osd(osdmap->get_addrs(osd)); s->con->set_priv(RefCountedPtr{s}); @@ -1853,28 +1860,28 @@ void Objecter::close_session(OSDSession *s) s->con->mark_down(); logger->inc(l_osdc_osd_session_close); } - unique_lock sl(s->lock); + OSDSession::unique_lock sl(s->lock); std::list<LingerOp*> homeless_lingers; std::list<CommandOp*> homeless_commands; std::list<Op*> homeless_ops; while (!s->linger_ops.empty()) { - auto i = s->linger_ops.begin(); + std::map<uint64_t, LingerOp*>::iterator i = s->linger_ops.begin(); ldout(cct, 10) << " linger_op " << i->first << dendl; homeless_lingers.push_back(i->second); _session_linger_op_remove(s, i->second); } while (!s->ops.empty()) { - auto i = s->ops.begin(); + std::map<ceph_tid_t, Op*>::iterator i = s->ops.begin(); ldout(cct, 10) << " op " << i->first << dendl; homeless_ops.push_back(i->second); _session_op_remove(s, i->second); } while (!s->command_ops.empty()) { - auto i = s->command_ops.begin(); + std::map<ceph_tid_t, CommandOp*>::iterator i = s->command_ops.begin(); ldout(cct, 10) << " command_op " << i->first << dendl; homeless_commands.push_back(i->second); _session_command_op_remove(s, i->second); @@ -1886,16 +1893,16 @@ void Objecter::close_session(OSDSession *s) // Assign any leftover ops to the homeless session { - unique_lock hsl(homeless_session->lock); - for (auto i = homeless_lingers.begin(); + OSDSession::unique_lock hsl(homeless_session->lock); + for (std::list<LingerOp*>::iterator i = homeless_lingers.begin(); i != homeless_lingers.end(); ++i) { _session_linger_op_assign(homeless_session, *i); } - for (auto i = homeless_ops.begin(); + for (std::list<Op*>::iterator i = homeless_ops.begin(); i != homeless_ops.end(); ++i) { _session_op_assign(homeless_session, *i); } - for (auto i = homeless_commands.begin(); + for (std::list<CommandOp*>::iterator i = homeless_commands.begin(); i != homeless_commands.end(); ++i) { _session_command_op_assign(homeless_session, *i); } @@ -1912,29 +1919,55 @@ void Objecter::wait_for_osd_map() return; } - ca::waiter<bs::error_code> w; - waiting_for_map[0].emplace_back(OpCompletion::create( - service.get_executor(), - w.ref()), - bs::error_code{}); + // Leave this since it goes with C_SafeCond + ceph::mutex lock = ceph::make_mutex(""); + ceph::condition_variable cond; + bool done; + std::unique_lock mlock{lock}; + C_SafeCond *context = new C_SafeCond(lock, cond, &done, NULL); + waiting_for_map[0].push_back(pair<Context*, int>(context, 0)); l.unlock(); - w.wait(); + cond.wait(mlock, [&done] { return done; }); +} + +struct C_Objecter_GetVersion : public Context { + Objecter *objecter; + uint64_t oldest, newest; + Context *fin; + C_Objecter_GetVersion(Objecter *o, Context *c) + : objecter(o), oldest(0), newest(0), fin(c) {} + void finish(int r) override { + if (r >= 0) { + objecter->get_latest_version(oldest, newest, fin); + } else if (r == -EAGAIN) { // try again as instructed + objecter->wait_for_latest_osdmap(fin); + } else { + // it doesn't return any other error codes! + ceph_abort(); + } + } +}; + +void Objecter::wait_for_latest_osdmap(Context *fin) +{ + ldout(cct, 10) << __func__ << dendl; + C_Objecter_GetVersion *c = new C_Objecter_GetVersion(this, fin); + monc->get_version("osdmap", &c->newest, &c->oldest, c); } -void Objecter::_get_latest_version(epoch_t oldest, epoch_t newest, - std::unique_ptr<OpCompletion> fin, - std::unique_lock<ceph::shared_mutex>&& l) +void Objecter::get_latest_version(epoch_t oldest, epoch_t newest, Context *fin) { - ceph_assert(fin); + unique_lock wl(rwlock); if (osdmap->get_epoch() >= newest) { ldout(cct, 10) << __func__ << " latest " << newest << ", have it" << dendl; - l.unlock(); - ca::defer(std::move(fin), bs::error_code{}); - } else { - ldout(cct, 10) << __func__ << " latest " << newest << ", waiting" << dendl; - _wait_for_new_map(std::move(fin), newest, bs::error_code{}); - l.unlock(); + wl.unlock(); + if (fin) + fin->complete(0); + return; } + + ldout(cct, 10) << __func__ << " latest " << newest << ", waiting" << dendl; + _wait_for_new_map(fin, newest, 0); } void Objecter::maybe_request_map() @@ -1963,11 +1996,10 @@ void Objecter::_maybe_request_map() } } -void Objecter::_wait_for_new_map(std::unique_ptr<OpCompletion> c, epoch_t epoch, - bs::error_code ec) +void Objecter::_wait_for_new_map(Context *c, epoch_t epoch, int err) { // rwlock is locked unique - waiting_for_map[epoch].emplace_back(std::move(c), ec); + waiting_for_map[epoch].push_back(pair<Context *, int>(c, err)); _maybe_request_map(); } @@ -1992,6 +2024,16 @@ bool Objecter::have_map(const epoch_t epoch) } } +bool Objecter::wait_for_map(epoch_t epoch, Context *c, int err) +{ + unique_lock wl(rwlock); + if (osdmap->get_epoch() >= epoch) { + return true; + } + _wait_for_new_map(c, epoch, err); + return false; +} + void Objecter::_kick_requests(OSDSession *session, map<uint64_t, LingerOp *>& lresend) { @@ -2003,7 +2045,8 @@ void Objecter::_kick_requests(OSDSession *session, // resend ops map<ceph_tid_t,Op*> resend; // resend in tid order - for (auto p = session->ops.begin(); p != session->ops.end();) { + for (map<ceph_tid_t, Op*>::iterator p = session->ops.begin(); + p != session->ops.end();) { Op *op = p->second; ++p; if (op->should_resend) { @@ -2023,7 +2066,7 @@ void Objecter::_kick_requests(OSDSession *session, // resend lingers logger->inc(l_osdc_linger_resend, session->linger_ops.size()); - for (auto j = session->linger_ops.begin(); + for (map<ceph_tid_t, LingerOp*>::iterator j = session->linger_ops.begin(); j != session->linger_ops.end(); ++j) { LingerOp *op = j->second; op->get(); @@ -2034,7 +2077,7 @@ void Objecter::_kick_requests(OSDSession *session, // resend commands logger->inc(l_osdc_command_resend, session->command_ops.size()); map<uint64_t,CommandOp*> cresend; // resend in order - for (auto k = session->command_ops.begin(); + for (map<ceph_tid_t, CommandOp*>::iterator k = session->command_ops.begin(); k != session->command_ops.end(); ++k) { cresend[k->first] = k->second; } @@ -2045,7 +2088,7 @@ void Objecter::_kick_requests(OSDSession *session, } void Objecter::_linger_ops_resend(map<uint64_t, LingerOp *>& lresend, - unique_lock<ceph::shared_mutex>& ul) + unique_lock& ul) { ceph_assert(ul.owns_lock()); shunique_lock sul(std::move(ul)); @@ -2092,13 +2135,15 @@ void Objecter::tick() unsigned laggy_ops = 0; - for (auto siter = osd_sessions.begin(); + for (map<int,OSDSession*>::iterator siter = osd_sessions.begin(); siter != osd_sessions.end(); ++siter) { - auto s = siter->second; - scoped_lock l(s->lock); + OSDSession *s = siter->second; + OSDSession::lock_guard l(s->lock); bool found = false; - for (auto p = s->ops.begin(); p != s->ops.end(); ++p) { - auto op = p->second; + for (map<ceph_tid_t,Op*>::iterator p = s->ops.begin(); + p != s->ops.end(); + ++p) { + Op *op = p->second; ceph_assert(op->session); if (op->stamp < cutoff) { ldout(cct, 2) << " tid " << p->first << " on osd." << op->session->osd @@ -2107,11 +2152,11 @@ void Objecter::tick() ++laggy_ops; } } - for (auto p = s->linger_ops.begin(); + for (map<uint64_t,LingerOp*>::iterator p = s->linger_ops.begin(); p != s->linger_ops.end(); ++p) { - auto op = p->second; - std::unique_lock wl(op->watch_lock); + LingerOp *op = p->second; + LingerOp::unique_lock wl(op->watch_lock); ceph_assert(op->session); ldout(cct, 10) << " pinging osd that serves lingering tid " << p->first << " (osd." << op->session->osd << ")" << dendl; @@ -2119,10 +2164,10 @@ void Objecter::tick() if (op->is_watch && op->registered && !op->last_error) _send_linger_ping(op); } - for (auto p = s->command_ops.begin(); + for (map<uint64_t,CommandOp*>::iterator p = s->command_ops.begin(); p != s->command_ops.end(); ++p) { - auto op = p->second; + CommandOp *op = p->second; ceph_assert(op->session); ldout(cct, 10) << " pinging osd that serves command tid " << p->first << " (osd." << op->session->osd << ")" << dendl; @@ -2141,7 +2186,9 @@ void Objecter::tick() if (!toping.empty()) { // send a ping to these osds, to ensure we detect any session resets // (osd reply message policy is lossy) - for (auto i = toping.begin(); i != toping.end(); ++i) { + for (set<OSDSession*>::const_iterator i = toping.begin(); + i != toping.end(); + ++i) { (*i)->con->send_message(new MPing); } } @@ -2159,37 +2206,48 @@ void Objecter::resend_mon_ops() ldout(cct, 10) << "resend_mon_ops" << dendl; - for (auto p = poolstat_ops.begin(); p != poolstat_ops.end(); ++p) { + for (map<ceph_tid_t,PoolStatOp*>::iterator p = poolstat_ops.begin(); + p != poolstat_ops.end(); + ++p) { _poolstat_submit(p->second); logger->inc(l_osdc_poolstat_resend); } - for (auto p = statfs_ops.begin(); p != statfs_ops.end(); ++p) { + for (map<ceph_tid_t,StatfsOp*>::iterator p = statfs_ops.begin(); + p != statfs_ops.end(); + ++p) { _fs_stats_submit(p->second); logger->inc(l_osdc_statfs_resend); } - for (auto p = pool_ops.begin(); p != pool_ops.end(); ++p) { + for (map<ceph_tid_t,PoolOp*>::iterator p = pool_ops.begin(); + p != pool_ops.end(); + ++p) { _pool_op_submit(p->second); logger->inc(l_osdc_poolop_resend); } - for (auto p = check_latest_map_ops.begin(); + for (map<ceph_tid_t, Op*>::iterator p = check_latest_map_ops.begin(); p != check_latest_map_ops.end(); ++p) { - monc->get_version("osdmap", CB_Op_Map_Latest(this, p->second->tid)); + C_Op_Map_Latest *c = new C_Op_Map_Latest(this, p->second->tid); + monc->get_version("osdmap", &c->latest, NULL, c); } - for (auto p = check_latest_map_lingers.begin(); + for (map<uint64_t, LingerOp*>::iterator p = check_latest_map_lingers.begin(); p != check_latest_map_lingers.end(); ++p) { - monc->get_version("osdmap", CB_Linger_Map_Latest(this, p->second->linger_id)); + C_Linger_Map_Latest *c + = new C_Linger_Map_Latest(this, p->second->linger_id); + monc->get_version("osdmap", &c->latest, NULL, c); } - for (auto p = check_latest_map_commands.begin(); + for (map<uint64_t, CommandOp*>::iterator p + = check_latest_map_commands.begin(); p != check_latest_map_commands.end(); ++p) { - monc->get_version("osdmap", CB_Command_Map_Latest(this, p->second->tid)); + C_Command_Map_Latest *c = new C_Command_Map_Latest(this, p->second->tid); + monc->get_version("osdmap", &c->latest, NULL, c); } } @@ -2205,8 +2263,7 @@ void Objecter::op_submit(Op *op, ceph_tid_t *ptid, int *ctx_budget) _op_submit_with_budget(op, rl, ptid, ctx_budget); } -void Objecter::_op_submit_with_budget(Op *op, - shunique_lock<ceph::shared_mutex>& sul, +void Objecter::_op_submit_with_budget(Op *op, shunique_lock& sul, ceph_tid_t *ptid, int *ctx_budget) { @@ -2244,7 +2301,7 @@ void Objecter::_send_op_account(Op *op) inflight_ops++; // add to gather set(s) - if (op->has_completion()) { + if (op->onfinish) { num_in_flight++; } else { ldout(cct, 20) << " note: not requesting reply" << dendl; @@ -2252,7 +2309,6 @@ void Objecter::_send_op_account(Op *op) logger->inc(l_osdc_op_active); logger->inc(l_osdc_op); - logger->inc(l_osdc_oplen_avg, op->ops.size()); if ((op->target.flags & (CEPH_OSD_FLAG_READ | CEPH_OSD_FLAG_WRITE)) == (CEPH_OSD_FLAG_READ|CEPH_OSD_FLAG_WRITE)) @@ -2265,7 +2321,7 @@ void Objecter::_send_op_account(Op *op) if (op->target.flags & CEPH_OSD_FLAG_PGOP) logger->inc(l_osdc_op_pg); - for (auto p = op->ops.begin(); p != op->ops.end(); ++p) { + for (vector<OSDOp>::iterator p = op->ops.begin(); p != op->ops.end(); ++p) { int code = l_osdc_osdop_other; switch (p->op.op) { case CEPH_OSD_OP_STAT: code = l_osdc_osdop_stat; break; @@ -2310,7 +2366,7 @@ void Objecter::_send_op_account(Op *op) } } -void Objecter::_op_submit(Op *op, shunique_lock<ceph::shared_mutex>& sul, ceph_tid_t *ptid) +void Objecter::_op_submit(Op *op, shunique_lock& sul, ceph_tid_t *ptid) { // rwlock is locked @@ -2396,7 +2452,7 @@ void Objecter::_op_submit(Op *op, shunique_lock<ceph::shared_mutex>& sul, ceph_t _maybe_request_map(); } - unique_lock sl(s->lock); + OSDSession::unique_lock sl(s->lock); if (op->tid == 0) op->tid = ++last_tid; @@ -2432,9 +2488,9 @@ int Objecter::op_cancel(OSDSession *s, ceph_tid_t tid, int r) { ceph_assert(initialized); - unique_lock sl(s->lock); + OSDSession::unique_lock sl(s->lock); - auto p = s->ops.find(tid); + map<ceph_tid_t, Op*>::iterator p = s->ops.find(tid); if (p == s->ops.end()) { ldout(cct, 10) << __func__ << " tid " << tid << " dne in session " << s->osd << dendl; @@ -2452,9 +2508,10 @@ int Objecter::op_cancel(OSDSession *s, ceph_tid_t tid, int r) ldout(cct, 10) << __func__ << " tid " << tid << " in session " << s->osd << dendl; Op *op = p->second; - if (op->has_completion()) { + if (op->onfinish) { num_in_flight--; - op->complete(osdcode(r), r); + op->onfinish->complete(r); + op->onfinish = NULL; } _op_cancel_map_check(op); _finish_op(op, r); @@ -2492,10 +2549,10 @@ int Objecter::_op_cancel(ceph_tid_t tid, int r) start: - for (auto siter = osd_sessions.begin(); + for (map<int, OSDSession *>::iterator siter = osd_sessions.begin(); siter != osd_sessions.end(); ++siter) { OSDSession *s = siter->second; - shared_lock sl(s->lock); + OSDSession::shared_lock sl(s->lock); if (s->ops.find(tid) != s->ops.end()) { sl.unlock(); ret = op_cancel(s, tid, r); @@ -2511,7 +2568,7 @@ start: << " not found in live sessions" << dendl; // Handle case where the op is in homeless session - shared_lock sl(homeless_session->lock); + OSDSession::shared_lock sl(homeless_session->lock); if (homeless_session->ops.find(tid) != homeless_session->ops.end()) { sl.unlock(); ret = op_cancel(homeless_session, tid, r); @@ -2539,11 +2596,11 @@ epoch_t Objecter::op_cancel_writes(int r, int64_t pool) std::vector<ceph_tid_t> to_cancel; bool found = false; - for (auto siter = osd_sessions.begin(); + for (map<int, OSDSession *>::iterator siter = osd_sessions.begin(); siter != osd_sessions.end(); ++siter) { OSDSession *s = siter->second; - shared_lock sl(s->lock); - for (auto op_i = s->ops.begin(); + OSDSession::shared_lock sl(s->lock); + for (map<ceph_tid_t, Op*>::iterator op_i = s->ops.begin(); op_i != s->ops.end(); ++op_i) { if (op_i->second->target.flags & CEPH_OSD_FLAG_WRITE && (pool == -1 || op_i->second->target.target_oloc.pool == pool)) { @@ -2552,7 +2609,9 @@ epoch_t Objecter::op_cancel_writes(int r, int64_t pool) } sl.unlock(); - for (auto titer = to_cancel.begin(); titer != to_cancel.end(); ++titer) { + for (std::vector<ceph_tid_t>::iterator titer = to_cancel.begin(); + titer != to_cancel.end(); + ++titer) { int cancel_result = op_cancel(s, *titer, r); // We hold rwlock across search and cancellation, so cancels // should always succeed @@ -2638,7 +2697,8 @@ bool Objecter::_osdmap_pool_full(const int64_t pool_id) const bool Objecter::_osdmap_has_pool_full() const { - for (auto it = osdmap->get_pools().begin(); + for (map<int64_t, pg_pool_t>::const_iterator it + = osdmap->get_pools().begin(); it != osdmap->get_pools().end(); ++it) { if (_osdmap_pool_full(it->second)) return true; @@ -2944,7 +3004,7 @@ int Objecter::_calc_target(op_target_t *t, Connection *con, bool any_change) } int Objecter::_map_session(op_target_t *target, OSDSession **s, - shunique_lock<ceph::shared_mutex>& sul) + shunique_lock& sul) { _calc_target(target, nullptr); return _get_session(target->osd, s, sul); @@ -3051,7 +3111,7 @@ void Objecter::_session_command_op_assign(OSDSession *to, CommandOp *op) } int Objecter::_recalc_linger_op_target(LingerOp *linger_op, - shunique_lock<ceph::shared_mutex>& sul) + shunique_lock& sul) { // rwlock is locked unique @@ -3070,7 +3130,7 @@ int Objecter::_recalc_linger_op_target(LingerOp *linger_op, // same time here is only safe because we are the only one that // takes two, and we are holding rwlock for write. Disable // lockdep because it doesn't know that. - unique_lock sl(s->lock); + OSDSession::unique_lock sl(s->lock); _session_linger_op_remove(linger_op->session, linger_op); _session_linger_op_assign(s, linger_op); } @@ -3086,8 +3146,8 @@ void Objecter::_cancel_linger_op(Op *op) ldout(cct, 15) << "cancel_op " << op->tid << dendl; ceph_assert(!op->should_resend); - if (op->has_completion()) { - op->onfinish = nullptr; + if (op->onfinish) { + delete op->onfinish; num_in_flight--; } @@ -3121,7 +3181,7 @@ void Objecter::_finish_op(Op *op, int r) op->put(); } -Objecter::MOSDOp *Objecter::_prepare_osd_op(Op *op) +MOSDOp *Objecter::_prepare_osd_op(Op *op) { // rwlock is locked @@ -3139,10 +3199,10 @@ Objecter::MOSDOp *Objecter::_prepare_osd_op(Op *op) op->stamp = ceph::coarse_mono_clock::now(); hobject_t hobj = op->target.get_hobj(); - auto m = new MOSDOp(client_inc, op->tid, - hobj, op->target.actual_pgid, - osdmap->get_epoch(), - flags, op->features); + MOSDOp *m = new MOSDOp(client_inc, op->tid, + hobj, op->target.actual_pgid, + osdmap->get_epoch(), + flags, op->features); m->set_snapid(op->snapid); m->set_snap_seq(op->snapc.seq); @@ -3248,10 +3308,12 @@ void Objecter::_send_op(Op *op) op->session->con->send_message(m); } -int Objecter::calc_op_budget(const bc::small_vector_base<OSDOp>& ops) +int Objecter::calc_op_budget(const vector<OSDOp>& ops) { int op_budget = 0; - for (auto i = ops.begin(); i != ops.end(); ++i) { + for (vector<OSDOp>::const_iterator i = ops.begin(); + i != ops.end(); + ++i) { if (i->op.op & CEPH_OSD_OP_MODE_WR) { op_budget += i->indata.length(); } else if (ceph_osd_op_mode_read(i->op.op)) { @@ -3267,7 +3329,7 @@ int Objecter::calc_op_budget(const bc::small_vector_base<OSDOp>& ops) } void Objecter::_throttle_op(Op *op, - shunique_lock<ceph::shared_mutex>& sul, + shunique_lock& sul, int op_budget) { ceph_assert(sul && sul.mutex() == &rwlock); @@ -3321,7 +3383,7 @@ void Objecter::handle_osd_op_reply(MOSDOpReply *m) return; } - unique_lock sl(s->lock); + OSDSession::unique_lock sl(s->lock); map<ceph_tid_t, Op *>::iterator iter = s->ops.find(tid); if (iter == s->ops.end()) { @@ -3347,7 +3409,7 @@ void Objecter::handle_osd_op_reply(MOSDOpReply *m) if (retry_writes_after_first_reply && op->attempts == 1 && (op->target.flags & CEPH_OSD_FLAG_WRITE)) { ldout(cct, 7) << "retrying write after first reply: " << tid << dendl; - if (op->has_completion()) { + if (op->onfinish) { num_in_flight--; } _session_op_remove(s, op); @@ -3375,13 +3437,13 @@ void Objecter::handle_osd_op_reply(MOSDOpReply *m) // have, but that is better than doing callbacks out of order. } - decltype(op->onfinish) onfinish; + Context *onfinish = 0; int rc = m->get_result(); if (m->is_redirect_reply()) { ldout(cct, 5) << " got redirect reply; redirecting" << dendl; - if (op->has_completion()) + if (op->onfinish) num_in_flight--; _session_op_remove(s, op); sl.unlock(); @@ -3401,7 +3463,7 @@ void Objecter::handle_osd_op_reply(MOSDOpReply *m) if (rc == -EAGAIN) { ldout(cct, 7) << " got -EAGAIN, resubmitting" << dendl; - if (op->has_completion()) + if (op->onfinish) num_in_flight--; _session_op_remove(s, op); sl.unlock(); @@ -3439,7 +3501,7 @@ void Objecter::handle_osd_op_reply(MOSDOpReply *m) ldout(cct,10) << __func__ << " copying resulting " << bl.length() << " into existing ceph::buffer of length " << op->outbl->length() << dendl; - cb::list t; + ceph::buffer::list t; t.claim(*op->outbl); t.invalidate_crc(); // we're overwriting the raw buffers via c_str() bl.copy(0, bl.length(), t.c_str()); @@ -3459,20 +3521,15 @@ void Objecter::handle_osd_op_reply(MOSDOpReply *m) << " != request ops " << op->ops << " from " << m->get_source_inst() << dendl; - ceph_assert(op->ops.size() == op->out_bl.size()); - ceph_assert(op->ops.size() == op->out_rval.size()); - ceph_assert(op->ops.size() == op->out_ec.size()); - ceph_assert(op->ops.size() == op->out_handler.size()); - auto pb = op->out_bl.begin(); - auto pr = op->out_rval.begin(); - auto pe = op->out_ec.begin(); - auto ph = op->out_handler.begin(); + vector<ceph::buffer::list*>::iterator pb = op->out_bl.begin(); + vector<int*>::iterator pr = op->out_rval.begin(); + vector<Context*>::iterator ph = op->out_handler.begin(); ceph_assert(op->out_bl.size() == op->out_rval.size()); ceph_assert(op->out_bl.size() == op->out_handler.size()); - auto p = out_ops.begin(); + vector<OSDOp>::iterator p = out_ops.begin(); for (unsigned i = 0; p != out_ops.end() && pb != op->out_bl.end(); - ++i, ++p, ++pb, ++pr, ++pe, ++ph) { + ++i, ++p, ++pb, ++pr, ++ph) { ldout(cct, 10) << " op " << i << " rval " << p->rval << " len " << p->outdata.length() << dendl; if (*pb) @@ -3481,22 +3538,20 @@ void Objecter::handle_osd_op_reply(MOSDOpReply *m) // can change it if e.g. decoding fails if (*pr) **pr = ceph_to_hostos_errno(p->rval); - if (*pe) - **pe = p->rval < 0 ? bs::error_code(-p->rval, osd_category()) : - bs::error_code(); if (*ph) { - std::move((*ph))(bs::error_code(-p->rval, osd_category()), - p->rval, p->outdata); + ldout(cct, 10) << " op " << i << " handler " << *ph << dendl; + (*ph)->complete(ceph_to_hostos_errno(p->rval)); + *ph = NULL; } } // NOTE: we assume that since we only request ONDISK ever we will // only ever get back one (type of) ack ever. - if (op->has_completion()) { + if (op->onfinish) { num_in_flight--; - onfinish = std::move(op->onfinish); - op->onfinish = nullptr; + onfinish = op->onfinish; + op->onfinish = NULL; } logger->inc(l_osdc_op_reply); @@ -3515,8 +3570,8 @@ void Objecter::handle_osd_op_reply(MOSDOpReply *m) sl.unlock(); // do callbacks - if (Op::has_completion(onfinish)) { - Op::complete(std::move(onfinish), osdcode(rc), rc); + if (onfinish) { + onfinish->complete(rc); } if (completion_lock.mutex()) { completion_lock.unlock(); @@ -3545,7 +3600,7 @@ void Objecter::handle_osd_backoff(MOSDBackoff *m) get_session(s); - unique_lock sl(s->lock); + OSDSession::unique_lock sl(s->lock); switch (m->op) { case CEPH_OSD_BACKOFF_OP_BLOCK: @@ -3560,9 +3615,10 @@ void Objecter::handle_osd_backoff(MOSDBackoff *m) // ack with original backoff's epoch so that the osd can discard this if // there was a pg split. - auto r = new MOSDBackoff(m->pgid, m->map_epoch, - CEPH_OSD_BACKOFF_OP_ACK_BLOCK, - m->id, m->begin, m->end); + Message *r = new MOSDBackoff(m->pgid, + m->map_epoch, + CEPH_OSD_BACKOFF_OP_ACK_BLOCK, + m->id, m->begin, m->end); // this priority must match the MOSDOps from _prepare_osd_op r->set_priority(cct->_conf->osd_client_op_priority); con->send_message(r); @@ -3725,7 +3781,7 @@ void Objecter::list_nobjects(NListContext *list_context, Context *onfinish) op.pg_nls(list_context->max_entries, list_context->filter, list_context->pos, osdmap->get_epoch()); list_context->bl.clear(); - auto onack = new C_NList(list_context, onfinish, this); + C_NList *onack = new C_NList(list_context, onfinish, this); object_locator_t oloc(list_context->pool_id, list_context->nspace); // note current_pg in case we don't have (or lose) SORTBITWISE @@ -3747,7 +3803,7 @@ void Objecter::_nlist_reply(NListContext *list_context, int r, decode(response, iter); if (!iter.end()) { // we do this as legacy. - cb::list legacy_extra_info; + ceph::buffer::list legacy_extra_info; decode(legacy_extra_info, iter); } @@ -3776,9 +3832,7 @@ void Objecter::_nlist_reply(NListContext *list_context, int r, << ", handle " << response.handle << ", tentative new pos " << list_context->pos << dendl; if (response_size) { - std::move(response.entries.begin(), response.entries.end(), - std::back_inserter(list_context->list)); - response.entries.clear(); + list_context->list.splice(list_context->list.end(), response.entries); } if (list_context->list.size() >= list_context->max_entries) { @@ -3807,177 +3861,176 @@ void Objecter::put_nlist_context_budget(NListContext *list_context) // snapshots -void Objecter::create_pool_snap(int64_t pool, std::string_view snap_name, - decltype(PoolOp::onfinish)&& onfinish) +int Objecter::create_pool_snap(int64_t pool, string& snap_name, + Context *onfinish) { unique_lock wl(rwlock); ldout(cct, 10) << "create_pool_snap; pool: " << pool << "; snap: " << snap_name << dendl; const pg_pool_t *p = osdmap->get_pg_pool(pool); - if (!p) { - onfinish->defer(std::move(onfinish), osdc_errc::pool_dne, cb::list{}); - return; - } - if (p->snap_exists(snap_name)) { - onfinish->defer(std::move(onfinish), osdc_errc::snapshot_exists, - cb::list{}); - return; - } + if (!p) + return -EINVAL; + if (p->snap_exists(snap_name.c_str())) + return -EEXIST; - auto op = new PoolOp; + PoolOp *op = new PoolOp; + if (!op) + return -ENOMEM; op->tid = ++last_tid; op->pool = pool; op->name = snap_name; - op->onfinish = std::move(onfinish); + op->onfinish = onfinish; op->pool_op = POOL_OP_CREATE_SNAP; pool_ops[op->tid] = op; pool_op_submit(op); + + return 0; } -struct CB_SelfmanagedSnap { - std::unique_ptr<ca::Completion<void(bs::error_code, snapid_t)>> fin; - CB_SelfmanagedSnap(decltype(fin)&& fin) - : fin(std::move(fin)) {} - void operator()(bs::error_code ec, const cb::list& bl) { - snapid_t snapid = 0; - if (!ec) { +struct C_SelfmanagedSnap : public Context { + ceph::buffer::list bl; + snapid_t *psnapid; + Context *fin; + C_SelfmanagedSnap(snapid_t *ps, Context *f) : psnapid(ps), fin(f) {} + void finish(int r) override { + if (r == 0) { try { - auto p = bl.cbegin(); - decode(snapid, p); - } catch (const cb::error& e) { - ec = e.code(); + auto p = bl.cbegin(); + decode(*psnapid, p); + } catch (ceph::buffer::error&) { + r = -EIO; } } - fin->defer(std::move(fin), ec, snapid); + fin->complete(r); } }; -void Objecter::allocate_selfmanaged_snap( - int64_t pool, - std::unique_ptr<ca::Completion<void(bs::error_code, snapid_t)>> onfinish) +int Objecter::allocate_selfmanaged_snap(int64_t pool, snapid_t *psnapid, + Context *onfinish) { unique_lock wl(rwlock); ldout(cct, 10) << "allocate_selfmanaged_snap; pool: " << pool << dendl; - auto op = new PoolOp; + PoolOp *op = new PoolOp; + if (!op) return -ENOMEM; op->tid = ++last_tid; op->pool = pool; - op->onfinish = PoolOp::OpComp::create( - service.get_executor(), - CB_SelfmanagedSnap(std::move(onfinish))); + C_SelfmanagedSnap *fin = new C_SelfmanagedSnap(psnapid, onfinish); + op->onfinish = fin; + op->blp = &fin->bl; op->pool_op = POOL_OP_CREATE_UNMANAGED_SNAP; pool_ops[op->tid] = op; pool_op_submit(op); + return 0; } -void Objecter::delete_pool_snap( - int64_t pool, std::string_view snap_name, - decltype(PoolOp::onfinish)&& onfinish) +int Objecter::delete_pool_snap(int64_t pool, string& snap_name, + Context *onfinish) { unique_lock wl(rwlock); ldout(cct, 10) << "delete_pool_snap; pool: " << pool << "; snap: " << snap_name << dendl; const pg_pool_t *p = osdmap->get_pg_pool(pool); - if (!p) { - onfinish->defer(std::move(onfinish), osdc_errc::pool_dne, cb::list{}); - return; - } - - if (!p->snap_exists(snap_name)) { - onfinish->defer(std::move(onfinish), osdc_errc::snapshot_dne, cb::list{}); - return; - } + if (!p) + return -EINVAL; + if (!p->snap_exists(snap_name.c_str())) + return -ENOENT; - auto op = new PoolOp; + PoolOp *op = new PoolOp; + if (!op) + return -ENOMEM; op->tid = ++last_tid; op->pool = pool; op->name = snap_name; - op->onfinish = std::move(onfinish); + op->onfinish = onfinish; op->pool_op = POOL_OP_DELETE_SNAP; pool_ops[op->tid] = op; pool_op_submit(op); + + return 0; } -void Objecter::delete_selfmanaged_snap(int64_t pool, snapid_t snap, - decltype(PoolOp::onfinish)&& onfinish) +int Objecter::delete_selfmanaged_snap(int64_t pool, snapid_t snap, + Context *onfinish) { unique_lock wl(rwlock); ldout(cct, 10) << "delete_selfmanaged_snap; pool: " << pool << "; snap: " << snap << dendl; - auto op = new PoolOp; + PoolOp *op = new PoolOp; + if (!op) return -ENOMEM; op->tid = ++last_tid; op->pool = pool; - op->onfinish = std::move(onfinish); + op->onfinish = onfinish; op->pool_op = POOL_OP_DELETE_UNMANAGED_SNAP; op->snapid = snap; pool_ops[op->tid] = op; pool_op_submit(op); + + return 0; } -void Objecter::create_pool(std::string_view name, - decltype(PoolOp::onfinish)&& onfinish, - int crush_rule) +int Objecter::create_pool(string& name, Context *onfinish, + int crush_rule) { unique_lock wl(rwlock); ldout(cct, 10) << "create_pool name=" << name << dendl; - if (osdmap->lookup_pg_pool_name(name) >= 0) { - onfinish->defer(std::move(onfinish), osdc_errc::pool_exists, cb::list{}); - return; - } + if (osdmap->lookup_pg_pool_name(name) >= 0) + return -EEXIST; - auto op = new PoolOp; + PoolOp *op = new PoolOp; + if (!op) + return -ENOMEM; op->tid = ++last_tid; op->pool = 0; op->name = name; - op->onfinish = std::move(onfinish); + op->onfinish = onfinish; op->pool_op = POOL_OP_CREATE; pool_ops[op->tid] = op; op->crush_rule = crush_rule; pool_op_submit(op); + + return 0; } -void Objecter::delete_pool(int64_t pool, - decltype(PoolOp::onfinish)&& onfinish) +int Objecter::delete_pool(int64_t pool, Context *onfinish) { unique_lock wl(rwlock); ldout(cct, 10) << "delete_pool " << pool << dendl; if (!osdmap->have_pg_pool(pool)) - onfinish->defer(std::move(onfinish), osdc_errc::pool_dne, cb::list{}); - else - _do_delete_pool(pool, std::move(onfinish)); + return -ENOENT; + + _do_delete_pool(pool, onfinish); + return 0; } -void Objecter::delete_pool(std::string_view pool_name, - decltype(PoolOp::onfinish)&& onfinish) +int Objecter::delete_pool(const string &pool_name, Context *onfinish) { unique_lock wl(rwlock); ldout(cct, 10) << "delete_pool " << pool_name << dendl; int64_t pool = osdmap->lookup_pg_pool_name(pool_name); if (pool < 0) - // This only returns one error: -ENOENT. - onfinish->defer(std::move(onfinish), osdc_errc::pool_dne, cb::list{}); - else - _do_delete_pool(pool, std::move(onfinish)); -} + return pool; -void Objecter::_do_delete_pool(int64_t pool, - decltype(PoolOp::onfinish)&& onfinish) + _do_delete_pool(pool, onfinish); + return 0; +} +void Objecter::_do_delete_pool(int64_t pool, Context *onfinish) { - auto op = new PoolOp; + PoolOp *op = new PoolOp; op->tid = ++last_tid; op->pool = pool; op->name = "delete"; - op->onfinish = std::move(onfinish); + op->onfinish = onfinish; op->pool_op = POOL_OP_DELETE; pool_ops[op->tid] = op; pool_op_submit(op); @@ -3999,9 +4052,9 @@ void Objecter::_pool_op_submit(PoolOp *op) // rwlock is locked unique ldout(cct, 10) << "pool_op_submit " << op->tid << dendl; - auto m = new MPoolOp(monc->get_fsid(), op->tid, op->pool, - op->name, op->pool_op, - last_seen_osdmap_version); + MPoolOp *m = new MPoolOp(monc->get_fsid(), op->tid, op->pool, + op->name, op->pool_op, + last_seen_osdmap_version); if (op->snapid) m->snapid = op->snapid; if (op->crush_rule) m->crush_rule = op->crush_rule; monc->send_mon_message(m); @@ -4012,15 +4065,13 @@ void Objecter::_pool_op_submit(PoolOp *op) /** * Handle a reply to a PoolOp message. Check that we sent the message - * and give the caller responsibility for the returned cb::list. + * and give the caller responsibility for the returned ceph::buffer::list. * Then either call the finisher or stash the PoolOp, depending on if we * have a new enough map. * Lastly, clean up the message and PoolOp. */ void Objecter::handle_pool_op_reply(MPoolOpReply *m) { - int rc = m->replyCode; - auto ec = rc < 0 ? bs::error_code(-rc, mon_category()) : bs::error_code(); FUNCTRACE(cct); shunique_lock sul(rwlock, acquire_shared); if (!initialized) { @@ -4031,13 +4082,13 @@ void Objecter::handle_pool_op_reply(MPoolOpReply *m) ldout(cct, 10) << "handle_pool_op_reply " << *m << dendl; ceph_tid_t tid = m->get_tid(); - auto iter = pool_ops.find(tid); + map<ceph_tid_t, PoolOp *>::iterator iter = pool_ops.find(tid); if (iter != pool_ops.end()) { PoolOp *op = iter->second; ldout(cct, 10) << "have request " << tid << " at " << op << " Op: " << ceph_pool_op_name(op->pool_op) << dendl; - cb::list bl; - bl.claim(m->response_data); + if (op->blp) + op->blp->claim(m->response_data); if (m->version > last_seen_osdmap_version) last_seen_osdmap_version = m->version; if (osdmap->get_epoch() < m->epoch) { @@ -4051,27 +4102,19 @@ void Objecter::handle_pool_op_reply(MPoolOpReply *m) if (osdmap->get_epoch() < m->epoch) { ldout(cct, 20) << "waiting for client to reach epoch " << m->epoch << " before calling back" << dendl; - _wait_for_new_map(OpCompletion::create( - service.get_executor(), - [o = std::move(op->onfinish), - bl = std::move(bl)]( - bs::error_code ec) mutable { - o->defer(std::move(o), ec, bl); - }), - m->epoch, - ec); + _wait_for_new_map(op->onfinish, m->epoch, m->replyCode); } else { // map epoch changed, probably because a MOSDMap message // sneaked in. Do caller-specified callback now or else // we lose it forever. ceph_assert(op->onfinish); - op->onfinish->defer(std::move(op->onfinish), ec, std::move(bl)); + op->onfinish->complete(m->replyCode); } } else { ceph_assert(op->onfinish); - op->onfinish->defer(std::move(op->onfinish), ec, std::move(bl)); + op->onfinish->complete(m->replyCode); } - op->onfinish = nullptr; + op->onfinish = NULL; if (!sul.owns_lock()) { sul.unlock(); sul.lock(); @@ -4098,7 +4141,7 @@ int Objecter::pool_op_cancel(ceph_tid_t tid, int r) unique_lock wl(rwlock); - auto it = pool_ops.find(tid); + map<ceph_tid_t, PoolOp*>::iterator it = pool_ops.find(tid); if (it == pool_ops.end()) { ldout(cct, 10) << __func__ << " tid " << tid << " dne" << dendl; return -ENOENT; @@ -4108,7 +4151,7 @@ int Objecter::pool_op_cancel(ceph_tid_t tid, int r) PoolOp *op = it->second; if (op->onfinish) - op->onfinish->defer(std::move(op->onfinish), osdcode(r), cb::list{}); + op->onfinish->complete(r); _finish_pool_op(op, r); return 0; @@ -4129,16 +4172,19 @@ void Objecter::_finish_pool_op(PoolOp *op, int r) // pool stats -void Objecter::get_pool_stats( - const std::vector<std::string>& pools, - decltype(PoolStatOp::onfinish)&& onfinish) +void Objecter::get_pool_stats(list<string>& pools, + map<string,pool_stat_t> *result, + bool *per_pool, + Context *onfinish) { ldout(cct, 10) << "get_pool_stats " << pools << dendl; - auto op = new PoolStatOp; + PoolStatOp *op = new PoolStatOp; op->tid = ++last_tid; op->pools = pools; - op->onfinish = std::move(onfinish); + op->pool_stats = result; + op->per_pool = per_pool; + op->onfinish = onfinish; if (mon_timeout > timespan(0)) { op->ontimeout = timer.add_event(mon_timeout, [this, op]() { @@ -4179,15 +4225,16 @@ void Objecter::handle_get_pool_stats_reply(MGetPoolStatsReply *m) return; } - auto iter = poolstat_ops.find(tid); + map<ceph_tid_t, PoolStatOp *>::iterator iter = poolstat_ops.find(tid); if (iter != poolstat_ops.end()) { PoolStatOp *op = poolstat_ops[tid]; ldout(cct, 10) << "have request " << tid << " at " << op << dendl; + *op->pool_stats = m->pool_stats; + *op->per_pool = m->per_pool; if (m->version > last_seen_pgmap_version) { last_seen_pgmap_version = m->version; } - op->onfinish->defer(std::move(op->onfinish), bs::error_code{}, - std::move(m->pool_stats), m->per_pool); + op->onfinish->complete(0); _finish_pool_stat_op(op, 0); } else { ldout(cct, 10) << "unknown request " << tid << dendl; @@ -4202,7 +4249,7 @@ int Objecter::pool_stat_op_cancel(ceph_tid_t tid, int r) unique_lock wl(rwlock); - auto it = poolstat_ops.find(tid); + map<ceph_tid_t, PoolStatOp*>::iterator it = poolstat_ops.find(tid); if (it == poolstat_ops.end()) { ldout(cct, 10) << __func__ << " tid " << tid << " dne" << dendl; return -ENOENT; @@ -4210,10 +4257,9 @@ int Objecter::pool_stat_op_cancel(ceph_tid_t tid, int r) ldout(cct, 10) << __func__ << " tid " << tid << dendl; - auto op = it->second; + PoolStatOp *op = it->second; if (op->onfinish) - op->onfinish->defer(std::move(op->onfinish), osdcode(r), - bc::flat_map<std::string, pool_stat_t>{}, false); + op->onfinish->complete(r); _finish_pool_stat_op(op, r); return 0; } @@ -4231,16 +4277,18 @@ void Objecter::_finish_pool_stat_op(PoolStatOp *op, int r) delete op; } -void Objecter::get_fs_stats(boost::optional<int64_t> poolid, - decltype(StatfsOp::onfinish)&& onfinish) +void Objecter::get_fs_stats(ceph_statfs& result, + boost::optional<int64_t> data_pool, + Context *onfinish) { ldout(cct, 10) << "get_fs_stats" << dendl; unique_lock l(rwlock); - auto op = new StatfsOp; + StatfsOp *op = new StatfsOp; op->tid = ++last_tid; - op->data_pool = poolid; - op->onfinish = std::move(onfinish); + op->stats = &result; + op->data_pool = data_pool; + op->onfinish = onfinish; if (mon_timeout > timespan(0)) { op->ontimeout = timer.add_event(mon_timeout, [this, op]() { @@ -4283,9 +4331,10 @@ void Objecter::handle_fs_stats_reply(MStatfsReply *m) if (statfs_ops.count(tid)) { StatfsOp *op = statfs_ops[tid]; ldout(cct, 10) << "have request " << tid << " at " << op << dendl; + *(op->stats) = m->h.st; if (m->h.version > last_seen_pgmap_version) last_seen_pgmap_version = m->h.version; - op->onfinish->defer(std::move(op->onfinish), bs::error_code{}, m->h.st); + op->onfinish->complete(0); _finish_statfs_op(op, 0); } else { ldout(cct, 10) << "unknown request " << tid << dendl; @@ -4300,7 +4349,7 @@ int Objecter::statfs_op_cancel(ceph_tid_t tid, int r) unique_lock wl(rwlock); - auto it = statfs_ops.find(tid); + map<ceph_tid_t, StatfsOp*>::iterator it = statfs_ops.find(tid); if (it == statfs_ops.end()) { ldout(cct, 10) << __func__ << " tid " << tid << " dne" << dendl; return -ENOENT; @@ -4308,9 +4357,9 @@ int Objecter::statfs_op_cancel(ceph_tid_t tid, int r) ldout(cct, 10) << __func__ << " tid " << tid << dendl; - auto op = it->second; + StatfsOp *op = it->second; if (op->onfinish) - op->onfinish->defer(std::move(op->onfinish), osdcode(r), ceph_statfs{}); + op->onfinish->complete(r); _finish_statfs_op(op, r); return 0; } @@ -4331,16 +4380,16 @@ void Objecter::_finish_statfs_op(StatfsOp *op, int r) // scatter/gather void Objecter::_sg_read_finish(vector<ObjectExtent>& extents, - vector<cb::list>& resultbl, - cb::list *bl, Context *onfinish) + vector<ceph::buffer::list>& resultbl, + ceph::buffer::list *bl, Context *onfinish) { // all done ldout(cct, 15) << "_sg_read_finish" << dendl; if (extents.size() > 1) { Striper::StripedReadResult r; - auto bit = resultbl.begin(); - for (auto eit = extents.begin(); + vector<ceph::buffer::list>::iterator bit = resultbl.begin(); + for (vector<ObjectExtent>::iterator eit = extents.begin(); eit != extents.end(); ++eit, ++bit) { r.add_partial_result(cct, *bit, eit->buffer_extents); @@ -4392,7 +4441,7 @@ bool Objecter::ms_handle_reset(Connection *con) return false; } map<uint64_t, LingerOp *> lresend; - unique_lock sl(session->lock); + OSDSession::unique_lock sl(session->lock); _reopen_session(session); _kick_requests(session, lresend); sl.unlock(); @@ -4440,7 +4489,9 @@ void Objecter::op_target_t::dump(Formatter *f) const void Objecter::_dump_active(OSDSession *s) { - for (auto p = s->ops.begin(); p != s->ops.end(); ++p) { + for (map<ceph_tid_t,Op*>::iterator p = s->ops.begin(); + p != s->ops.end(); + ++p) { Op *op = p->second; ldout(cct, 20) << op->tid << "\t" << op->target.pgid << "\tosd." << (op->session ? op->session->osd : -1) @@ -4453,10 +4504,10 @@ void Objecter::_dump_active() { ldout(cct, 20) << "dump_active .. " << num_homeless_ops << " homeless" << dendl; - for (auto siter = osd_sessions.begin(); + for (map<int, OSDSession *>::iterator siter = osd_sessions.begin(); siter != osd_sessions.end(); ++siter) { - auto s = siter->second; - shared_lock sl(s->lock); + OSDSession *s = siter->second; + OSDSession::shared_lock sl(s->lock); _dump_active(s); sl.unlock(); } @@ -4485,7 +4536,9 @@ void Objecter::dump_requests(Formatter *fmt) void Objecter::_dump_ops(const OSDSession *s, Formatter *fmt) { - for (auto p = s->ops.begin(); p != s->ops.end(); ++p) { + for (map<ceph_tid_t,Op*>::const_iterator p = s->ops.begin(); + p != s->ops.end(); + ++p) { Op *op = p->second; auto age = std::chrono::duration<double>(coarse_mono_clock::now() - op->stamp); fmt->open_object_section("op"); @@ -4499,7 +4552,9 @@ void Objecter::_dump_ops(const OSDSession *s, Formatter *fmt) fmt->dump_stream("mtime") << op->mtime; fmt->open_array_section("osd_ops"); - for (auto it = op->ops.begin(); it != op->ops.end(); ++it) { + for (vector<OSDOp>::const_iterator it = op->ops.begin(); + it != op->ops.end(); + ++it) { fmt->dump_stream("osd_op") << *it; } fmt->close_section(); // osd_ops array @@ -4512,10 +4567,10 @@ void Objecter::dump_ops(Formatter *fmt) { // Read-lock on Objecter held fmt->open_array_section("ops"); - for (auto siter = osd_sessions.begin(); + for (map<int, OSDSession *>::const_iterator siter = osd_sessions.begin(); siter != osd_sessions.end(); ++siter) { OSDSession *s = siter->second; - shared_lock sl(s->lock); + OSDSession::shared_lock sl(s->lock); _dump_ops(s, fmt); sl.unlock(); } @@ -4525,8 +4580,10 @@ void Objecter::dump_ops(Formatter *fmt) void Objecter::_dump_linger_ops(const OSDSession *s, Formatter *fmt) { - for (auto p = s->linger_ops.begin(); p != s->linger_ops.end(); ++p) { - auto op = p->second; + for (map<uint64_t, LingerOp*>::const_iterator p = s->linger_ops.begin(); + p != s->linger_ops.end(); + ++p) { + LingerOp *op = p->second; fmt->open_object_section("linger_op"); fmt->dump_unsigned("linger_id", op->linger_id); op->target.dump(fmt); @@ -4540,10 +4597,10 @@ void Objecter::dump_linger_ops(Formatter *fmt) { // We have a read-lock on the objecter fmt->open_array_section("linger_ops"); - for (auto siter = osd_sessions.begin(); + for (map<int, OSDSession *>::const_iterator siter = osd_sessions.begin(); siter != osd_sessions.end(); ++siter) { - auto s = siter->second; - shared_lock sl(s->lock); + OSDSession *s = siter->second; + OSDSession::shared_lock sl(s->lock); _dump_linger_ops(s, fmt); sl.unlock(); } @@ -4553,13 +4610,16 @@ void Objecter::dump_linger_ops(Formatter *fmt) void Objecter::_dump_command_ops(const OSDSession *s, Formatter *fmt) { - for (auto p = s->command_ops.begin(); p != s->command_ops.end(); ++p) { - auto op = p->second; + for (map<uint64_t, CommandOp*>::const_iterator p = s->command_ops.begin(); + p != s->command_ops.end(); + ++p) { + CommandOp *op = p->second; fmt->open_object_section("command_op"); fmt->dump_unsigned("command_id", op->tid); fmt->dump_int("osd", op->session ? op->session->osd : -1); fmt->open_array_section("command"); - for (auto q = op->cmd.begin(); q != op->cmd.end(); ++q) + for (vector<string>::const_iterator q = op->cmd.begin(); + q != op->cmd.end(); ++q) fmt->dump_string("word", *q); fmt->close_section(); if (op->target_osd >= 0) @@ -4574,10 +4634,10 @@ void Objecter::dump_command_ops(Formatter *fmt) { // We have a read-lock on the Objecter here fmt->open_array_section("command_ops"); - for (auto siter = osd_sessions.begin(); + for (map<int, OSDSession *>::const_iterator siter = osd_sessions.begin(); siter != osd_sessions.end(); ++siter) { - auto s = siter->second; - shared_lock sl(s->lock); + OSDSession *s = siter->second; + OSDSession::shared_lock sl(s->lock); _dump_command_ops(s, fmt); sl.unlock(); } @@ -4588,8 +4648,10 @@ void Objecter::dump_command_ops(Formatter *fmt) void Objecter::dump_pool_ops(Formatter *fmt) const { fmt->open_array_section("pool_ops"); - for (auto p = pool_ops.begin(); p != pool_ops.end(); ++p) { - auto op = p->second; + for (map<ceph_tid_t, PoolOp*>::const_iterator p = pool_ops.begin(); + p != pool_ops.end(); + ++p) { + PoolOp *op = p->second; fmt->open_object_section("pool_op"); fmt->dump_unsigned("tid", op->tid); fmt->dump_int("pool", op->pool); @@ -4606,7 +4668,7 @@ void Objecter::dump_pool_ops(Formatter *fmt) const void Objecter::dump_pool_stat_ops(Formatter *fmt) const { fmt->open_array_section("pool_stat_ops"); - for (auto p = poolstat_ops.begin(); + for (map<ceph_tid_t, PoolStatOp*>::const_iterator p = poolstat_ops.begin(); p != poolstat_ops.end(); ++p) { PoolStatOp *op = p->second; @@ -4615,8 +4677,10 @@ void Objecter::dump_pool_stat_ops(Formatter *fmt) const fmt->dump_stream("last_sent") << op->last_submit; fmt->open_array_section("pools"); - for (const auto& it : op->pools) { - fmt->dump_string("pool", it); + for (list<string>::const_iterator it = op->pools.begin(); + it != op->pools.end(); + ++it) { + fmt->dump_string("pool", *it); } fmt->close_section(); // pools array @@ -4628,8 +4692,10 @@ void Objecter::dump_pool_stat_ops(Formatter *fmt) const void Objecter::dump_statfs_ops(Formatter *fmt) const { fmt->open_array_section("statfs_ops"); - for (auto p = statfs_ops.begin(); p != statfs_ops.end(); ++p) { - auto op = p->second; + for (map<ceph_tid_t, StatfsOp*>::const_iterator p = statfs_ops.begin(); + p != statfs_ops.end(); + ++p) { + StatfsOp *op = p->second; fmt->open_object_section("statfs_op"); fmt->dump_unsigned("tid", op->tid); fmt->dump_stream("last_sent") << op->last_submit; @@ -4647,7 +4713,7 @@ int Objecter::RequestStateHook::call(std::string_view command, const cmdmap_t& cmdmap, Formatter *f, std::ostream& ss, - cb::list& out) + ceph::buffer::list& out) { shared_lock rl(m_objecter->rwlock); m_objecter->dump_requests(f); @@ -4669,7 +4735,7 @@ void Objecter::blacklist_self(bool set) ss << messenger->get_myaddrs().front().get_legacy_str(); cmd.push_back("\"addr\":\"" + ss.str() + "\""); - auto m = new MMonCommand(monc->get_fsid()); + MMonCommand *m = new MMonCommand(monc->get_fsid()); m->cmd = cmd; monc->send_mon_message(m); @@ -4694,8 +4760,8 @@ void Objecter::handle_command_reply(MCommandReply *m) return; } - shared_lock sl(s->lock); - auto p = s->command_ops.find(m->get_tid()); + OSDSession::shared_lock sl(s->lock); + map<ceph_tid_t,CommandOp*>::iterator p = s->command_ops.find(m->get_tid()); if (p == s->command_ops.end()) { ldout(cct, 10) << "handle_command_reply tid " << m->get_tid() << " not found" << dendl; @@ -4715,7 +4781,6 @@ void Objecter::handle_command_reply(MCommandReply *m) sl.unlock(); return; } - if (m->r == -EAGAIN) { ldout(cct,10) << __func__ << " tid " << m->get_tid() << " got EAGAIN, requesting map and resending" << dendl; @@ -4728,12 +4793,14 @@ void Objecter::handle_command_reply(MCommandReply *m) return; } + if (c->poutbl) { + c->poutbl->claim(m->get_data()); + } + sl.unlock(); - unique_lock sul(s->lock); - _finish_command(c, m->r < 0 ? bs::error_code(-m->r, osd_category()) : - bs::error_code(), std::move(m->rs), - std::move(m->get_data())); + OSDSession::unique_lock sul(s->lock); + _finish_command(c, m->r, m->rs); sul.unlock(); m->put(); @@ -4748,7 +4815,7 @@ void Objecter::submit_command(CommandOp *c, ceph_tid_t *ptid) c->tid = tid; { - unique_lock hs_wl(homeless_session->lock); + OSDSession::unique_lock hs_wl(homeless_session->lock); _session_command_op_assign(homeless_session, c); } @@ -4757,9 +4824,8 @@ void Objecter::submit_command(CommandOp *c, ceph_tid_t *ptid) if (osd_timeout > timespan(0)) { c->ontimeout = timer.add_event(osd_timeout, [this, c, tid]() { - command_op_cancel( - c->session, tid, - osdc_errc::timed_out); }); + command_op_cancel(c->session, tid, + -ETIMEDOUT); }); } if (!c->session->is_homeless()) { @@ -4769,14 +4835,12 @@ void Objecter::submit_command(CommandOp *c, ceph_tid_t *ptid) } if (c->map_check_error) _send_command_map_check(c); - if (ptid) - *ptid = tid; + *ptid = tid; logger->inc(l_osdc_command_active); } -int Objecter::_calc_command_target(CommandOp *c, - shunique_lock<ceph::shared_mutex>& sul) +int Objecter::_calc_command_target(CommandOp *c, shunique_lock& sul) { ceph_assert(sul.owns_lock() && sul.mutex() == &rwlock); @@ -4832,7 +4896,7 @@ int Objecter::_calc_command_target(CommandOp *c, } void Objecter::_assign_command_session(CommandOp *c, - shunique_lock<ceph::shared_mutex>& sul) + shunique_lock& sul) { ceph_assert(sul.owns_lock() && sul.mutex() == &rwlock); @@ -4843,11 +4907,11 @@ void Objecter::_assign_command_session(CommandOp *c, if (c->session != s) { if (c->session) { OSDSession *cs = c->session; - unique_lock csl(cs->lock); + OSDSession::unique_lock csl(cs->lock); _session_command_op_remove(c->session, c); csl.unlock(); } - unique_lock sl(s->lock); + OSDSession::unique_lock sl(s->lock); _session_command_op_assign(s, c); } @@ -4859,7 +4923,7 @@ void Objecter::_send_command(CommandOp *c) ldout(cct, 10) << "_send_command " << c->tid << dendl; ceph_assert(c->session); ceph_assert(c->session->con); - auto m = new MCommand(monc->monmap.fsid); + MCommand *m = new MCommand(monc->monmap.fsid); m->cmd = c->cmd; m->set_data(c->inbl); m->set_tid(c->tid); @@ -4867,14 +4931,13 @@ void Objecter::_send_command(CommandOp *c) logger->inc(l_osdc_command_send); } -int Objecter::command_op_cancel(OSDSession *s, ceph_tid_t tid, - bs::error_code ec) +int Objecter::command_op_cancel(OSDSession *s, ceph_tid_t tid, int r) { ceph_assert(initialized); unique_lock wl(rwlock); - auto it = s->command_ops.find(tid); + map<ceph_tid_t, CommandOp*>::iterator it = s->command_ops.find(tid); if (it == s->command_ops.end()) { ldout(cct, 10) << __func__ << " tid " << tid << " dne" << dendl; return -ENOENT; @@ -4884,25 +4947,25 @@ int Objecter::command_op_cancel(OSDSession *s, ceph_tid_t tid, CommandOp *op = it->second; _command_cancel_map_check(op); - unique_lock sl(op->session->lock); - _finish_command(op, ec, {}, {}); + OSDSession::unique_lock sl(op->session->lock); + _finish_command(op, r, ""); sl.unlock(); return 0; } -void Objecter::_finish_command(CommandOp *c, bs::error_code ec, - string&& rs, cb::list&& bl) +void Objecter::_finish_command(CommandOp *c, int r, string rs) { // rwlock is locked unique // session lock is locked - ldout(cct, 10) << "_finish_command " << c->tid << " = " << ec << " " + ldout(cct, 10) << "_finish_command " << c->tid << " = " << r << " " << rs << dendl; - + if (c->prs) + *c->prs = rs; if (c->onfinish) - c->onfinish->defer(std::move(c->onfinish), ec, std::move(rs), std::move(bl)); + c->onfinish->complete(r); - if (c->ontimeout && ec != bs::errc::timed_out) + if (c->ontimeout && r != -ETIMEDOUT) timer.cancel_event(c->ontimeout); _session_command_op_remove(c->session, c); @@ -4921,14 +4984,20 @@ Objecter::OSDSession::~OSDSession() ceph_assert(command_ops.empty()); } -Objecter::Objecter(CephContext *cct, - Messenger *m, MonClient *mc, - boost::asio::io_context& service, +Objecter::Objecter(CephContext *cct_, Messenger *m, MonClient *mc, + Finisher *fin, double mon_timeout, double osd_timeout) : - Dispatcher(cct), messenger(m), monc(mc), service(service), + Dispatcher(cct_), messenger(m), monc(mc), finisher(fin), + trace_endpoint("0.0.0.0", 0, "Objecter"), + osdmap{std::make_unique<OSDMap>()}, + homeless_session(new OSDSession(cct, -1)), mon_timeout(ceph::make_timespan(mon_timeout)), - osd_timeout(ceph::make_timespan(osd_timeout)) + osd_timeout(ceph::make_timespan(osd_timeout)), + op_throttle_bytes(cct, "objecter_bytes", + cct->_conf->objecter_inflight_op_bytes), + op_throttle_ops(cct, "objecter_ops", cct->_conf->objecter_inflight_ops), + retry_writes_after_first_reply(cct->_conf->objecter_retry_writes_after_first_reply) {} Objecter::~Objecter() @@ -4983,79 +5052,60 @@ hobject_t Objecter::enumerate_objects_end() return hobject_t::get_max(); } -struct EnumerationContext { - Objecter* objecter; - const hobject_t end; - const cb::list filter; - uint32_t max; - const object_locator_t oloc; - std::vector<librados::ListObjectImpl> ls; -private: - fu2::unique_function<void(bs::error_code, - std::vector<librados::ListObjectImpl>, - hobject_t) &&> on_finish; -public: - epoch_t epoch = 0; - int budget = -1; - - EnumerationContext(Objecter* objecter, - hobject_t end, cb::list filter, - uint32_t max, object_locator_t oloc, - decltype(on_finish) on_finish) - : objecter(objecter), end(std::move(end)), filter(std::move(filter)), - max(max), oloc(std::move(oloc)), on_finish(std::move(on_finish)) {} - - void operator()(bs::error_code ec, - std::vector<librados::ListObjectImpl> v, - hobject_t h) && { - if (budget >= 0) { - objecter->put_op_budget_bytes(budget); - budget = -1; - } - - std::move(on_finish)(ec, std::move(v), std::move(h)); - } -}; +struct C_EnumerateReply : public Context { + ceph::buffer::list bl; -struct CB_EnumerateReply { - cb::list bl; + Objecter *objecter; + hobject_t *next; + std::list<librados::ListObjectImpl> *result; + const hobject_t end; + const int64_t pool_id; + Context *on_finish; - Objecter* objecter; - std::unique_ptr<EnumerationContext> ctx; + epoch_t epoch; + int budget; - CB_EnumerateReply(Objecter* objecter, - std::unique_ptr<EnumerationContext>&& ctx) : - objecter(objecter), ctx(std::move(ctx)) {} + C_EnumerateReply(Objecter *objecter_, hobject_t *next_, + std::list<librados::ListObjectImpl> *result_, + const hobject_t end_, const int64_t pool_id_, Context *on_finish_) : + objecter(objecter_), next(next_), result(result_), + end(end_), pool_id(pool_id_), on_finish(on_finish_), + epoch(0), budget(-1) + {} - void operator()(bs::error_code ec) { - objecter->_enumerate_reply(std::move(bl), ec, std::move(ctx)); + void finish(int r) override { + objecter->_enumerate_reply( + bl, r, end, pool_id, budget, epoch, result, next, on_finish); } }; void Objecter::enumerate_objects( - int64_t pool_id, - std::string_view ns, - hobject_t start, - hobject_t end, - const uint32_t max, - const cb::list& filter_bl, - fu2::unique_function<void(bs::error_code, - std::vector<librados::ListObjectImpl>, - hobject_t) &&> on_finish) { + int64_t pool_id, + const std::string &ns, + const hobject_t &start, + const hobject_t &end, + const uint32_t max, + const ceph::buffer::list &filter_bl, + std::list<librados::ListObjectImpl> *result, + hobject_t *next, + Context *on_finish) +{ + ceph_assert(result); + if (!end.is_max() && start > end) { lderr(cct) << __func__ << ": start " << start << " > end " << end << dendl; - std::move(on_finish)(osdc_errc::precondition_violated, {}, {}); + on_finish->complete(-EINVAL); return; } if (max < 1) { lderr(cct) << __func__ << ": result size may not be zero" << dendl; - std::move(on_finish)(osdc_errc::precondition_violated, {}, {}); + on_finish->complete(-EINVAL); return; } if (start.is_max()) { - std::move(on_finish)({}, {}, {}); + on_finish->complete(0); return; } @@ -5064,92 +5114,92 @@ void Objecter::enumerate_objects( if (!osdmap->test_flag(CEPH_OSDMAP_SORTBITWISE)) { rl.unlock(); lderr(cct) << __func__ << ": SORTBITWISE cluster flag not set" << dendl; - std::move(on_finish)(osdc_errc::not_supported, {}, {}); + on_finish->complete(-EOPNOTSUPP); return; } - const pg_pool_t* p = osdmap->get_pg_pool(pool_id); + const pg_pool_t *p = osdmap->get_pg_pool(pool_id); if (!p) { lderr(cct) << __func__ << ": pool " << pool_id << " DNE in osd epoch " << osdmap->get_epoch() << dendl; rl.unlock(); - std::move(on_finish)(osdc_errc::pool_dne, {}, {}); + on_finish->complete(-ENOENT); return; } else { rl.unlock(); } - _issue_enumerate(start, - std::make_unique<EnumerationContext>( - this, std::move(end), filter_bl, - max, object_locator_t{pool_id, ns}, - std::move(on_finish))); -} + ldout(cct, 20) << __func__ << ": start=" << start << " end=" << end << dendl; + + // Stash completion state + C_EnumerateReply *on_ack = new C_EnumerateReply( + this, next, result, end, pool_id, on_finish); -void Objecter::_issue_enumerate(hobject_t start, - std::unique_ptr<EnumerationContext> ctx) { ObjectOperation op; - auto c = ctx.get(); - op.pg_nls(c->max, c->filter, start, osdmap->get_epoch()); - auto on_ack = std::make_unique<CB_EnumerateReply>(this, std::move(ctx)); - // I hate having to do this. Try to find a cleaner way - // later. - auto epoch = &c->epoch; - auto budget = &c->budget; - auto pbl = &on_ack->bl; + op.pg_nls(max, filter_bl, start, 0); // Issue. See you later in _enumerate_reply - pg_read(start.get_hash(), - c->oloc, op, pbl, 0, - Op::OpComp::create(service.get_executor(), - [c = std::move(on_ack)] - (bs::error_code ec) mutable { - (*c)(ec); - }), epoch, budget); + object_locator_t oloc(pool_id, ns); + pg_read(start.get_hash(), oloc, op, + &on_ack->bl, 0, on_ack, &on_ack->epoch, &on_ack->budget); } void Objecter::_enumerate_reply( - cb::list&& bl, - bs::error_code ec, - std::unique_ptr<EnumerationContext>&& ctx) -{ - if (ec) { - std::move(*ctx)(ec, {}, {}); + ceph::buffer::list &bl, + int r, + const hobject_t &end, + const int64_t pool_id, + int budget, + epoch_t reply_epoch, + std::list<librados::ListObjectImpl> *result, + hobject_t *next, + Context *on_finish) +{ + if (budget >= 0) { + put_op_budget_bytes(budget); + } + + if (r < 0) { + ldout(cct, 4) << __func__ << ": remote error " << r << dendl; + on_finish->complete(r); return; } + ceph_assert(next != NULL); + // Decode the results auto iter = bl.cbegin(); pg_nls_response_t response; - try { - decode(response, iter); - if (!iter.end()) { - // extra_info isn't used anywhere. We do this solely to preserve - // backward compatibility - cb::list legacy_extra_info; - decode(legacy_extra_info, iter); - } - } catch (const bs::system_error& e) { - std::move(*ctx)(e.code(), {}, {}); - return; - } - - shared_lock rl(rwlock); - auto pool = osdmap->get_pg_pool(ctx->oloc.get_pool()); - rl.unlock(); - if (!pool) { - // pool is gone, drop any results which are now meaningless. - std::move(*ctx)(osdc_errc::pool_dne, {}, {}); - return; + decode(response, iter); + if (!iter.end()) { + // extra_info isn't used anywhere. We do this solely to preserve + // backward compatibility + ceph::buffer::list legacy_extra_info; + decode(legacy_extra_info, iter); } - hobject_t next; - if ((response.handle <= ctx->end)) { - next = response.handle; + ldout(cct, 10) << __func__ << ": got " << response.entries.size() + << " handle " << response.handle + << " reply_epoch " << reply_epoch << dendl; + ldout(cct, 20) << __func__ << ": response.entries.size " + << response.entries.size() << ", response.entries " + << response.entries << dendl; + if (response.handle <= end) { + *next = response.handle; } else { - next = ctx->end; + ldout(cct, 10) << __func__ << ": adjusted next down to end " << end + << dendl; + *next = end; // drop anything after 'end' + shared_lock rl(rwlock); + const pg_pool_t *pool = osdmap->get_pg_pool(pool_id); + if (!pool) { + // pool is gone, drop any results which are now meaningless. + rl.unlock(); + on_finish->complete(-ENOENT); + return; + } while (!response.entries.empty()) { uint32_t hash = response.entries.back().locator.empty() ? pool->hash_key(response.entries.back().oid, @@ -5160,49 +5210,34 @@ void Objecter::_enumerate_reply( response.entries.back().locator, CEPH_NOSNAP, hash, - ctx->oloc.get_pool(), + pool_id, response.entries.back().nspace); - if (last < ctx->end) + if (last < end) break; + ldout(cct, 20) << __func__ << " dropping item " << last + << " >= end " << end << dendl; response.entries.pop_back(); } + rl.unlock(); } - - if (response.entries.size() <= ctx->max) { - ctx->max -= response.entries.size(); - std::move(response.entries.begin(), response.entries.end(), - std::back_inserter(ctx->ls)); - } else { - auto i = response.entries.begin(); - while (ctx->max > 0) { - ctx->ls.push_back(std::move(*i)); - --(ctx->max); - ++i; - } - uint32_t hash = - i->locator.empty() ? - pool->hash_key(i->oid, i->nspace) : - pool->hash_key(i->locator, i->nspace); - - next = hobject_t{i->oid, i->locator, - CEPH_NOSNAP, - hash, - ctx->oloc.get_pool(), - i->nspace}; + if (!response.entries.empty()) { + result->merge(response.entries); } - if (next == ctx->end || ctx->max == 0) { - std::move(*ctx)(ec, std::move(ctx->ls), std::move(next)); - } else { - _issue_enumerate(next, std::move(ctx)); - } + // release the listing context's budget once all + // OPs (in the session) are finished +#if 0 + put_nlist_context_budget(list_context); +#endif + on_finish->complete(r); + return; } namespace { using namespace librados; template <typename T> - void do_decode(std::vector<T>& items, std::vector<cb::list>& bls) + void do_decode(std::vector<T>& items, std::vector<ceph::buffer::list>& bls) { for (auto bl : bls) { auto p = bl.cbegin(); @@ -5213,19 +5248,19 @@ namespace { } struct C_ObjectOperation_scrub_ls : public Context { - cb::list bl; - uint32_t* interval; + ceph::buffer::list bl; + uint32_t *interval; std::vector<inconsistent_obj_t> *objects = nullptr; std::vector<inconsistent_snapset_t> *snapsets = nullptr; - int* rval; + int *rval; - C_ObjectOperation_scrub_ls(uint32_t* interval, - std::vector<inconsistent_obj_t>* objects, - int* rval) + C_ObjectOperation_scrub_ls(uint32_t *interval, + std::vector<inconsistent_obj_t> *objects, + int *rval) : interval(interval), objects(objects), rval(rval) {} - C_ObjectOperation_scrub_ls(uint32_t* interval, - std::vector<inconsistent_snapset_t>* snapsets, - int* rval) + C_ObjectOperation_scrub_ls(uint32_t *interval, + std::vector<inconsistent_snapset_t> *snapsets, + int *rval) : interval(interval), snapsets(snapsets), rval(rval) {} void finish(int r) override { if (r < 0 && r != -EAGAIN) { @@ -5239,7 +5274,7 @@ namespace { try { decode(); - } catch (cb::error&) { + } catch (ceph::buffer::error&) { if (rval) *rval = -EIO; } @@ -5259,19 +5294,19 @@ namespace { }; template <typename T> - void do_scrub_ls(::ObjectOperation* op, + void do_scrub_ls(::ObjectOperation *op, const scrub_ls_arg_t& arg, std::vector<T> *items, - uint32_t* interval, - int* rval) + uint32_t *interval, + int *rval) { OSDOp& osd_op = op->add_op(CEPH_OSD_OP_SCRUBLS); op->flags |= CEPH_OSD_FLAG_PGOP; ceph_assert(interval); arg.encode(osd_op.indata); unsigned p = op->ops.size() - 1; - auto h = new C_ObjectOperation_scrub_ls{interval, items, rval}; - op->set_handler(h); + auto *h = new C_ObjectOperation_scrub_ls{interval, items, rval}; + op->out_handler[p] = h; op->out_bl[p] = &h->bl; op->out_rval[p] = rval; } @@ -5279,9 +5314,9 @@ namespace { void ::ObjectOperation::scrub_ls(const librados::object_id_t& start_after, uint64_t max_to_get, - std::vector<librados::inconsistent_obj_t>* objects, - uint32_t* interval, - int* rval) + std::vector<librados::inconsistent_obj_t> *objects, + uint32_t *interval, + int *rval) { scrub_ls_arg_t arg = {*interval, 0, start_after, max_to_get}; do_scrub_ls(this, arg, objects, interval, rval); diff --git a/src/osdc/Objecter.h b/src/osdc/Objecter.h index a684fbcc83e..f669ce31c5f 100644 --- a/src/osdc/Objecter.h +++ b/src/osdc/Objecter.h @@ -21,33 +21,24 @@ #include <mutex> #include <memory> #include <sstream> -#include <string> -#include <string_view> #include <type_traits> -#include <boost/container/small_vector.hpp> -#include <boost/asio.hpp> +#include <boost/thread/shared_mutex.hpp> -#include "include/buffer.h" #include "include/ceph_assert.h" -#include "include/ceph_fs.h" -#include "include/expected.hpp" +#include "include/buffer.h" #include "include/types.h" #include "include/rados/rados_types.hpp" -#include "include/function2.hpp" #include "common/admin_socket.h" -#include "common/async/completion.h" #include "common/ceph_time.h" -#include "common/ceph_mutex.h" #include "common/ceph_timer.h" #include "common/config_obs.h" #include "common/shunique_lock.h" #include "common/zipkin_trace.h" +#include "common/Finisher.h" #include "common/Throttle.h" -#include "mon/MonClient.h" - #include "messages/MOSDOp.h" #include "msg/Dispatcher.h" @@ -57,6 +48,7 @@ class Context; class Messenger; class MonClient; class Message; +class Finisher; class MPoolOpReply; @@ -66,47 +58,28 @@ class MCommandReply; class MWatchNotify; class PerfCounters; -struct EnumerationContext; - -inline constexpr std::size_t osdc_opvec_len = 4; -using osdc_opvec = boost::container::small_vector<OSDOp, osdc_opvec_len>; - // ----------------------------------------- struct ObjectOperation { - osdc_opvec ops; - int flags = 0; - int priority = 0; - - boost::container::small_vector<ceph::buffer::list*, osdc_opvec_len> out_bl; - boost::container::small_vector< - fu2::unique_function<void(boost::system::error_code, int, - const ceph::buffer::list& bl) &&>, - osdc_opvec_len> out_handler; - boost::container::small_vector<int*, osdc_opvec_len> out_rval; - boost::container::small_vector<boost::system::error_code*, - osdc_opvec_len> out_ec; - - ObjectOperation() = default; - ObjectOperation(const ObjectOperation&) = delete; - ObjectOperation& operator =(const ObjectOperation&) = delete; - ObjectOperation(ObjectOperation&&) = default; - ObjectOperation& operator =(ObjectOperation&&) = default; - ~ObjectOperation() = default; - - size_t size() const { - return ops.size(); + std::vector<OSDOp> ops; + int flags; + int priority; + + std::vector<ceph::buffer::list*> out_bl; + std::vector<Context*> out_handler; + std::vector<int*> out_rval; + + ObjectOperation() : flags(0), priority(0) {} + ~ObjectOperation() { + while (!out_handler.empty()) { + delete out_handler.back(); + out_handler.pop_back(); + } } - void clear() { - ops.clear(); - flags = 0; - priority = 0; - out_bl.clear(); - out_handler.clear(); - out_rval.clear(); - out_ec.clear(); + size_t size() { + return ops.size(); } void set_last_op_flags(int flags) { @@ -114,51 +87,24 @@ struct ObjectOperation { ops.rbegin()->op.flags = flags; } - - void set_handler(fu2::unique_function<void(boost::system::error_code, int, - const ceph::buffer::list&) &&> f) { - if (f) { - if (out_handler.back()) { - // This happens seldom enough that we may as well keep folding - // functions together when we get another one rather than - // using a container. - out_handler.back() = - [f = std::move(f), - g = std::move(std::move(out_handler.back()))] - (boost::system::error_code ec, int r, - const ceph::buffer::list& bl) mutable { - std::move(g)(ec, r, bl); - std::move(f)(ec, r, bl); - }; - } else { - out_handler.back() = std::move(f); - } - } - ceph_assert(ops.size() == out_handler.size()); - } - - void set_handler(Context *c) { - if (c) - set_handler([c = std::unique_ptr<Context>(c)](boost::system::error_code, - int r, - const ceph::buffer::list&) mutable { - c.release()->complete(r); - }); - - } + class C_TwoContexts; + /** + * Add a callback to run when this operation completes, + * after any other callbacks for it. + */ + void add_handler(Context *extra); OSDOp& add_op(int op) { - ops.emplace_back(); - ops.back().op.op = op; - out_bl.push_back(nullptr); - ceph_assert(ops.size() == out_bl.size()); - out_handler.emplace_back(); - ceph_assert(ops.size() == out_handler.size()); - out_rval.push_back(nullptr); - ceph_assert(ops.size() == out_rval.size()); - out_ec.push_back(nullptr); - ceph_assert(ops.size() == out_ec.size()); - return ops.back(); + int s = ops.size(); + ops.resize(s+1); + ops[s].op.op = op; + out_bl.resize(s+1); + out_bl[s] = NULL; + out_handler.resize(s+1); + out_handler[s] = NULL; + out_rval.resize(s+1); + out_rval[s] = NULL; + return ops[s]; } void add_data(int op, uint64_t off, uint64_t len, ceph::buffer::list& bl) { OSDOp& osd_op = add_op(op); @@ -193,58 +139,21 @@ struct ObjectOperation { osd_op.indata.append(name, osd_op.op.xattr.name_len); osd_op.indata.append(data); } - void add_xattr(int op, std::string_view name, const ceph::buffer::list& data) { - OSDOp& osd_op = add_op(op); - osd_op.op.xattr.name_len = name.size(); - osd_op.op.xattr.value_len = data.length(); - osd_op.indata.append(name.data(), osd_op.op.xattr.name_len); - osd_op.indata.append(data); - } - void add_xattr_cmp(int op, std::string_view name, uint8_t cmp_op, - uint8_t cmp_mode, const ceph::buffer::list& data) { - OSDOp& osd_op = add_op(op); - osd_op.op.xattr.name_len = name.size(); - osd_op.op.xattr.value_len = data.length(); - osd_op.op.xattr.cmp_op = cmp_op; - osd_op.op.xattr.cmp_mode = cmp_mode; - if (!name.empty()) - osd_op.indata.append(name.data(), osd_op.op.xattr.name_len); - osd_op.indata.append(data); - } - void add_call(int op, std::string_view cname, std::string_view method, - const ceph::buffer::list &indata, + void add_call(int op, const char *cname, const char *method, + ceph::buffer::list &indata, ceph::buffer::list *outbl, Context *ctx, int *prval) { OSDOp& osd_op = add_op(op); unsigned p = ops.size() - 1; - set_handler(ctx); + out_handler[p] = ctx; out_bl[p] = outbl; out_rval[p] = prval; - osd_op.op.cls.class_len = cname.size(); - osd_op.op.cls.method_len = method.size(); - osd_op.op.cls.indata_len = indata.length(); - osd_op.indata.append(cname.data(), osd_op.op.cls.class_len); - osd_op.indata.append(method.data(), osd_op.op.cls.method_len); - osd_op.indata.append(indata); - } - void add_call(int op, std::string_view cname, std::string_view method, - const ceph::buffer::list &indata, - fu2::unique_function<void(boost::system::error_code, - const ceph::buffer::list&) &&> f) { - OSDOp& osd_op = add_op(op); - - set_handler([f = std::move(f)](boost::system::error_code ec, - int, - const ceph::buffer::list& bl) mutable { - std::move(f)(ec, bl); - }); - - osd_op.op.cls.class_len = cname.size(); - osd_op.op.cls.method_len = method.size(); + osd_op.op.cls.class_len = strlen(cname); + osd_op.op.cls.method_len = strlen(method); osd_op.op.cls.indata_len = indata.length(); - osd_op.indata.append(cname.data(), osd_op.op.cls.class_len); - osd_op.indata.append(method.data(), osd_op.op.cls.method_len); + osd_op.indata.append(cname, osd_op.op.cls.class_len); + osd_op.indata.append(method, osd_op.op.cls.method_len); osd_op.indata.append(indata); } void add_pgls(int op, uint64_t count, collection_list_handle_t cookie, @@ -316,18 +225,17 @@ struct ObjectOperation { o.op.flags = (excl ? CEPH_OSD_OP_FLAG_EXCL : 0); } - struct CB_ObjectOperation_stat { + struct C_ObjectOperation_stat : public Context { ceph::buffer::list bl; uint64_t *psize; ceph::real_time *pmtime; time_t *ptime; struct timespec *pts; int *prval; - boost::system::error_code* pec; - CB_ObjectOperation_stat(uint64_t *ps, ceph::real_time *pm, time_t *pt, struct timespec *_pts, - int *prval, boost::system::error_code* pec) - : psize(ps), pmtime(pm), ptime(pt), pts(_pts), prval(prval), pec(pec) {} - void operator()(boost::system::error_code ec, int r, const ceph::buffer::list& bl) { + C_ObjectOperation_stat(uint64_t *ps, ceph::real_time *pm, time_t *pt, struct timespec *_pts, + int *prval) + : psize(ps), pmtime(pm), ptime(pt), pts(_pts), prval(prval) {} + void finish(int r) override { using ceph::decode; if (r >= 0) { auto p = bl.cbegin(); @@ -344,91 +252,58 @@ struct ObjectOperation { *ptime = ceph::real_clock::to_time_t(mtime); if (pts) *pts = ceph::real_clock::to_timespec(mtime); - } catch (const ceph::buffer::error& e) { + } catch (ceph::buffer::error& e) { if (prval) *prval = -EIO; - if (pec) - *pec = e.code(); } } } }; void stat(uint64_t *psize, ceph::real_time *pmtime, int *prval) { add_op(CEPH_OSD_OP_STAT); - set_handler(CB_ObjectOperation_stat(psize, pmtime, nullptr, nullptr, prval, - nullptr)); - out_rval.back() = prval; - } - void stat(uint64_t *psize, ceph::real_time *pmtime, - boost::system::error_code* ec) { - add_op(CEPH_OSD_OP_STAT); - set_handler(CB_ObjectOperation_stat(psize, pmtime, nullptr, nullptr, - nullptr, ec)); - out_ec.back() = ec; + unsigned p = ops.size() - 1; + C_ObjectOperation_stat *h = new C_ObjectOperation_stat(psize, pmtime, NULL, NULL, + prval); + out_bl[p] = &h->bl; + out_handler[p] = h; + out_rval[p] = prval; } void stat(uint64_t *psize, time_t *ptime, int *prval) { add_op(CEPH_OSD_OP_STAT); - set_handler(CB_ObjectOperation_stat(psize, nullptr, ptime, nullptr, prval, - nullptr)); - out_rval.back() = prval; + unsigned p = ops.size() - 1; + C_ObjectOperation_stat *h = new C_ObjectOperation_stat(psize, NULL, ptime, NULL, + prval); + out_bl[p] = &h->bl; + out_handler[p] = h; + out_rval[p] = prval; } void stat(uint64_t *psize, struct timespec *pts, int *prval) { add_op(CEPH_OSD_OP_STAT); - set_handler(CB_ObjectOperation_stat(psize, nullptr, nullptr, pts, prval, nullptr)); - out_rval.back() = prval; - } - void stat(uint64_t *psize, ceph::real_time *pmtime, nullptr_t) { - add_op(CEPH_OSD_OP_STAT); - set_handler(CB_ObjectOperation_stat(psize, pmtime, nullptr, nullptr, nullptr, - nullptr)); - } - void stat(uint64_t *psize, time_t *ptime, nullptr_t) { - add_op(CEPH_OSD_OP_STAT); - set_handler(CB_ObjectOperation_stat(psize, nullptr, ptime, nullptr, nullptr, - nullptr)); - } - void stat(uint64_t *psize, struct timespec *pts, nullptr_t) { - add_op(CEPH_OSD_OP_STAT); - set_handler(CB_ObjectOperation_stat(psize, nullptr, nullptr, pts, nullptr, - nullptr)); - } - void stat(uint64_t *psize, nullptr_t, nullptr_t) { - add_op(CEPH_OSD_OP_STAT); - set_handler(CB_ObjectOperation_stat(psize, nullptr, nullptr, nullptr, - nullptr, nullptr)); + unsigned p = ops.size() - 1; + C_ObjectOperation_stat *h = new C_ObjectOperation_stat(psize, NULL, NULL, pts, + prval); + out_bl[p] = &h->bl; + out_handler[p] = h; + out_rval[p] = prval; } - // object cmpext - struct CB_ObjectOperation_cmpext { - int* prval = nullptr; - boost::system::error_code* ec = nullptr; - std::size_t* s = nullptr; - explicit CB_ObjectOperation_cmpext(int *prval) + struct C_ObjectOperation_cmpext : public Context { + int *prval; + explicit C_ObjectOperation_cmpext(int *prval) : prval(prval) {} - CB_ObjectOperation_cmpext(boost::system::error_code* ec, std::size_t* s) - : ec(ec), s(s) {} - void operator()(boost::system::error_code ec, int r, const ceph::buffer::list&) { + void finish(int r) { if (prval) *prval = r; - if (this->ec) - *this->ec = ec; - if (s) - *s = static_cast<std::size_t>(-(MAX_ERRNO - r)); } }; void cmpext(uint64_t off, ceph::buffer::list& cmp_bl, int *prval) { add_data(CEPH_OSD_OP_CMPEXT, off, cmp_bl.length(), cmp_bl); - set_handler(CB_ObjectOperation_cmpext(prval)); - out_rval.back() = prval; - } - - void cmpext(uint64_t off, ceph::buffer::list&& cmp_bl, boost::system::error_code* ec, - std::size_t* s) { - add_data(CEPH_OSD_OP_CMPEXT, off, cmp_bl.length(), cmp_bl); - set_handler(CB_ObjectOperation_cmpext(ec, s)); - out_ec.back() = ec; + unsigned p = ops.size() - 1; + C_ObjectOperation_cmpext *h = new C_ObjectOperation_cmpext(prval); + out_handler[p] = h; + out_rval[p] = prval; } // Used by C API @@ -436,8 +311,10 @@ struct ObjectOperation { ceph::buffer::list cmp_bl; cmp_bl.append(cmp_buf, cmp_len); add_data(CEPH_OSD_OP_CMPEXT, off, cmp_len, cmp_bl); - set_handler(CB_ObjectOperation_cmpext(prval)); - out_rval.back() = prval; + unsigned p = ops.size() - 1; + C_ObjectOperation_cmpext *h = new C_ObjectOperation_cmpext(prval); + out_handler[p] = h; + out_rval[p] = prval; } void read(uint64_t off, uint64_t len, ceph::buffer::list *pbl, int *prval, @@ -447,29 +324,20 @@ struct ObjectOperation { unsigned p = ops.size() - 1; out_bl[p] = pbl; out_rval[p] = prval; - set_handler(ctx); + out_handler[p] = ctx; } - void read(uint64_t off, uint64_t len, boost::system::error_code* ec, - ceph::buffer::list* pbl) { + struct C_ObjectOperation_sparse_read : public Context { ceph::buffer::list bl; - add_data(CEPH_OSD_OP_READ, off, len, bl); - out_ec.back() = ec; - out_bl.back() = pbl; - } - - template<typename Ex> - struct CB_ObjectOperation_sparse_read { - ceph::buffer::list* data_bl; - Ex* extents; - int* prval; - boost::system::error_code* pec; - CB_ObjectOperation_sparse_read(ceph::buffer::list* data_bl, - Ex* extents, - int* prval, - boost::system::error_code* pec) - : data_bl(data_bl), extents(extents), prval(prval), pec(pec) {} - void operator()(boost::system::error_code ec, int r, const ceph::buffer::list& bl) { + ceph::buffer::list *data_bl; + std::map<uint64_t, uint64_t> *extents; + int *prval; + C_ObjectOperation_sparse_read(ceph::buffer::list *data_bl, + std::map<uint64_t, uint64_t> *extents, + int *prval) + : data_bl(data_bl), extents(extents), prval(prval) {} + void finish(int r) override { + using ceph::decode; auto iter = bl.cbegin(); if (r >= 0) { // NOTE: it's possible the sub-op has not been executed but the result @@ -479,35 +347,26 @@ struct ObjectOperation { try { decode(*extents, iter); decode(*data_bl, iter); - } catch (const ceph::buffer::error& e) { + } catch (ceph::buffer::error& e) { if (prval) *prval = -EIO; - if (pec) - *pec = e.code(); } } else if (prval) { *prval = -EIO; - if (pec) - *pec = buffer::errc::end_of_buffer; - } + } } } }; - void sparse_read(uint64_t off, uint64_t len, std::map<uint64_t, uint64_t>* m, - ceph::buffer::list* data_bl, int* prval) { + void sparse_read(uint64_t off, uint64_t len, std::map<uint64_t,uint64_t> *m, + ceph::buffer::list *data_bl, int *prval) { ceph::buffer::list bl; add_data(CEPH_OSD_OP_SPARSE_READ, off, len, bl); - set_handler(CB_ObjectOperation_sparse_read(data_bl, m, prval, nullptr)); - out_rval.back() = prval; - } - void sparse_read(uint64_t off, uint64_t len, - boost::system::error_code* ec, - std::vector<std::pair<uint64_t, uint64_t>>* m, - ceph::buffer::list* data_bl) { - ceph::buffer::list bl; - add_data(CEPH_OSD_OP_SPARSE_READ, off, len, bl); - set_handler(CB_ObjectOperation_sparse_read(data_bl, m, nullptr, ec)); - out_ec.back() = ec; + unsigned p = ops.size() - 1; + C_ObjectOperation_sparse_read *h = + new C_ObjectOperation_sparse_read(data_bl, m, prval); + out_bl[p] = &h->bl; + out_handler[p] = h; + out_rval[p] = prval; } void write(uint64_t off, ceph::buffer::list& bl, uint64_t truncate_size, @@ -563,7 +422,7 @@ struct ObjectOperation { unsigned p = ops.size() - 1; out_bl[p] = pbl; out_rval[p] = prval; - set_handler(ctx); + out_handler[p] = ctx; } // object attrs @@ -574,37 +433,28 @@ struct ObjectOperation { out_bl[p] = pbl; out_rval[p] = prval; } - void getxattr(std::string_view name, boost::system::error_code* ec, - buffer::list *pbl) { - ceph::buffer::list bl; - add_xattr(CEPH_OSD_OP_GETXATTR, name, bl); - out_bl.back() = pbl; - out_ec.back() = ec; - } - - template<typename Vals> - struct CB_ObjectOperation_decodevals { + struct C_ObjectOperation_decodevals : public Context { uint64_t max_entries; - Vals* pattrs; - bool* ptruncated; - int* prval; - boost::system::error_code* pec; - CB_ObjectOperation_decodevals(uint64_t m, Vals* pa, - bool *pt, int *pr, - boost::system::error_code* pec) - : max_entries(m), pattrs(pa), ptruncated(pt), prval(pr), pec(pec) { + ceph::buffer::list bl; + std::map<std::string,ceph::buffer::list> *pattrs; + bool *ptruncated; + int *prval; + C_ObjectOperation_decodevals(uint64_t m, std::map<std::string,ceph::buffer::list> *pa, + bool *pt, int *pr) + : max_entries(m), pattrs(pa), ptruncated(pt), prval(pr) { if (ptruncated) { *ptruncated = false; } } - void operator()(boost::system::error_code ec, int r, const ceph::buffer::list& bl) { + void finish(int r) override { + using ceph::decode; if (r >= 0) { auto p = bl.cbegin(); try { if (pattrs) decode(*pattrs, p); if (ptruncated) { - Vals ignore; + std::map<std::string,ceph::buffer::list> ignore; if (!pattrs) { decode(ignore, p); pattrs = &ignore; @@ -612,36 +462,34 @@ struct ObjectOperation { if (!p.end()) { decode(*ptruncated, p); } else { - // the OSD did not provide this. Since old OSDs do not + // the OSD did not provide this. since old OSDs do not // enfoce omap result limits either, we can infer it from // the size of the result *ptruncated = (pattrs->size() == max_entries); } } - } catch (const ceph::buffer::error& e) { + } + catch (ceph::buffer::error& e) { if (prval) *prval = -EIO; - if (pec) - *pec = e.code(); } } } }; - template<typename Keys> - struct CB_ObjectOperation_decodekeys { + struct C_ObjectOperation_decodekeys : public Context { uint64_t max_entries; - Keys* pattrs; + ceph::buffer::list bl; + std::set<std::string> *pattrs; bool *ptruncated; int *prval; - boost::system::error_code* pec; - CB_ObjectOperation_decodekeys(uint64_t m, Keys* pa, bool *pt, - int *pr, boost::system::error_code* pec) - : max_entries(m), pattrs(pa), ptruncated(pt), prval(pr), pec(pec) { + C_ObjectOperation_decodekeys(uint64_t m, std::set<std::string> *pa, bool *pt, + int *pr) + : max_entries(m), pattrs(pa), ptruncated(pt), prval(pr) { if (ptruncated) { *ptruncated = false; } } - void operator()(boost::system::error_code ec, int r, const ceph::buffer::list& bl) { + void finish(int r) override { if (r >= 0) { using ceph::decode; auto p = bl.cbegin(); @@ -649,7 +497,7 @@ struct ObjectOperation { if (pattrs) decode(*pattrs, p); if (ptruncated) { - Keys ignore; + std::set<std::string> ignore; if (!pattrs) { decode(ignore, p); pattrs = &ignore; @@ -663,24 +511,22 @@ struct ObjectOperation { *ptruncated = (pattrs->size() == max_entries); } } - } catch (const ceph::buffer::error& e) { + } + catch (ceph::buffer::error& e) { if (prval) *prval = -EIO; - if (pec) - *pec = e.code(); } } } }; - template<typename Watchers> - struct CB_ObjectOperation_decodewatchers { - Watchers* pwatchers; - int* prval; - boost::system::error_code* pec; - CB_ObjectOperation_decodewatchers(Watchers* pw, int* pr, - boost::system::error_code* pec) - : pwatchers(pw), prval(pr), pec(pec) {} - void operator()(boost::system::error_code ec, int r, const ceph::buffer::list& bl) { + struct C_ObjectOperation_decodewatchers : public Context { + ceph::buffer::list bl; + std::list<obj_watch_t> *pwatchers; + int *prval; + C_ObjectOperation_decodewatchers(std::list<obj_watch_t> *pw, int *pr) + : pwatchers(pw), prval(pr) {} + void finish(int r) override { + using ceph::decode; if (r >= 0) { auto p = bl.cbegin(); try { @@ -698,23 +544,21 @@ struct ObjectOperation { pwatchers->push_back(std::move(ow)); } } - } catch (const ceph::buffer::error& e) { + } + catch (ceph::buffer::error& e) { if (prval) *prval = -EIO; - if (pec) - *pec = e.code(); } } } }; - struct CB_ObjectOperation_decodesnaps { + struct C_ObjectOperation_decodesnaps : public Context { + ceph::buffer::list bl; librados::snap_set_t *psnaps; int *prval; - boost::system::error_code* pec; - CB_ObjectOperation_decodesnaps(librados::snap_set_t* ps, int* pr, - boost::system::error_code* pec) - : psnaps(ps), prval(pr), pec(pec) {} - void operator()(boost::system::error_code ec, int r, const ceph::buffer::list& bl) { + C_ObjectOperation_decodesnaps(librados::snap_set_t *ps, int *pr) + : psnaps(ps), prval(pr) {} + void finish(int r) override { if (r >= 0) { using ceph::decode; auto p = bl.cbegin(); @@ -723,9 +567,7 @@ struct ObjectOperation { decode(resp, p); if (psnaps) { psnaps->clones.clear(); - for (auto ci = resp.clones.begin(); - ci != resp.clones.end(); - ++ci) { + for (auto ci = resp.clones.begin(); ci != resp.clones.end(); ++ci) { librados::clone_info_t clone; clone.cloneid = ci->cloneid; @@ -739,11 +581,9 @@ struct ObjectOperation { } psnaps->seq = resp.seq; } - } catch (const ceph::buffer::error& e) { + } catch (ceph::buffer::error& e) { if (prval) *prval = -EIO; - if (pec) - *pec = e.code(); } } } @@ -751,23 +591,17 @@ struct ObjectOperation { void getxattrs(std::map<std::string,ceph::buffer::list> *pattrs, int *prval) { add_op(CEPH_OSD_OP_GETXATTRS); if (pattrs || prval) { - set_handler(CB_ObjectOperation_decodevals(0, pattrs, nullptr, prval, - nullptr)); - out_rval.back() = prval; + unsigned p = ops.size() - 1; + C_ObjectOperation_decodevals *h + = new C_ObjectOperation_decodevals(0, pattrs, nullptr, prval); + out_handler[p] = h; + out_bl[p] = &h->bl; + out_rval[p] = prval; } } - void getxattrs(boost::system::error_code* ec, - boost::container::flat_map<std::string, ceph::buffer::list> *pattrs) { - add_op(CEPH_OSD_OP_GETXATTRS); - set_handler(CB_ObjectOperation_decodevals(0, pattrs, nullptr, nullptr, ec)); - out_ec.back() = ec; - } void setxattr(const char *name, const ceph::buffer::list& bl) { add_xattr(CEPH_OSD_OP_SETXATTR, name, bl); } - void setxattr(std::string_view name, const ceph::buffer::list& bl) { - add_xattr(CEPH_OSD_OP_SETXATTR, name, bl); - } void setxattr(const char *name, const std::string& s) { ceph::buffer::list bl; bl.append(s); @@ -777,19 +611,11 @@ struct ObjectOperation { const ceph::buffer::list& bl) { add_xattr_cmp(CEPH_OSD_OP_CMPXATTR, name, cmp_op, cmp_mode, bl); } - void cmpxattr(std::string_view name, uint8_t cmp_op, uint8_t cmp_mode, - const ceph::buffer::list& bl) { - add_xattr_cmp(CEPH_OSD_OP_CMPXATTR, name, cmp_op, cmp_mode, bl); - } void rmxattr(const char *name) { ceph::buffer::list bl; add_xattr(CEPH_OSD_OP_RMXATTR, name, bl); } - void rmxattr(std::string_view name) { - ceph::buffer::list bl; - add_xattr(CEPH_OSD_OP_RMXATTR, name, bl); - } - void setxattrs(map<string, ceph::buffer::list>& attrs) { + void setxattrs(std::map<std::string, ceph::buffer::list>& attrs) { using ceph::encode; ceph::buffer::list bl; encode(attrs, bl); @@ -822,28 +648,14 @@ struct ObjectOperation { op.op.extent.length = bl.length(); op.indata.claim_append(bl); if (prval || ptruncated || out_set) { - set_handler(CB_ObjectOperation_decodekeys(max_to_get, out_set, ptruncated, prval, - nullptr)); - out_rval.back() = prval; + unsigned p = ops.size() - 1; + C_ObjectOperation_decodekeys *h = + new C_ObjectOperation_decodekeys(max_to_get, out_set, ptruncated, prval); + out_handler[p] = h; + out_bl[p] = &h->bl; + out_rval[p] = prval; } } - void omap_get_keys(std::optional<std::string_view> start_after, - uint64_t max_to_get, - boost::system::error_code* ec, - boost::container::flat_set<std::string> *out_set, - bool *ptruncated) { - OSDOp& op = add_op(CEPH_OSD_OP_OMAPGETKEYS); - ceph::buffer::list bl; - encode(start_after ? *start_after : std::string_view{}, bl); - encode(max_to_get, bl); - op.op.extent.offset = 0; - op.op.extent.length = bl.length(); - op.indata.claim_append(bl); - set_handler( - CB_ObjectOperation_decodekeys(max_to_get, out_set, ptruncated, nullptr, - ec)); - out_ec.back() = ec; - } void omap_get_vals(const std::string &start_after, const std::string &filter_prefix, @@ -861,34 +673,19 @@ struct ObjectOperation { op.op.extent.length = bl.length(); op.indata.claim_append(bl); if (prval || out_set || ptruncated) { - set_handler(CB_ObjectOperation_decodevals(max_to_get, out_set, ptruncated, - prval, nullptr)); - out_rval.back() = prval; + unsigned p = ops.size() - 1; + C_ObjectOperation_decodevals *h = + new C_ObjectOperation_decodevals(max_to_get, out_set, ptruncated, prval); + out_handler[p] = h; + out_bl[p] = &h->bl; + out_rval[p] = prval; } } - void omap_get_vals(std::optional<std::string_view> start_after, - std::optional<std::string_view> filter_prefix, - uint64_t max_to_get, - boost::system::error_code* ec, - boost::container::flat_map<std::string, ceph::buffer::list> *out_set, - bool *ptruncated) { - OSDOp &op = add_op(CEPH_OSD_OP_OMAPGETVALS); - ceph::buffer::list bl; - encode(start_after ? *start_after : std::string_view{}, bl); - encode(max_to_get, bl); - encode(filter_prefix ? *start_after : std::string_view{}, bl); - op.op.extent.offset = 0; - op.op.extent.length = bl.length(); - op.indata.claim_append(bl); - set_handler(CB_ObjectOperation_decodevals(max_to_get, out_set, ptruncated, - nullptr, ec)); - out_ec.back() = ec; - } - void omap_get_vals_by_keys(const std::set<std::string> &to_get, - std::map<std::string, ceph::buffer::list> *out_set, - int *prval) { + std::map<std::string, ceph::buffer::list> *out_set, + int *prval) { + using ceph::encode; OSDOp &op = add_op(CEPH_OSD_OP_OMAPGETVALSBYKEYS); ceph::buffer::list bl; encode(to_get, bl); @@ -896,28 +693,16 @@ struct ObjectOperation { op.op.extent.length = bl.length(); op.indata.claim_append(bl); if (prval || out_set) { - set_handler(CB_ObjectOperation_decodevals(0, out_set, nullptr, prval, - nullptr)); - out_rval.back() = prval; + unsigned p = ops.size() - 1; + C_ObjectOperation_decodevals *h = + new C_ObjectOperation_decodevals(0, out_set, nullptr, prval); + out_handler[p] = h; + out_bl[p] = &h->bl; + out_rval[p] = prval; } } - void omap_get_vals_by_keys( - const boost::container::flat_set<std::string>& to_get, - boost::system::error_code* ec, - boost::container::flat_map<std::string, ceph::buffer::list> *out_set) { - OSDOp &op = add_op(CEPH_OSD_OP_OMAPGETVALSBYKEYS); - ceph::buffer::list bl; - encode(to_get, bl); - op.op.extent.offset = 0; - op.op.extent.length = bl.length(); - op.indata.claim_append(bl); - set_handler(CB_ObjectOperation_decodevals(0, out_set, nullptr, nullptr, - ec)); - out_ec.back() = ec; - } - - void omap_cmp(const std::map<std::string, pair<ceph::buffer::list,int> > &assertions, + void omap_cmp(const std::map<std::string, std::pair<ceph::buffer::list,int> > &assertions, int *prval) { using ceph::encode; OSDOp &op = add_op(CEPH_OSD_OP_OMAP_CMP); @@ -932,18 +717,6 @@ struct ObjectOperation { } } - void omap_cmp(const boost::container::flat_map< - std::string, pair<ceph::buffer::list, int>>& assertions, - boost::system::error_code *ec) { - OSDOp &op = add_op(CEPH_OSD_OP_OMAP_CMP); - ceph::buffer::list bl; - encode(assertions, bl); - op.op.extent.offset = 0; - op.op.extent.length = bl.length(); - op.indata.claim_append(bl); - out_ec.back() = ec; - } - struct C_ObjectOperation_copyget : public Context { ceph::buffer::list bl; object_copy_cursor_t *cursor; @@ -1032,7 +805,7 @@ struct ObjectOperation { if (out_truncate_size) *out_truncate_size = copy_reply.truncate_size; *cursor = copy_reply.cursor; - } catch (const ceph::buffer::error& e) { + } catch (ceph::buffer::error& e) { if (prval) *prval = -EIO; } @@ -1073,7 +846,7 @@ struct ObjectOperation { out_reqid_return_codes, truncate_seq, truncate_size, prval); out_bl[p] = &h->bl; - set_handler(h); + out_handler[p] = h; } void undirty() { @@ -1096,7 +869,7 @@ struct ObjectOperation { decode(isdirty, p); if (pisdirty) *pisdirty = isdirty; - } catch (const ceph::buffer::error& e) { + } catch (ceph::buffer::error& e) { if (prval) *prval = -EIO; } @@ -1110,7 +883,7 @@ struct ObjectOperation { C_ObjectOperation_isdirty *h = new C_ObjectOperation_isdirty(pisdirty, prval); out_bl[p] = &h->bl; - set_handler(h); + out_handler[p] = h; } struct C_ObjectOperation_hit_set_ls : public Context { @@ -1145,7 +918,7 @@ struct ObjectOperation { } if (putls) putls->swap(ls); - } catch (const ceph::buffer::error& e) { + } catch (ceph::buffer::error& e) { r = -EIO; } if (prval) @@ -1170,7 +943,7 @@ struct ObjectOperation { C_ObjectOperation_hit_set_ls *h = new C_ObjectOperation_hit_set_ls(pls, NULL, prval); out_bl[p] = &h->bl; - set_handler(h); + out_handler[p] = h; } void hit_set_ls(std::list<std::pair<ceph::real_time, ceph::real_time> > *pls, int *prval) { @@ -1180,7 +953,7 @@ struct ObjectOperation { C_ObjectOperation_hit_set_ls *h = new C_ObjectOperation_hit_set_ls(NULL, pls, prval); out_bl[p] = &h->bl; - set_handler(h); + out_handler[p] = h; } /** @@ -1208,19 +981,8 @@ struct ObjectOperation { out_rval[p] = prval; } - void omap_get_header(boost::system::error_code* ec, ceph::buffer::list *bl) { - add_op(CEPH_OSD_OP_OMAPGETHEADER); - out_bl.back() = bl; - out_ec.back() = ec; - } - - void omap_set(const map<string, ceph::buffer::list> &map) { - ceph::buffer::list bl; - encode(map, bl); - add_data(CEPH_OSD_OP_OMAPSETVALS, 0, bl.length(), bl); - } - - void omap_set(const boost::container::flat_map<string, ceph::buffer::list>& map) { + void omap_set(const std::map<std::string, ceph::buffer::list>& map) { + using ceph::encode; ceph::buffer::list bl; encode(map, bl); add_data(CEPH_OSD_OP_OMAPSETVALS, 0, bl.length(), bl); @@ -1240,11 +1002,6 @@ struct ObjectOperation { encode(to_remove, bl); add_data(CEPH_OSD_OP_OMAPRMKEYS, 0, bl.length(), bl); } - void omap_rm_keys(const boost::container::flat_set<std::string>& to_remove) { - ceph::buffer::list bl; - encode(to_remove, bl); - add_data(CEPH_OSD_OP_OMAPRMKEYS, 0, bl.length(), bl); - } void omap_rm_range(std::string_view key_begin, std::string_view key_end) { bufferlist bl; @@ -1263,24 +1020,6 @@ struct ObjectOperation { add_call(CEPH_OSD_OP_CALL, cname, method, indata, outdata, ctx, prval); } - void call(std::string_view cname, std::string_view method, - const ceph::buffer::list& indata, boost::system::error_code* ec) { - add_call(CEPH_OSD_OP_CALL, cname, method, indata, NULL, NULL, NULL); - out_ec.back() = ec; - } - - void call(std::string_view cname, std::string_view method, const ceph::buffer::list& indata, - boost::system::error_code* ec, ceph::buffer::list *outdata) { - add_call(CEPH_OSD_OP_CALL, cname, method, indata, outdata, nullptr, nullptr); - out_ec.back() = ec; - } - void call(std::string_view cname, std::string_view method, - const ceph::buffer::list& indata, - fu2::unique_function<void (boost::system::error_code, - const ceph::buffer::list&) &&> f) { - add_call(CEPH_OSD_OP_CALL, cname, method, indata, std::move(f)); - } - // watch/notify void watch(uint64_t cookie, __u8 op, uint32_t timeout = 0) { OSDOp& osd_op = add_op(CEPH_OSD_OP_WATCH); @@ -1313,26 +1052,26 @@ struct ObjectOperation { void list_watchers(std::list<obj_watch_t> *out, int *prval) { - add_op(CEPH_OSD_OP_LIST_WATCHERS); + (void)add_op(CEPH_OSD_OP_LIST_WATCHERS); if (prval || out) { - set_handler(CB_ObjectOperation_decodewatchers(out, prval, nullptr)); - out_rval.back() = prval; + unsigned p = ops.size() - 1; + C_ObjectOperation_decodewatchers *h = + new C_ObjectOperation_decodewatchers(out, prval); + out_handler[p] = h; + out_bl[p] = &h->bl; + out_rval[p] = prval; } } - void list_watchers(vector<obj_watch_t>* out, - boost::system::error_code* ec) { - add_op(CEPH_OSD_OP_LIST_WATCHERS); - set_handler(CB_ObjectOperation_decodewatchers(out, nullptr, ec)); - out_ec.back() = ec; - } - void list_snaps(librados::snap_set_t *out, int *prval, - boost::system::error_code* ec = nullptr) { - add_op(CEPH_OSD_OP_LIST_SNAPS); - if (prval || out || ec) { - set_handler(CB_ObjectOperation_decodesnaps(out, prval, ec)); - out_rval.back() = prval; - out_ec.back() = ec; + void list_snaps(librados::snap_set_t *out, int *prval) { + (void)add_op(CEPH_OSD_OP_LIST_SNAPS); + if (prval || out) { + unsigned p = ops.size() - 1; + C_ObjectOperation_decodesnaps *h = + new C_ObjectOperation_decodesnaps(out, prval); + out_handler[p] = h; + out_bl[p] = &h->bl; + out_rval[p] = prval; } } @@ -1458,19 +1197,15 @@ struct ObjectOperation { set_last_op_flags(CEPH_OSD_OP_FLAG_FAILOK); } - template<typename V> - void dup(V& sops) { - ops.clear(); - std::copy(sops.begin(), sops.end(), - std::back_inserter(ops)); + void dup(std::vector<OSDOp>& sops) { + ops = sops; out_bl.resize(sops.size()); out_handler.resize(sops.size()); out_rval.resize(sops.size()); - out_ec.resize(sops.size()); for (uint32_t i = 0; i < sops.size(); i++) { out_bl[i] = &sops[i].outdata; + out_handler[i] = NULL; out_rval[i] = &sops[i].rval; - out_ec[i] = nullptr; } } @@ -1486,28 +1221,12 @@ struct ObjectOperation { } }; -inline std::ostream& operator <<(std::ostream& m, const ObjectOperation& oo) { - auto i = oo.ops.cbegin(); - m << '['; - while (i != oo.ops.cend()) { - if (i != oo.ops.cbegin()) - m << ' '; - m << *i; - ++i; - } - m << ']'; - return m; -} - // ---------------- + class Objecter : public md_config_obs_t, public Dispatcher { - using MOSDOp = _mosdop::MOSDOp<osdc_opvec>; public: - using OpSignature = void(boost::system::error_code); - using OpCompletion = ceph::async::Completion<OpSignature>; - // config observer bits const char** get_tracked_conf_keys() const override; void handle_conf_change(const ConfigProxy& conf, @@ -1516,13 +1235,10 @@ public: public: Messenger *messenger; MonClient *monc; - boost::asio::io_context& service; - // The guaranteed sequenced, one-at-a-time execution and apparently - // people sometimes depend on this. - boost::asio::io_context::strand finish_strand{service}; - ZTracer::Endpoint trace_endpoint{"0.0.0.0", 0, "Objecter"}; + Finisher *finisher; + ZTracer::Endpoint trace_endpoint; private: - std::unique_ptr<OSDMap> osdmap{std::make_unique<OSDMap>()}; + std::unique_ptr<OSDMap> osdmap; public: using Dispatcher::cct; std::multimap<std::string,std::string> crush_location; @@ -1557,8 +1273,7 @@ private: : epoch(epoch), up(up), up_primary(up_primary), acting(acting), acting_primary(acting_primary) {} }; - ceph::shared_mutex pg_mapping_lock = - ceph::make_shared_mutex("Objecter::pg_mapping_lock"); + std::shared_mutex pg_mapping_lock; // pool -> pg mapping std::map<int64_t, std::vector<pg_mapping_t>> pg_mappings; @@ -1613,11 +1328,14 @@ private: version_t last_seen_osdmap_version = 0; version_t last_seen_pgmap_version = 0; - mutable ceph::shared_mutex rwlock = - ceph::make_shared_mutex("Objecter::rwlock"); + mutable std::shared_mutex rwlock; + using lock_guard = std::lock_guard<decltype(rwlock)>; + using unique_lock = std::unique_lock<decltype(rwlock)>; + using shared_lock = boost::shared_lock<decltype(rwlock)>; + using shunique_lock = ceph::shunique_lock<decltype(rwlock)>; ceph::timer<ceph::coarse_mono_clock> timer; - PerfCounters* logger = nullptr; + PerfCounters *logger = nullptr; uint64_t tick_event = 0; @@ -1707,175 +1425,92 @@ public: void dump(ceph::Formatter *f) const; }; - std::unique_ptr<ceph::async::Completion<void(boost::system::error_code)>> - OpContextVert(Context* c) { - if (c) - return ceph::async::Completion<void(boost::system::error_code)>::create( - service.get_executor(), - [c = std::unique_ptr<Context>(c)] - (boost::system::error_code e) mutable { - c.release()->complete(e); - }); - else - return nullptr; - } - - template<typename T> - std::unique_ptr<ceph::async::Completion<void(boost::system::error_code, T)>> - OpContextVert(Context* c, T* p) { - - if (c || p) - return - ceph::async::Completion<void(boost::system::error_code, T)>::create( - service.get_executor(), - [c = std::unique_ptr<Context>(c), p] - (boost::system::error_code e, T r) mutable { - if (p) - *p = std::move(r); - if (c) - c.release()->complete(ceph::from_error_code(e)); - }); - else - return nullptr; - } - - template<typename T> - std::unique_ptr<ceph::async::Completion<void(boost::system::error_code, T)>> - OpContextVert(Context* c, T& p) { - if (c) - return ceph::async::Completion< - void(boost::system::error_code, T)>::create( - service.get_executor(), - [c = std::unique_ptr<Context>(c), &p] - (boost::system::error_code e, T r) mutable { - p = std::move(r); - if (c) - c.release()->complete(ceph::from_error_code(e)); - }); - else - return nullptr; - } - struct Op : public RefCountedObject { - OSDSession *session = nullptr; - int incarnation = 0; + OSDSession *session; + int incarnation; op_target_t target; - ConnectionRef con = nullptr; // for rx buffer only - uint64_t features = CEPH_FEATURES_SUPPORTED_DEFAULT; // explicitly specified op features + ConnectionRef con; // for rx buffer only + uint64_t features; // explicitly specified op features - osdc_opvec ops; + std::vector<OSDOp> ops; - snapid_t snapid = CEPH_NOSNAP; + snapid_t snapid; SnapContext snapc; ceph::real_time mtime; - ceph::buffer::list *outbl = nullptr; - boost::container::small_vector<ceph::buffer::list*, osdc_opvec_len> out_bl; - boost::container::small_vector< - fu2::unique_function<void(boost::system::error_code, int, - const ceph::buffer::list& bl) &&>, - osdc_opvec_len> out_handler; - boost::container::small_vector<int*, osdc_opvec_len> out_rval; - boost::container::small_vector<boost::system::error_code*, - osdc_opvec_len> out_ec; - - int priority = 0; - using OpSig = void(boost::system::error_code); - using OpComp = ceph::async::Completion<OpSig>; - // Due to an irregularity of cmpxattr, we actualy need the 'int' - // value for onfinish for legacy librados users. As such just - // preserve the Context* in this one case. That way we can have - // our callers just pass in a unique_ptr<OpComp> and not deal with - // our signature in Objecter being different than the exposed - // signature in RADOS. - std::variant<std::unique_ptr<OpComp>, Context*> onfinish; - uint64_t ontimeout = 0; + ceph::buffer::list *outbl; + std::vector<ceph::buffer::list*> out_bl; + std::vector<Context*> out_handler; + std::vector<int*> out_rval; - ceph_tid_t tid = 0; - int attempts = 0; + int priority; + Context *onfinish; + uint64_t ontimeout; + + ceph_tid_t tid; + int attempts; version_t *objver; - epoch_t *reply_epoch = nullptr; + epoch_t *reply_epoch; ceph::coarse_mono_time stamp; - epoch_t map_dne_bound = 0; + epoch_t map_dne_bound; - int budget = -1; + int budget; /// true if we should resend this message on failure - bool should_resend = true; + bool should_resend; /// true if the throttle budget is get/put on a series of OPs, /// instead of per OP basis, when this flag is set, the budget is /// acquired before sending the very first OP of the series and /// released upon receiving the last OP reply. - bool ctx_budgeted = false; + bool ctx_budgeted; int *data_offset; osd_reqid_t reqid; // explicitly setting reqid ZTracer::Trace trace; - static bool has_completion(decltype(onfinish)& f) { - return std::visit([](auto&& arg) { return bool(arg);}, f); - } - bool has_completion() { - return has_completion(onfinish); - } - - static void complete(decltype(onfinish)&& f, boost::system::error_code ec, - int r) { - std::visit([ec, r](auto&& arg) { - if constexpr (std::is_same_v<std::decay_t<decltype(arg)>, - Context*>) { - arg->complete(r); - } else { - arg->defer(std::move(arg), ec); - } - }, std::move(f)); - } - void complete(boost::system::error_code ec, int r) { - complete(std::move(onfinish), ec, r); - } - - Op(const object_t& o, const object_locator_t& ol, osdc_opvec&& _ops, - int f, std::unique_ptr<OpComp>&& fin, - version_t *ov, int *offset = nullptr, + Op(const object_t& o, const object_locator_t& ol, std::vector<OSDOp>& op, + int f, Context *fin, version_t *ov, int *offset = NULL, ZTracer::Trace *parent_trace = nullptr) : + session(NULL), incarnation(0), target(o, ol, f), - ops(std::move(_ops)), - out_bl(ops.size(), nullptr), - out_handler(ops.size()), - out_rval(ops.size(), nullptr), - out_ec(ops.size(), nullptr), - onfinish(std::move(fin)), + con(NULL), + features(CEPH_FEATURES_SUPPORTED_DEFAULT), + snapid(CEPH_NOSNAP), + outbl(NULL), + priority(0), + onfinish(fin), + ontimeout(0), + tid(0), + attempts(0), objver(ov), + reply_epoch(NULL), + map_dne_bound(0), + budget(-1), + should_resend(true), + ctx_budgeted(false), data_offset(offset) { - if (target.base_oloc.key == o) - target.base_oloc.key.clear(); - if (parent_trace && parent_trace->valid()) { - trace.init("op", nullptr, parent_trace); - trace.event("start"); + ops.swap(op); + + /* initialize out_* to match op std::vector */ + out_bl.resize(ops.size()); + out_rval.resize(ops.size()); + out_handler.resize(ops.size()); + for (unsigned i = 0; i < ops.size(); i++) { + out_bl[i] = NULL; + out_handler[i] = NULL; + out_rval[i] = NULL; } - } - Op(const object_t& o, const object_locator_t& ol, osdc_opvec&& _ops, - int f, Context* fin, version_t *ov, int *offset = nullptr, - ZTracer::Trace *parent_trace = nullptr) : - target(o, ol, f), - ops(std::move(_ops)), - out_bl(ops.size(), nullptr), - out_handler(ops.size()), - out_rval(ops.size(), nullptr), - out_ec(ops.size(), nullptr), - onfinish(fin), - objver(ov), - data_offset(offset) { if (target.base_oloc.key == o) target.base_oloc.key.clear(); + if (parent_trace && parent_trace->valid()) { trace.init("op", nullptr, parent_trace); trace.event("start"); @@ -1894,22 +1529,30 @@ public: private: ~Op() override { + while (!out_handler.empty()) { + delete out_handler.back(); + out_handler.pop_back(); + } trace.event("finish"); } }; - struct CB_Op_Map_Latest { + struct C_Op_Map_Latest : public Context { Objecter *objecter; ceph_tid_t tid; - CB_Op_Map_Latest(Objecter *o, ceph_tid_t t) : objecter(o), tid(t) {} - void operator()(boost::system::error_code err, version_t latest, version_t); + version_t latest; + C_Op_Map_Latest(Objecter *o, ceph_tid_t t) : objecter(o), tid(t), + latest(0) {} + void finish(int r) override; }; - struct CB_Command_Map_Latest { + struct C_Command_Map_Latest : public Context { Objecter *objecter; uint64_t tid; - CB_Command_Map_Latest(Objecter *o, ceph_tid_t t) : objecter(o), tid(t) {} - void operator()(boost::system::error_code err, version_t latest, version_t); + version_t latest; + C_Command_Map_Latest(Objecter *o, ceph_tid_t t) : objecter(o), tid(t), + latest(0) {} + void finish(int r) override; }; struct C_Stat : public Context { @@ -2007,43 +1650,40 @@ public: struct PoolStatOp { ceph_tid_t tid; - std::vector<std::string> pools; - using OpSig = void(boost::system::error_code, - boost::container::flat_map<std::string, pool_stat_t>, - bool); - using OpComp = ceph::async::Completion<OpSig>; - std::unique_ptr<OpComp> onfinish; - std::uint64_t ontimeout; + std::list<std::string> pools; + + std::map<std::string,pool_stat_t> *pool_stats; + bool *per_pool; + Context *onfinish; + uint64_t ontimeout; + ceph::coarse_mono_time last_submit; }; struct StatfsOp { ceph_tid_t tid; + struct ceph_statfs *stats; boost::optional<int64_t> data_pool; - using OpSig = void(boost::system::error_code, - const struct ceph_statfs); - using OpComp = ceph::async::Completion<OpSig>; - - std::unique_ptr<OpComp> onfinish; + Context *onfinish; uint64_t ontimeout; ceph::coarse_mono_time last_submit; }; struct PoolOp { - ceph_tid_t tid = 0; - int64_t pool = 0; + ceph_tid_t tid; + int64_t pool; std::string name; - using OpSig = void(boost::system::error_code, ceph::buffer::list); - using OpComp = ceph::async::Completion<OpSig>; - std::unique_ptr<OpComp> onfinish; - uint64_t ontimeout = 0; - int pool_op = 0; - int16_t crush_rule = 0; - snapid_t snapid = 0; - ceph::coarse_mono_time last_submit; + Context *onfinish; + uint64_t ontimeout; + int pool_op; + int16_t crush_rule; + snapid_t snapid; + ceph::buffer::list *blp; - PoolOp() {} + ceph::coarse_mono_time last_submit; + PoolOp() : tid(0), pool(0), onfinish(NULL), ontimeout(0), pool_op(0), + crush_rule(0), snapid(0), blp(NULL) {} }; // -- osd commands -- @@ -2052,6 +1692,8 @@ public: ceph_tid_t tid = 0; std::vector<std::string> cmd; ceph::buffer::list inbl; + ceph::buffer::list *poutbl = nullptr; + std::string *prs = nullptr; // target_osd == -1 means target_pg is valid const int target_osd = -1; @@ -2063,92 +1705,108 @@ public: int map_check_error = 0; // error to return if std::map check fails const char *map_check_error_str = nullptr; - using OpSig = void(boost::system::error_code, std::string, - ceph::buffer::list); - using OpComp = ceph::async::Completion<OpSig>; - std::unique_ptr<OpComp> onfinish; - + Context *onfinish = nullptr; uint64_t ontimeout = 0; ceph::coarse_mono_time last_submit; CommandOp( int target_osd, - std::vector<string>&& cmd, - ceph::buffer::list&& inbl, - decltype(onfinish)&& onfinish) - : cmd(std::move(cmd)), - inbl(std::move(inbl)), + const std::vector<std::string> &cmd, + ceph::buffer::list inbl, + ceph::buffer::list *poutbl, + std::string *prs, + Context *onfinish) + : cmd(cmd), + inbl(inbl), + poutbl(poutbl), + prs(prs), target_osd(target_osd), - onfinish(std::move(onfinish)) {} + onfinish(onfinish) {} CommandOp( pg_t pgid, - std::vector<string>&& cmd, - ceph::buffer::list&& inbl, - decltype(onfinish)&& onfinish) - : cmd(std::move(cmd)), - inbl(std::move(inbl)), + const std::vector<std::string> &cmd, + ceph::buffer::list inbl, + ceph::buffer::list *poutbl, + std::string *prs, + Context *onfinish) + : cmd(cmd), + inbl(inbl), + poutbl(poutbl), + prs(prs), target_pg(pgid), target(pgid), - onfinish(std::move(onfinish)) {} + onfinish(onfinish) {} + }; void submit_command(CommandOp *c, ceph_tid_t *ptid); - int _calc_command_target(CommandOp *c, - ceph::shunique_lock<ceph::shared_mutex> &sul); - void _assign_command_session(CommandOp *c, - ceph::shunique_lock<ceph::shared_mutex> &sul); + int _calc_command_target(CommandOp *c, shunique_lock &sul); + void _assign_command_session(CommandOp *c, shunique_lock &sul); void _send_command(CommandOp *c); - int command_op_cancel(OSDSession *s, ceph_tid_t tid, - boost::system::error_code ec); - void _finish_command(CommandOp *c, boost::system::error_code ec, - std::string&& rs, ceph::buffer::list&& bl); + int command_op_cancel(OSDSession *s, ceph_tid_t tid, int r); + void _finish_command(CommandOp *c, int r, std::string rs); void handle_command_reply(MCommandReply *m); + // -- lingering ops -- + struct WatchContext { + // this simply mirrors librados WatchCtx2 + virtual void handle_notify(uint64_t notify_id, + uint64_t cookie, + uint64_t notifier_id, + ceph::buffer::list& bl) = 0; + virtual void handle_error(uint64_t cookie, int err) = 0; + virtual ~WatchContext() {} + }; + struct LingerOp : public RefCountedObject { - uint64_t linger_id{0}; - op_target_t target{object_t(), object_locator_t(), 0}; - snapid_t snap{CEPH_NOSNAP}; + uint64_t linger_id; + + op_target_t target; + + snapid_t snap; SnapContext snapc; ceph::real_time mtime; - osdc_opvec ops; + std::vector<OSDOp> ops; ceph::buffer::list inbl; - version_t *pobjver{nullptr}; + ceph::buffer::list *poutbl; + version_t *pobjver; - bool is_watch{false}; + bool is_watch; ceph::coarse_mono_time watch_valid_thru; ///< send time for last acked ping - boost::system::error_code last_error; ///< error from last failed ping|reconnect, if any - ceph::shared_mutex watch_lock = - ceph::make_shared_mutex("LingerOp::watch_lock"); + int last_error; ///< error from last failed ping|reconnect, if any + std::shared_mutex watch_lock; + using lock_guard = std::unique_lock<decltype(watch_lock)>; + using unique_lock = std::unique_lock<decltype(watch_lock)>; + using shared_lock = boost::shared_lock<decltype(watch_lock)>; + using shunique_lock = ceph::shunique_lock<decltype(watch_lock)>; // queue of pending async operations, with the timestamp of // when they were queued. std::list<ceph::coarse_mono_time> watch_pending_async; - uint32_t register_gen{0}; - bool registered{false}; - bool canceled{false}; - using OpSig = void(boost::system::error_code, ceph::buffer::list); - using OpComp = ceph::async::Completion<OpSig>; - std::unique_ptr<OpComp> on_reg_commit; - std::unique_ptr<OpComp> on_notify_finish; - uint64_t notify_id{0}; - - fu2::unique_function<void(boost::system::error_code, - uint64_t notify_id, - uint64_t cookie, - uint64_t notifier_id, - ceph::buffer::list&& bl)> handle; - OSDSession *session{nullptr}; + uint32_t register_gen; + bool registered; + bool canceled; + Context *on_reg_commit; + + // we trigger these from an async finisher + Context *on_notify_finish; + ceph::buffer::list *notify_result_bl; + uint64_t notify_id; + + WatchContext *watch_context; + + OSDSession *session; Objecter *objecter; - int ctx_budget{-1}; - ceph_tid_t register_tid{0}; - ceph_tid_t ping_tid{0}; - epoch_t map_dne_bound{0}; + int ctx_budget; + ceph_tid_t register_tid; + ceph_tid_t ping_tid; + epoch_t map_dne_bound; void _queued_async() { // watch_lock ust be locked unique @@ -2160,8 +1818,24 @@ public: watch_pending_async.pop_front(); } - explicit LingerOp(Objecter *o) - : objecter(o) {} + explicit LingerOp(Objecter *o) : linger_id(0), + target(object_t(), object_locator_t(), 0), + snap(CEPH_NOSNAP), poutbl(NULL), pobjver(NULL), + is_watch(false), last_error(0), + register_gen(0), + registered(false), + canceled(false), + on_reg_commit(NULL), + on_notify_finish(NULL), + notify_result_bl(NULL), + notify_id(0), + watch_context(NULL), + session(NULL), + objecter(o), + ctx_budget(-1), + register_tid(0), + ping_tid(0), + map_dne_bound(0) {} const LingerOp &operator=(const LingerOp& r) = delete; LingerOp(const LingerOp& o) = delete; @@ -2169,60 +1843,66 @@ public: uint64_t get_cookie() { return reinterpret_cast<uint64_t>(this); } + + private: + ~LingerOp() override { + delete watch_context; + } }; - struct CB_Linger_Commit { + struct C_Linger_Commit : public Context { Objecter *objecter; LingerOp *info; ceph::buffer::list outbl; // used for notify only - CB_Linger_Commit(Objecter *o, LingerOp *l) : objecter(o), info(l) { + C_Linger_Commit(Objecter *o, LingerOp *l) : objecter(o), info(l) { info->get(); } - ~CB_Linger_Commit() { + ~C_Linger_Commit() override { info->put(); } - void operator()(boost::system::error_code ec) { - objecter->_linger_commit(info, ec, outbl); + void finish(int r) override { + objecter->_linger_commit(info, r, outbl); } }; - struct CB_Linger_Reconnect { + struct C_Linger_Reconnect : public Context { Objecter *objecter; LingerOp *info; - CB_Linger_Reconnect(Objecter *o, LingerOp *l) - : objecter(o), info(l) { + C_Linger_Reconnect(Objecter *o, LingerOp *l) : objecter(o), info(l) { info->get(); } - ~CB_Linger_Reconnect() { + ~C_Linger_Reconnect() override { info->put(); } - void operator()(boost::system::error_code ec) { - objecter->_linger_reconnect(info, ec); + void finish(int r) override { + objecter->_linger_reconnect(info, r); } }; - struct CB_Linger_Ping { + struct C_Linger_Ping : public Context { Objecter *objecter; LingerOp *info; ceph::coarse_mono_time sent; uint32_t register_gen; - CB_Linger_Ping(Objecter *o, LingerOp *l) + C_Linger_Ping(Objecter *o, LingerOp *l) : objecter(o), info(l), register_gen(info->register_gen) { info->get(); } - CB_Linger_Ping() { + ~C_Linger_Ping() override { info->put(); } - void operator()(boost::system::error_code ec) { - objecter->_linger_ping(info, ec, sent, register_gen); + void finish(int r) override { + objecter->_linger_ping(info, r, sent, register_gen); } }; - struct CB_Linger_Map_Latest { + struct C_Linger_Map_Latest : public Context { Objecter *objecter; uint64_t linger_id; - CB_Linger_Map_Latest(Objecter *o, uint64_t id) : objecter(o), linger_id(id) {} - void operator()(boost::system::error_code err, version_t latest, version_t); + version_t latest; + C_Linger_Map_Latest(Objecter *o, uint64_t id) : + objecter(o), linger_id(id), latest(0) {} + void finish(int r) override; }; // -- osd sessions -- @@ -2233,8 +1913,11 @@ public: }; struct OSDSession : public RefCountedObject { - ceph::shared_mutex lock = - ceph::make_shared_mutex("OSDSession::lock"); + std::shared_mutex lock; + using lock_guard = std::lock_guard<decltype(lock)>; + using unique_lock = std::unique_lock<decltype(lock)>; + using shared_lock = boost::shared_lock<decltype(lock)>; + using shunique_lock = ceph::shunique_lock<decltype(lock)>; // pending ops std::map<ceph_tid_t,Op*> ops; @@ -2250,6 +1933,9 @@ public: ConnectionRef con; int num_locks; std::unique_ptr<std::mutex[]> completion_locks; + using unique_completion_lock = std::unique_lock< + decltype(completion_locks)::element_type>; + OSDSession(CephContext *cct, int o) : osd(o), incarnation(0), con(NULL), @@ -2260,7 +1946,7 @@ public: bool is_homeless() { return (osd == -1); } - std::unique_lock<std::mutex> get_lock(object_t& oid); + unique_completion_lock get_lock(object_t& oid); }; std::map<int,OSDSession*> osd_sessions; @@ -2288,8 +1974,7 @@ public: std::map<ceph_tid_t,PoolOp*> pool_ops; std::atomic<unsigned> num_homeless_ops{0}; - OSDSession* homeless_session = new OSDSession(cct, -1); - + OSDSession *homeless_session; // ops waiting for an osdmap with a new pool or confirmation that // the pool does not exist (may be expanded to other uses later) @@ -2297,9 +1982,7 @@ public: std::map<ceph_tid_t, Op*> check_latest_map_ops; std::map<ceph_tid_t, CommandOp*> check_latest_map_commands; - std::map<epoch_t, - std::vector<std::pair<std::unique_ptr<OpCompletion>, - boost::system::error_code>>> waiting_for_map; + std::map<epoch_t,std::list< std::pair<Context*, int> > > waiting_for_map; ceph::timespan mon_timeout; ceph::timespan osd_timeout; @@ -2332,7 +2015,7 @@ public: int _calc_target(op_target_t *t, Connection *con, bool any_change = false); int _map_session(op_target_t *op, OSDSession **s, - ceph::shunique_lock<ceph::shared_mutex>& lc); + shunique_lock& lc); void _session_op_assign(OSDSession *s, Op *op); void _session_op_remove(OSDSession *s, Op *op); @@ -2341,35 +2024,28 @@ public: void _session_command_op_assign(OSDSession *to, CommandOp *op); void _session_command_op_remove(OSDSession *from, CommandOp *op); - int _assign_op_target_session(Op *op, ceph::shunique_lock<ceph::shared_mutex>& lc, + int _assign_op_target_session(Op *op, shunique_lock& lc, bool src_session_locked, bool dst_session_locked); - int _recalc_linger_op_target(LingerOp *op, - ceph::shunique_lock<ceph::shared_mutex>& lc); - - void _linger_submit(LingerOp *info, - ceph::shunique_lock<ceph::shared_mutex>& sul); - void _send_linger(LingerOp *info, - ceph::shunique_lock<ceph::shared_mutex>& sul); - void _linger_commit(LingerOp *info, boost::system::error_code ec, - ceph::buffer::list& outbl); - void _linger_reconnect(LingerOp *info, boost::system::error_code ec); + int _recalc_linger_op_target(LingerOp *op, shunique_lock& lc); + + void _linger_submit(LingerOp *info, shunique_lock& sul); + void _send_linger(LingerOp *info, shunique_lock& sul); + void _linger_commit(LingerOp *info, int r, ceph::buffer::list& outbl); + void _linger_reconnect(LingerOp *info, int r); void _send_linger_ping(LingerOp *info); - void _linger_ping(LingerOp *info, boost::system::error_code ec, - ceph::coarse_mono_time sent, uint32_t register_gen); - boost::system::error_code _normalize_watch_error(boost::system::error_code ec); + void _linger_ping(LingerOp *info, int r, ceph::coarse_mono_time sent, + uint32_t register_gen); + int _normalize_watch_error(int r); - friend class CB_DoWatchError; + friend class C_DoWatchError; public: - template<typename CT> - auto linger_callback_flush(CT&& ct) { - boost::asio::async_completion<CT, void(void)> init(ct); - boost::asio::defer(finish_strand, std::move(init.completion_handler)); - return init.result.get(); + void linger_callback_flush(Context *ctx) { + finisher->queue(ctx); } private: - void _check_op_pool_dne(Op *op, std::unique_lock<ceph::shared_mutex> *sl); + void _check_op_pool_dne(Op *op, unique_lock *sl); void _send_op_map_check(Op *op); void _op_cancel_map_check(Op *op); void _check_linger_pool_dne(LingerOp *op, bool *need_unregister); @@ -2380,11 +2056,9 @@ private: void _command_cancel_map_check(CommandOp *op); void _kick_requests(OSDSession *session, std::map<uint64_t, LingerOp *>& lresend); - void _linger_ops_resend(std::map<uint64_t, LingerOp *>& lresend, - std::unique_lock<ceph::shared_mutex>& ul); + void _linger_ops_resend(std::map<uint64_t, LingerOp *>& lresend, unique_lock& ul); - int _get_session(int osd, OSDSession **session, - ceph::shunique_lock<ceph::shared_mutex>& sul); + int _get_session(int osd, OSDSession **session, shunique_lock& sul); void put_session(OSDSession *s); void get_session(OSDSession *s); void _reopen_session(OSDSession *session); @@ -2401,10 +2075,9 @@ private: * and returned whenever an op is removed from the std::map * If throttle_op needs to throttle it will unlock client_lock. */ - int calc_op_budget(const boost::container::small_vector_base<OSDOp>& ops); - void _throttle_op(Op *op, ceph::shunique_lock<ceph::shared_mutex>& sul, - int op_size = 0); - int _take_op_budget(Op *op, ceph::shunique_lock<ceph::shared_mutex>& sul) { + int calc_op_budget(const std::vector<OSDOp>& ops); + void _throttle_op(Op *op, shunique_lock& sul, int op_size = 0); + int _take_op_budget(Op *op, shunique_lock& sul) { ceph_assert(sul && sul.mutex() == &rwlock); int op_budget = calc_op_budget(op->ops); if (keep_balanced_budget) { @@ -2417,21 +2090,18 @@ private: return op_budget; } int take_linger_budget(LingerOp *info); + friend class WatchContext; // to invoke put_up_budget_bytes void put_op_budget_bytes(int op_budget) { ceph_assert(op_budget >= 0); op_throttle_bytes.put(op_budget); op_throttle_ops.put(1); } void put_nlist_context_budget(NListContext *list_context); - Throttle op_throttle_bytes{cct, "objecter_bytes", - static_cast<int64_t>( - cct->_conf->objecter_inflight_op_bytes)}; - Throttle op_throttle_ops{cct, "objecter_ops", - static_cast<int64_t>( - cct->_conf->objecter_inflight_ops)}; + Throttle op_throttle_bytes, op_throttle_ops; + public: - Objecter(CephContext *cct, Messenger *m, MonClient *mc, - boost::asio::io_context& service, + Objecter(CephContext *cct_, Messenger *m, MonClient *mc, + Finisher *fin, double mon_timeout, double osd_timeout); ~Objecter() override; @@ -2483,7 +2153,7 @@ private: std::map<ceph_tid_t, Op*>& need_resend, std::list<LingerOp*>& need_resend_linger, std::map<ceph_tid_t, CommandOp*>& need_resend_command, - ceph::shunique_lock<ceph::shared_mutex>& sul); + shunique_lock& sul); int64_t get_object_hash_position(int64_t pool, const std::string& key, const std::string& ns); @@ -2517,27 +2187,6 @@ private: void handle_osd_map(class MOSDMap *m); void wait_for_osd_map(); - template<typename CompletionToken> - auto wait_for_osd_map(CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, void()> init(token); - unique_lock l(rwlock); - if (osdmap->get_epoch()) { - l.unlock(); - boost::asio::dispatch(std::move(init.completion_handler)); - } else { - waiting_for_map[0].emplace_back( - OpCompletion::create( - service.get_executor(), - [c = std::move(init.completion_handler)] - (boost::system::error_code) mutable { - std::move(c)(); - }), boost::system::error_code{}); - l.unlock(); - } - return init.result.get(); - } - - /** * Get std::list of entities blacklisted since this was last called, * and reset the std::list. @@ -2562,17 +2211,15 @@ private: const OSDMap &new_osd_map); // low-level - void _op_submit(Op *op, ceph::shunique_lock<ceph::shared_mutex>& lc, - ceph_tid_t *ptid); - void _op_submit_with_budget(Op *op, - ceph::shunique_lock<ceph::shared_mutex>& lc, + void _op_submit(Op *op, shunique_lock& lc, ceph_tid_t *ptid); + void _op_submit_with_budget(Op *op, shunique_lock& lc, ceph_tid_t *ptid, int *ctx_budget = NULL); // public interface public: void op_submit(Op *op, ceph_tid_t *ptid = NULL, int *ctx_budget = NULL); bool is_active() { - std::shared_lock l(rwlock); + shared_lock l(rwlock); return !((!inflight_ops) && linger_ops.empty() && poolstat_ops.empty() && statfs_ops.empty()); } @@ -2598,87 +2245,11 @@ public: void set_client_incarnation(int inc) { client_inc = inc; } bool have_map(epoch_t epoch); - - struct CB_Objecter_GetVersion { - Objecter *objecter; - std::unique_ptr<OpCompletion> fin; - - CB_Objecter_GetVersion(Objecter *o, std::unique_ptr<OpCompletion> c) - : objecter(o), fin(std::move(c)) {} - void operator()(boost::system::error_code ec, version_t newest, - version_t oldest) { - if (ec == boost::system::errc::resource_unavailable_try_again) { - // try again as instructed - objecter->wait_for_latest_osdmap(std::move(fin)); - } else if (ec) { - ceph::async::post(std::move(fin), ec); - } else { - auto l = std::unique_lock(objecter->rwlock); - objecter->_get_latest_version(oldest, newest, std::move(fin), - std::move(l)); - } - } - }; - - template<typename CompletionToken> - typename boost::asio::async_result<CompletionToken, OpSignature>::return_type - wait_for_map(epoch_t epoch, CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, OpSignature> init(token); - - if (osdmap->get_epoch() >= epoch) { - boost::asio::post(service, - ceph::async::bind_handler( - std::move(init.completion_handler), - boost::system::error_code())); - } else { - monc->get_version("osdmap", - CB_Objecter_GetVersion( - this, - OpCompletion::create(service.get_executor(), - std::move(init.completion_handler)))); - } - return init.result.get(); - } - - void _wait_for_new_map(std::unique_ptr<OpCompletion>, epoch_t epoch, - boost::system::error_code = {}); - - template<typename CompletionToken> - typename boost::asio::async_result<CompletionToken, OpSignature>::return_type - wait_for_latest_osdmap(CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, OpSignature> init(token); - - monc->get_version("osdmap", - CB_Objecter_GetVersion( - this, - OpCompletion::create(service.get_executor(), - std::move(init.completion_handler)))); - return init.result.get(); - } - - void wait_for_latest_osdmap(std::unique_ptr<OpCompletion> c) { - monc->get_version("osdmap", - CB_Objecter_GetVersion(this, std::move(c))); - } - - template<typename CompletionToken> - auto get_latest_version(epoch_t oldest, epoch_t newest, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, OpSignature> init(token); - { - std::unique_lock wl(rwlock); - _get_latest_version(oldest, newest, - OpCompletion::create( - service.get_executor(), - std::move(init.completion_handler)), - std::move(wl)); - } - return init.result.get(); - } - - void _get_latest_version(epoch_t oldest, epoch_t neweset, - std::unique_ptr<OpCompletion> fin, - std::unique_lock<ceph::shared_mutex>&& ul); + /// wait for epoch; true if we already have it + bool wait_for_map(epoch_t epoch, Context *c, int err=0); + void _wait_for_new_map(Context *c, epoch_t epoch, int err=0); + void wait_for_latest_osdmap(Context *fin); + void get_latest_version(epoch_t oldest, epoch_t neweset, Context *fin); /** Get the current set of global op flags */ int get_global_op_flags() const { return global_op_flags; } @@ -2710,52 +2281,32 @@ public: epoch_t op_cancel_writes(int r, int64_t pool=-1); // commands - void osd_command(int osd, std::vector<std::string> cmd, - ceph::buffer::list inbl, ceph_tid_t *ptid, - decltype(CommandOp::onfinish)&& onfinish) { + void osd_command(int osd, const std::vector<std::string>& cmd, + const ceph::buffer::list& inbl, ceph_tid_t *ptid, + ceph::buffer::list *poutbl, std::string *prs, Context *onfinish) { ceph_assert(osd >= 0); - auto c = new CommandOp( + CommandOp *c = new CommandOp( osd, - std::move(cmd), - std::move(inbl), - std::move(onfinish)); + cmd, + inbl, + poutbl, + prs, + onfinish); submit_command(c, ptid); } - template<typename CompletionToken> - auto osd_command(int osd, std::vector<std::string> cmd, - ceph::buffer::list inbl, ceph_tid_t *ptid, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, - CommandOp::OpSig> init(token); - osd_command(osd, std::move(cmd), std::move(inbl), ptid, - CommandOp::OpComp::create(service.get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - - void pg_command(pg_t pgid, std::vector<std::string> cmd, - ceph::buffer::list inbl, ceph_tid_t *ptid, - decltype(CommandOp::onfinish)&& onfinish) { - auto *c = new CommandOp( + void pg_command(pg_t pgid, const std::vector<std::string>& cmd, + const ceph::buffer::list& inbl, ceph_tid_t *ptid, + ceph::buffer::list *poutbl, std::string *prs, Context *onfinish) { + CommandOp *c = new CommandOp( pgid, - std::move(cmd), - std::move(inbl), - std::move(onfinish)); + cmd, + inbl, + poutbl, + prs, + onfinish); submit_command(c, ptid); } - template<typename CompletionToken> - auto pg_command(pg_t pgid, std::vector<std::string> cmd, - ceph::buffer::list inbl, ceph_tid_t *ptid, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, - CommandOp::OpSig> init(token); - pg_command(pgid, std::move(cmd), std::move(inbl), ptid, - CommandOp::OpComp::create(service.get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } - // mid-level helpers Op *prepare_mutate_op( const object_t& oid, const object_locator_t& oloc, @@ -2764,18 +2315,15 @@ public: Context *oncommit, version_t *objver = NULL, osd_reqid_t reqid = osd_reqid_t(), ZTracer::Trace *parent_trace = nullptr) { - Op *o = new Op(oid, oloc, std::move(op.ops), flags | global_op_flags | - CEPH_OSD_FLAG_WRITE, oncommit, objver, - nullptr, parent_trace); + Op *o = new Op(oid, oloc, op.ops, flags | global_op_flags | + CEPH_OSD_FLAG_WRITE, oncommit, objver, nullptr, parent_trace); o->priority = op.priority; o->mtime = mtime; o->snapc = snapc; o->out_rval.swap(op.out_rval); o->out_bl.swap(op.out_bl); o->out_handler.swap(op.out_handler); - o->out_ec.swap(op.out_ec); o->reqid = reqid; - op.clear(); return o; } ceph_tid_t mutate( @@ -2790,27 +2338,6 @@ public: op_submit(o, &tid); return tid; } - - void mutate(const object_t& oid, const object_locator_t& oloc, - ObjectOperation&& op, const SnapContext& snapc, - ceph::real_time mtime, int flags, - std::unique_ptr<Op::OpComp>&& oncommit, - version_t *objver = NULL, osd_reqid_t reqid = osd_reqid_t()) { - Op *o = new Op(oid, oloc, std::move(op.ops), flags | global_op_flags | - CEPH_OSD_FLAG_WRITE, std::move(oncommit), objver, - nullptr); - o->priority = op.priority; - o->mtime = mtime; - o->snapc = snapc; - o->out_bl.swap(op.out_bl); - o->out_handler.swap(op.out_handler); - o->out_rval.swap(op.out_rval); - o->out_ec.swap(op.out_ec); - o->reqid = reqid; - op.clear(); - op_submit(o); - } - Op *prepare_read_op( const object_t& oid, const object_locator_t& oloc, ObjectOperation& op, @@ -2819,19 +2346,16 @@ public: int *data_offset = NULL, uint64_t features = 0, ZTracer::Trace *parent_trace = nullptr) { - Op *o = new Op(oid, oloc, std::move(op.ops), flags | global_op_flags | - CEPH_OSD_FLAG_READ, onack, objver, - data_offset, parent_trace); + Op *o = new Op(oid, oloc, op.ops, flags | global_op_flags | + CEPH_OSD_FLAG_READ, onack, objver, data_offset, parent_trace); o->priority = op.priority; o->snapid = snapid; o->outbl = pbl; - if (!o->outbl && op.size() == 1 && op.out_bl[0] && op.out_bl[0]->length()) + if (!o->outbl && op.size() == 1 && op.out_bl[0]->length()) o->outbl = op.out_bl[0]; o->out_bl.swap(op.out_bl); o->out_handler.swap(op.out_handler); o->out_rval.swap(op.out_rval); - o->out_ec.swap(op.out_ec); - op.clear(); return o; } ceph_tid_t read( @@ -2849,40 +2373,13 @@ public: op_submit(o, &tid); return tid; } - - void read(const object_t& oid, const object_locator_t& oloc, - ObjectOperation&& op, snapid_t snapid, ceph::buffer::list *pbl, - int flags, std::unique_ptr<Op::OpComp>&& onack, - version_t *objver = nullptr, int *data_offset = nullptr, - uint64_t features = 0) { - Op *o = new Op(oid, oloc, std::move(op.ops), flags | global_op_flags | - CEPH_OSD_FLAG_READ, std::move(onack), objver, - data_offset); - o->priority = op.priority; - o->snapid = snapid; - o->outbl = pbl; - // XXX - if (!o->outbl && op.size() == 1 && op.out_bl[0] && op.out_bl[0]->length()) { - o->outbl = op.out_bl[0]; - } - o->out_bl.swap(op.out_bl); - o->out_handler.swap(op.out_handler); - o->out_rval.swap(op.out_rval); - o->out_ec.swap(op.out_ec); - if (features) - o->features = features; - op.clear(); - op_submit(o); - } - - Op *prepare_pg_read_op( uint32_t hash, object_locator_t oloc, ObjectOperation& op, ceph::buffer::list *pbl, int flags, Context *onack, epoch_t *reply_epoch, int *ctx_budget) { Op *o = new Op(object_t(), oloc, - std::move(op.ops), + op.ops, flags | global_op_flags | CEPH_OSD_FLAG_READ | CEPH_OSD_FLAG_IGNORE_OVERLAY, onack, NULL); @@ -2894,13 +2391,11 @@ public: o->out_bl.swap(op.out_bl); o->out_handler.swap(op.out_handler); o->out_rval.swap(op.out_rval); - o->out_ec.swap(op.out_ec); o->reply_epoch = reply_epoch; if (ctx_budget) { // budget is tracked by listing context o->ctx_budgeted = true; } - op.clear(); return o; } ceph_tid_t pg_read( @@ -2915,35 +2410,6 @@ public: return tid; } - ceph_tid_t pg_read( - uint32_t hash, object_locator_t oloc, - ObjectOperation& op, ceph::buffer::list *pbl, int flags, - std::unique_ptr<Op::OpComp>&& onack, epoch_t *reply_epoch, int *ctx_budget) { - ceph_tid_t tid; - Op *o = new Op(object_t(), oloc, - std::move(op.ops), - flags | global_op_flags | CEPH_OSD_FLAG_READ | - CEPH_OSD_FLAG_IGNORE_OVERLAY, - std::move(onack), nullptr); - o->target.precalc_pgid = true; - o->target.base_pgid = pg_t(hash, oloc.pool); - o->priority = op.priority; - o->snapid = CEPH_NOSNAP; - o->outbl = pbl; - o->out_bl.swap(op.out_bl); - o->out_handler.swap(op.out_handler); - o->out_rval.swap(op.out_rval); - o->out_ec.swap(op.out_ec); - o->reply_epoch = reply_epoch; - if (ctx_budget) { - // budget is tracked by listing context - o->ctx_budgeted = true; - } - op_submit(o, &tid, ctx_budget); - op.clear(); - return tid; - } - // caller owns a ref LingerOp *linger_register(const object_t& oid, const object_locator_t& oloc, int flags); @@ -2951,34 +2417,15 @@ public: ObjectOperation& op, const SnapContext& snapc, ceph::real_time mtime, ceph::buffer::list& inbl, - decltype(info->on_reg_commit)&& oncommit, + Context *onfinish, version_t *objver); - ceph_tid_t linger_watch(LingerOp *info, - ObjectOperation& op, - const SnapContext& snapc, ceph::real_time mtime, - ceph::buffer::list& inbl, - Context* onfinish, - version_t *objver) { - return linger_watch(info, op, snapc, mtime, inbl, - OpContextVert<ceph::buffer::list>(onfinish, nullptr), objver); - } - ceph_tid_t linger_notify(LingerOp *info, - ObjectOperation& op, - snapid_t snap, ceph::buffer::list& inbl, - decltype(LingerOp::on_reg_commit)&& onfinish, - version_t *objver); ceph_tid_t linger_notify(LingerOp *info, ObjectOperation& op, snapid_t snap, ceph::buffer::list& inbl, ceph::buffer::list *poutbl, - Context* onack, - version_t *objver) { - return linger_notify(info, op, snap, inbl, - OpContextVert(onack, poutbl), - objver); - } - tl::expected<ceph::timespan, - boost::system::error_code> linger_check(LingerOp *info); + Context *onack, + version_t *objver); + int linger_check(LingerOp *info); void linger_cancel(LingerOp *info); // releases a reference void _linger_cancel(LingerOp *info); @@ -2994,8 +2441,7 @@ public: * @param extra_ops pointer to [array of] initial op[s] * @return index of final op (for caller to fill in) */ - int init_ops(boost::container::small_vector_base<OSDOp>& ops, int ops_count, - ObjectOperation *extra_ops) { + int init_ops(std::vector<OSDOp>& ops, int ops_count, ObjectOperation *extra_ops) { int i; int extra = 0; @@ -3018,11 +2464,11 @@ public: snapid_t snap, uint64_t *psize, ceph::real_time *pmtime, int flags, Context *onfinish, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { - osdc_opvec ops; + std::vector<OSDOp> ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_STAT; C_Stat *fin = new C_Stat(psize, pmtime, onfinish); - Op *o = new Op(oid, oloc, std::move(ops), flags | global_op_flags | + Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_READ, fin, objver); o->snapid = snap; o->outbl = &fin->bl; @@ -3046,7 +2492,7 @@ public: int flags, Context *onfinish, version_t *objver = NULL, ObjectOperation *extra_ops = NULL, int op_flags = 0, ZTracer::Trace *parent_trace = nullptr) { - osdc_opvec ops; + std::vector<OSDOp> ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_READ; ops[i].op.extent.offset = off; @@ -3054,9 +2500,8 @@ public: ops[i].op.extent.truncate_size = 0; ops[i].op.extent.truncate_seq = 0; ops[i].op.flags = op_flags; - Op *o = new Op(oid, oloc, std::move(ops), flags | global_op_flags | - CEPH_OSD_FLAG_READ, onfinish, objver, - nullptr, parent_trace); + Op *o = new Op(oid, oloc, ops, flags | global_op_flags | + CEPH_OSD_FLAG_READ, onfinish, objver, nullptr, parent_trace); o->snapid = snap; o->outbl = pbl; return o; @@ -3078,7 +2523,7 @@ public: uint64_t off, ceph::buffer::list &cmp_bl, snapid_t snap, int flags, Context *onfinish, version_t *objver = NULL, ObjectOperation *extra_ops = NULL, int op_flags = 0) { - osdc_opvec ops; + std::vector<OSDOp> ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_CMPEXT; ops[i].op.extent.offset = off; @@ -3087,7 +2532,7 @@ public: ops[i].op.extent.truncate_seq = 0; ops[i].indata = cmp_bl; ops[i].op.flags = op_flags; - Op *o = new Op(oid, oloc, std::move(ops), flags | global_op_flags | + Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_READ, onfinish, objver); o->snapid = snap; return o; @@ -3111,7 +2556,7 @@ public: __u32 trunc_seq, Context *onfinish, version_t *objver = NULL, ObjectOperation *extra_ops = NULL, int op_flags = 0) { - osdc_opvec ops; + std::vector<OSDOp> ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_READ; ops[i].op.extent.offset = off; @@ -3119,7 +2564,7 @@ public: ops[i].op.extent.truncate_size = trunc_size; ops[i].op.extent.truncate_seq = trunc_seq; ops[i].op.flags = op_flags; - Op *o = new Op(oid, oloc, std::move(ops), flags | global_op_flags | + Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_READ, onfinish, objver); o->snapid = snap; o->outbl = pbl; @@ -3131,14 +2576,14 @@ public: uint64_t off, uint64_t len, snapid_t snap, ceph::buffer::list *pbl, int flags, Context *onfinish, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { - osdc_opvec ops; + std::vector<OSDOp> ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_MAPEXT; ops[i].op.extent.offset = off; ops[i].op.extent.length = len; ops[i].op.extent.truncate_size = 0; ops[i].op.extent.truncate_seq = 0; - Op *o = new Op(oid, oloc, std::move(ops), flags | global_op_flags | + Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_READ, onfinish, objver); o->snapid = snap; o->outbl = pbl; @@ -3150,14 +2595,14 @@ public: const char *name, snapid_t snap, ceph::buffer::list *pbl, int flags, Context *onfinish, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { - osdc_opvec ops; + std::vector<OSDOp> ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_GETXATTR; ops[i].op.xattr.name_len = (name ? strlen(name) : 0); ops[i].op.xattr.value_len = 0; if (name) ops[i].indata.append(name, ops[i].op.xattr.name_len); - Op *o = new Op(oid, oloc, std::move(ops), flags | global_op_flags | + Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_READ, onfinish, objver); o->snapid = snap; o->outbl = pbl; @@ -3170,11 +2615,11 @@ public: snapid_t snap, std::map<std::string,ceph::buffer::list>& attrset, int flags, Context *onfinish, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { - osdc_opvec ops; + std::vector<OSDOp> ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_GETXATTRS; C_GetAttrs *fin = new C_GetAttrs(attrset, onfinish); - Op *o = new Op(oid, oloc, std::move(ops), flags | global_op_flags | + Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_READ, fin, objver); o->snapid = snap; o->outbl = &fin->bl; @@ -3194,12 +2639,11 @@ public: // writes ceph_tid_t _modify(const object_t& oid, const object_locator_t& oloc, - osdc_opvec& ops, - ceph::real_time mtime, + std::vector<OSDOp>& ops, ceph::real_time mtime, const SnapContext& snapc, int flags, Context *oncommit, version_t *objver = NULL) { - Op *o = new Op(oid, oloc, std::move(ops), flags | global_op_flags | + Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, oncommit, objver); o->mtime = mtime; o->snapc = snapc; @@ -3214,7 +2658,7 @@ public: Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL, int op_flags = 0, ZTracer::Trace *parent_trace = nullptr) { - osdc_opvec ops; + std::vector<OSDOp> ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_WRITE; ops[i].op.extent.offset = off; @@ -3223,8 +2667,8 @@ public: ops[i].op.extent.truncate_seq = 0; ops[i].indata = bl; ops[i].op.flags = op_flags; - Op *o = new Op(oid, oloc, std::move(ops), flags | global_op_flags | - CEPH_OSD_FLAG_WRITE, std::move(oncommit), objver, + Op *o = new Op(oid, oloc, ops, flags | global_op_flags | + CEPH_OSD_FLAG_WRITE, oncommit, objver, nullptr, parent_trace); o->mtime = mtime; o->snapc = snapc; @@ -3249,7 +2693,7 @@ public: Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { - osdc_opvec ops; + std::vector<OSDOp> ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_APPEND; ops[i].op.extent.offset = 0; @@ -3257,7 +2701,7 @@ public: ops[i].op.extent.truncate_size = 0; ops[i].op.extent.truncate_seq = 0; ops[i].indata = bl; - Op *o = new Op(oid, oloc, std::move(ops), flags | global_op_flags | + Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, oncommit, objver); o->mtime = mtime; o->snapc = snapc; @@ -3283,7 +2727,7 @@ public: Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL, int op_flags = 0) { - osdc_opvec ops; + std::vector<OSDOp> ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_WRITE; ops[i].op.extent.offset = off; @@ -3292,7 +2736,7 @@ public: ops[i].op.extent.truncate_seq = trunc_seq; ops[i].indata = bl; ops[i].op.flags = op_flags; - Op *o = new Op(oid, oloc, std::move(ops), flags | global_op_flags | + Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, oncommit, objver); o->mtime = mtime; o->snapc = snapc; @@ -3306,14 +2750,14 @@ public: ceph::real_time mtime, int flags, Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL, int op_flags = 0) { - osdc_opvec ops; + std::vector<OSDOp> ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_WRITEFULL; ops[i].op.extent.offset = 0; ops[i].op.extent.length = bl.length(); ops[i].indata = bl; ops[i].op.flags = op_flags; - Op *o = new Op(oid, oloc, std::move(ops), flags | global_op_flags | + Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, oncommit, objver); o->mtime = mtime; o->snapc = snapc; @@ -3339,7 +2783,7 @@ public: Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL, int op_flags = 0) { - osdc_opvec ops; + std::vector<OSDOp> ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_WRITESAME; ops[i].op.writesame.offset = off; @@ -3347,7 +2791,7 @@ public: ops[i].op.writesame.data_length = bl.length(); ops[i].indata = bl; ops[i].op.flags = op_flags; - Op *o = new Op(oid, oloc, std::move(ops), flags | global_op_flags | + Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, oncommit, objver); o->mtime = mtime; o->snapc = snapc; @@ -3374,13 +2818,13 @@ public: uint64_t trunc_size, __u32 trunc_seq, Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { - osdc_opvec ops; + std::vector<OSDOp> ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_TRUNCATE; ops[i].op.extent.offset = trunc_size; ops[i].op.extent.truncate_size = trunc_size; ops[i].op.extent.truncate_seq = trunc_seq; - Op *o = new Op(oid, oloc, std::move(ops), flags | global_op_flags | + Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, oncommit, objver); o->mtime = mtime; o->snapc = snapc; @@ -3392,12 +2836,12 @@ public: uint64_t off, uint64_t len, const SnapContext& snapc, ceph::real_time mtime, int flags, Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { - osdc_opvec ops; + std::vector<OSDOp> ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_ZERO; ops[i].op.extent.offset = off; ops[i].op.extent.length = len; - Op *o = new Op(oid, oloc, std::move(ops), flags | global_op_flags | + Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, oncommit, objver); o->mtime = mtime; o->snapc = snapc; @@ -3410,11 +2854,11 @@ public: ceph::real_time mtime, Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { - osdc_opvec ops; + std::vector<OSDOp> ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_ROLLBACK; ops[i].op.snap.snapid = snapid; - Op *o = new Op(oid, oloc, std::move(ops), CEPH_OSD_FLAG_WRITE, oncommit, objver); + Op *o = new Op(oid, oloc, ops, CEPH_OSD_FLAG_WRITE, oncommit, objver); o->mtime = mtime; o->snapc = snapc; ceph_tid_t tid; @@ -3426,11 +2870,11 @@ public: int create_flags, Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { - osdc_opvec ops; + std::vector<OSDOp> ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_CREATE; ops[i].op.flags = create_flags; - Op *o = new Op(oid, oloc, std::move(ops), global_flags | global_op_flags | + Op *o = new Op(oid, oloc, ops, global_flags | global_op_flags | CEPH_OSD_FLAG_WRITE, oncommit, objver); o->mtime = mtime; o->snapc = snapc; @@ -3443,10 +2887,10 @@ public: const SnapContext& snapc, ceph::real_time mtime, int flags, Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { - osdc_opvec ops; + std::vector<OSDOp> ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_DELETE; - Op *o = new Op(oid, oloc, std::move(ops), flags | global_op_flags | + Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, oncommit, objver); o->mtime = mtime; o->snapc = snapc; @@ -3469,7 +2913,7 @@ public: ceph::real_time mtime, int flags, Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { - osdc_opvec ops; + std::vector<OSDOp> ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_SETXATTR; ops[i].op.xattr.name_len = (name ? strlen(name) : 0); @@ -3477,9 +2921,8 @@ public: if (name) ops[i].indata.append(name, ops[i].op.xattr.name_len); ops[i].indata.append(bl); - Op *o = new Op(oid, oloc, std::move(ops), flags | global_op_flags | - CEPH_OSD_FLAG_WRITE, oncommit, - objver); + Op *o = new Op(oid, oloc, ops, flags | global_op_flags | + CEPH_OSD_FLAG_WRITE, oncommit, objver); o->mtime = mtime; o->snapc = snapc; ceph_tid_t tid; @@ -3491,14 +2934,14 @@ public: ceph::real_time mtime, int flags, Context *oncommit, version_t *objver = NULL, ObjectOperation *extra_ops = NULL) { - osdc_opvec ops; + std::vector<OSDOp> ops; int i = init_ops(ops, 1, extra_ops); ops[i].op.op = CEPH_OSD_OP_RMXATTR; ops[i].op.xattr.name_len = (name ? strlen(name) : 0); ops[i].op.xattr.value_len = 0; if (name) ops[i].indata.append(name, ops[i].op.xattr.name_len); - Op *o = new Op(oid, oloc, std::move(ops), flags | global_op_flags | + Op *o = new Op(oid, oloc, ops, flags | global_op_flags | CEPH_OSD_FLAG_WRITE, oncommit, objver); o->mtime = mtime; o->snapc = snapc; @@ -3514,25 +2957,29 @@ public: hobject_t enumerate_objects_begin(); hobject_t enumerate_objects_end(); - - friend EnumerationContext; - friend struct CB_EnumerateReply; + //hobject_t enumerate_objects_begin(int n, int m); void enumerate_objects( int64_t pool_id, - std::string_view ns, - hobject_t start, - hobject_t end, + const std::string &ns, + const hobject_t &start, + const hobject_t &end, const uint32_t max, - const ceph::buffer::list& filter_bl, - fu2::unique_function<void(boost::system::error_code, - std::vector<librados::ListObjectImpl>, - hobject_t) &&> on_finish); - void _issue_enumerate(hobject_t start, - std::unique_ptr<EnumerationContext>); + const ceph::buffer::list &filter_bl, + std::list<librados::ListObjectImpl> *result, + hobject_t *next, + Context *on_finish); + void _enumerate_reply( - ceph::buffer::list&& bl, - boost::system::error_code ec, - std::unique_ptr<EnumerationContext>&& ectx); + ceph::buffer::list &bl, + int r, + const hobject_t &end, + const int64_t pool_id, + int budget, + epoch_t reply_epoch, + std::list<librados::ListObjectImpl> *result, + hobject_t *next, + Context *on_finish); + friend class C_EnumerateReply; // ------------------------- // pool ops @@ -3540,66 +2987,18 @@ private: void pool_op_submit(PoolOp *op); void _pool_op_submit(PoolOp *op); void _finish_pool_op(PoolOp *op, int r); - void _do_delete_pool(int64_t pool, - decltype(PoolOp::onfinish)&& onfinish); - + void _do_delete_pool(int64_t pool, Context *onfinish); public: - void create_pool_snap(int64_t pool, std::string_view snapName, - decltype(PoolOp::onfinish)&& onfinish); - void create_pool_snap(int64_t pool, std::string_view snapName, - Context* c) { - create_pool_snap(pool, snapName, - OpContextVert<ceph::buffer::list>(c, nullptr)); - } - void allocate_selfmanaged_snap(int64_t pool, - std::unique_ptr<ceph::async::Completion< - void(boost::system::error_code, - snapid_t)>> onfinish); - void allocate_selfmanaged_snap(int64_t pool, snapid_t* psnapid, - Context* c) { - allocate_selfmanaged_snap(pool, - OpContextVert(c, psnapid)); - } - void delete_pool_snap(int64_t pool, std::string_view snapName, - decltype(PoolOp::onfinish)&& onfinish); - void delete_pool_snap(int64_t pool, std::string_view snapName, - Context* c) { - delete_pool_snap(pool, snapName, - OpContextVert<ceph::buffer::list>(c, nullptr)); - } - - void delete_selfmanaged_snap(int64_t pool, snapid_t snap, - decltype(PoolOp::onfinish)&& onfinish); - void delete_selfmanaged_snap(int64_t pool, snapid_t snap, - Context* c) { - delete_selfmanaged_snap(pool, snap, - OpContextVert<ceph::buffer::list>(c, nullptr)); - } - - - void create_pool(std::string_view name, - decltype(PoolOp::onfinish)&& onfinish, - int crush_rule=-1); - void create_pool(std::string_view name, Context *onfinish, - int crush_rule=-1) { - create_pool(name, - OpContextVert<ceph::buffer::list>(onfinish, nullptr), - crush_rule); - } - void delete_pool(int64_t pool, - decltype(PoolOp::onfinish)&& onfinish); - void delete_pool(int64_t pool, - Context* onfinish) { - delete_pool(pool, OpContextVert<ceph::buffer::list>(onfinish, nullptr)); - } - - void delete_pool(std::string_view name, - decltype(PoolOp::onfinish)&& onfinish); - - void delete_pool(std::string_view name, - Context* onfinish) { - delete_pool(name, OpContextVert<ceph::buffer::list>(onfinish, nullptr)); - } + int create_pool_snap(int64_t pool, std::string& snapName, Context *onfinish); + int allocate_selfmanaged_snap(int64_t pool, snapid_t *psnapid, + Context *onfinish); + int delete_pool_snap(int64_t pool, std::string& snapName, Context *onfinish); + int delete_selfmanaged_snap(int64_t pool, snapid_t snap, Context *onfinish); + + int create_pool(std::string& name, Context *onfinish, + int crush_rule=-1); + int delete_pool(int64_t pool, Context *onfinish); + int delete_pool(const std::string& name, Context *onfinish); void handle_pool_op_reply(MPoolOpReply *m); int pool_op_cancel(ceph_tid_t tid, int r); @@ -3610,19 +3009,10 @@ private: void _poolstat_submit(PoolStatOp *op); public: void handle_get_pool_stats_reply(MGetPoolStatsReply *m); - void get_pool_stats(const std::vector<std::string>& pools, - decltype(PoolStatOp::onfinish)&& onfinish); - template<typename CompletionToken> - auto get_pool_stats(const std::vector<std::string>& pools, - CompletionToken&& token) { - boost::asio::async_completion<CompletionToken, - PoolStatOp::OpSig> init(token); - get_pool_stats(pools, - PoolStatOp::OpComp::create( - service.get_executor(), - std::move(init.completion_handler))); - return init.result.get(); - } + void get_pool_stats(std::list<std::string>& pools, + std::map<std::string,pool_stat_t> *result, + bool *per_pool, + Context *onfinish); int pool_stat_op_cancel(ceph_tid_t tid, int r); void _finish_pool_stat_op(PoolStatOp *op, int r); @@ -3632,12 +3022,8 @@ private: void _fs_stats_submit(StatfsOp *op); public: void handle_fs_stats_reply(MStatfsReply *m); - void get_fs_stats(boost::optional<int64_t> poolid, - decltype(StatfsOp::onfinish)&& onfinish); void get_fs_stats(struct ceph_statfs& result, boost::optional<int64_t> poolid, - Context *onfinish) { - get_fs_stats(poolid, OpContextVert(onfinish, result)); - } + Context *onfinish); int statfs_op_cancel(ceph_tid_t tid, int r); void _finish_statfs_op(StatfsOp *op, int r); @@ -3735,9 +3121,7 @@ public: private: epoch_t epoch_barrier = 0; - bool retry_writes_after_first_reply = - cct->_conf->objecter_retry_writes_after_first_reply; - + bool retry_writes_after_first_reply; public: void set_epoch_barrier(epoch_t epoch); diff --git a/src/osdc/error_code.cc b/src/osdc/error_code.cc deleted file mode 100644 index 8017f7a4ce5..00000000000 --- a/src/osdc/error_code.cc +++ /dev/null @@ -1,147 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2019 Red Hat <contact@redhat.com> - * Author: Adam C. Emerson <aemerson@redhat.com> - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#include <string> - -#include "common/error_code.h" -#include "error_code.h" - -namespace bs = boost::system; - -class osdc_error_category : public ceph::converting_category { -public: - osdc_error_category(){} - const char* name() const noexcept override; - std::string message(int ev) const override; - bs::error_condition default_error_condition(int ev) const noexcept - override; - bool equivalent(int ev, const bs::error_condition& c) const - noexcept override; - using ceph::converting_category::equivalent; - int from_code(int ev) const noexcept override; -}; - -const char* osdc_error_category::name() const noexcept { - return "osdc"; -} - -std::string osdc_error_category::message(int ev) const { - if (ev == 0) - return "No error"; - - switch (static_cast<osdc_errc>(ev)) { - case osdc_errc::pool_dne: - return "Pool does not exist"; - - case osdc_errc::pool_exists: - return "Pool already exists"; - - case osdc_errc::precondition_violated: - return "Precondition for operation not satisfied"; - - case osdc_errc::not_supported: - return "Operation not supported"; - - case osdc_errc::snapshot_exists: - return "Snapshot already exists"; - - case osdc_errc::snapshot_dne: - return "Snapshot does not exist"; - - case osdc_errc::timed_out: - return "Operation timed out"; - } - - return "Unknown error"; -} - -bs::error_condition -osdc_error_category::default_error_condition(int ev) const noexcept { - switch (static_cast<osdc_errc>(ev)) { - case osdc_errc::pool_dne: - return ceph::errc::does_not_exist; - case osdc_errc::pool_exists: - return ceph::errc::exists; - case osdc_errc::precondition_violated: - return bs::errc::invalid_argument; - case osdc_errc::not_supported: - return bs::errc::operation_not_supported; - case osdc_errc::snapshot_exists: - return ceph::errc::exists; - case osdc_errc::snapshot_dne: - return ceph::errc::does_not_exist; - case osdc_errc::timed_out: - return bs::errc::timed_out; - } - - return { ev, *this }; -} - -bool osdc_error_category::equivalent(int ev, - const bs::error_condition& c) const noexcept { - if (ev == osdc_errc::pool_dne) { - if (c == bs::errc::no_such_file_or_directory) { - return true; - } - if (c == ceph::errc::not_in_map) { - return true; - } - } - if (ev == osdc_errc::pool_exists) { - if (c == bs::errc::file_exists) { - return true; - } - } - if (ev == osdc_errc::snapshot_exists) { - if (c == bs::errc::file_exists) { - return true; - } - } - if (ev == osdc_errc::snapshot_dne) { - if (c == bs::errc::no_such_file_or_directory) { - return true; - } - if (c == ceph::errc::not_in_map) { - return true; - } - } - - return default_error_condition(ev) == c; -} - -int osdc_error_category::from_code(int ev) const noexcept { - switch (static_cast<osdc_errc>(ev)) { - case osdc_errc::pool_dne: - return -ENOENT; - case osdc_errc::pool_exists: - return -EEXIST; - case osdc_errc::precondition_violated: - return -EINVAL; - case osdc_errc::not_supported: - return -EOPNOTSUPP; - case osdc_errc::snapshot_exists: - return -EEXIST; - case osdc_errc::snapshot_dne: - return -ENOENT; - case osdc_errc::timed_out: - return -ETIMEDOUT; - } - return -EDOM; -} - -const bs::error_category& osdc_category() noexcept { - static const osdc_error_category c; - return c; -} diff --git a/src/osdc/error_code.h b/src/osdc/error_code.h deleted file mode 100644 index 224c9768879..00000000000 --- a/src/osdc/error_code.h +++ /dev/null @@ -1,53 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2019 Red Hat <contact@redhat.com> - * Author: Adam C. Emerson <aemerson@redhat.com> - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#pragma once - -#include <boost/system/error_code.hpp> - -#include "include/rados.h" - -const boost::system::error_category& osdc_category() noexcept; - -enum osdc_errc { - pool_dne = 1, - pool_exists, - // Come the revolution, we'll just kill your program. Maybe. - precondition_violated, - not_supported, - snapshot_exists, - snapshot_dne, - timed_out -}; - -namespace boost { -namespace system { -template<> -struct is_error_code_enum<::osdc_errc> { - static const bool value = true; -}; -} -} - -// explicit conversion: -inline boost::system::error_code make_error_code(osdc_errc e) noexcept { - return { e, osdc_category() }; -} - -// implicit conversion: -inline boost::system::error_condition make_error_condition(osdc_errc e) - noexcept { - return { e, osdc_category() }; -} diff --git a/src/rgw/rgw_bucket.cc b/src/rgw/rgw_bucket.cc index f702d8d5e12..1a3b6b1a4c5 100644 --- a/src/rgw/rgw_bucket.cc +++ b/src/rgw/rgw_bucket.cc @@ -3573,8 +3573,7 @@ int RGWBucketCtl::chown(rgw::sal::RGWRadosStore *store, RGWBucketInfo& bucket_in decode(policy, bl); owner = policy.get_owner(); } catch (buffer::error& err) { - ldout(store->ctx(), 0) << "ERROR: decode policy failed" << err.what() - << dendl; + ldout(store->ctx(), 0) << "ERROR: decode policy failed" << err << dendl; return -EIO; } diff --git a/src/rgw/rgw_common.h b/src/rgw/rgw_common.h index a45730867eb..cdc85016318 100644 --- a/src/rgw/rgw_common.h +++ b/src/rgw/rgw_common.h @@ -2299,7 +2299,7 @@ struct rgw_obj { } else { ssize_t pos = key.name.find('_', 1); if (pos < 0) { - throw buffer::malformed_input(); + throw buffer::error(); } key.name = key.name.substr(pos + 1); } diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 401a5151aac..c9bfe939939 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -32,7 +32,6 @@ add_subdirectory(fs) add_subdirectory(journal) add_subdirectory(libcephfs) add_subdirectory(librados) -add_subdirectory(RADOS) add_subdirectory(librados_test_stub) if(WITH_LIBRADOSSTRIPER) add_subdirectory(libradosstriper) diff --git a/src/test/RADOS/CMakeLists.txt b/src/test/RADOS/CMakeLists.txt deleted file mode 100644 index e95fbc47ec3..00000000000 --- a/src/test/RADOS/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -add_executable(ceph_test_RADOS_start_stop start_stop.cc) -target_link_libraries(ceph_test_RADOS_start_stop - global libRADOS ${unittest_libs}) - -add_executable(ceph_test_RADOS_completions completions.cc) -target_link_libraries(ceph_test_RADOS_completions Boost::system pthread - ${unittest_libs}) - -add_executable(ceph_test_RADOS_op_speed op_speed.cc) -target_link_libraries(ceph_test_RADOS_op_speed - global libRADOS fmt::fmt ${unittest_libs}) - -add_executable(ceph_test_RADOS_list_pool list_pool.cc) -target_link_libraries(ceph_test_RADOS_list_pool - global libRADOS fmt::fmt ${unittest_libs}) diff --git a/src/test/RADOS/completions.cc b/src/test/RADOS/completions.cc deleted file mode 100644 index d9c0e087005..00000000000 --- a/src/test/RADOS/completions.cc +++ /dev/null @@ -1,20 +0,0 @@ -#include <cassert> -#include <boost/asio.hpp> -#include <boost/system/system_error.hpp> - -constexpr int max_completions = 10'000'000; -int completed = 0; - -boost::asio::io_context c; - -void nested_cb() { - if (++completed < max_completions) - c.post(&nested_cb); -} - -int main(void) { - c.post(&nested_cb); - c.run(); - assert(completed == max_completions); - return 0; -} diff --git a/src/test/RADOS/list_pool.cc b/src/test/RADOS/list_pool.cc deleted file mode 100644 index 5d5cb3dfd4e..00000000000 --- a/src/test/RADOS/list_pool.cc +++ /dev/null @@ -1,192 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2019 Red Hat <contact@redhat.com> - * Author: Adam C. Emerson <aemerson@redhat.com> - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#include <iostream> -#include <initializer_list> -#include <optional> -#include <thread> -#include <tuple> -#include <string_view> -#include <vector> - -#include <sys/param.h> - -#include <unistd.h> - -#include <boost/system/system_error.hpp> - -#include <fmt/format.h> - -#include "include/RADOS/RADOS.hpp" - -#include "include/scope_guard.h" - -#include "common/async/context_pool.h" -#include "common/ceph_time.h" -#include "common/ceph_argparse.h" -#include "common/async/waiter.h" - -#include "global/global_init.h" - -std::string_view hostname() { - static char hostname[MAXHOSTNAMELEN] = { 0 }; - static size_t len = 0; - if (!len) { - auto r = gethostname(hostname, sizeof(hostname)); - if (r != 0) { - throw boost::system::system_error( - errno, boost::system::system_category()); - } - len = std::strlen(hostname); - } - return {hostname, len}; -} - -std::string temp_pool_name(const std::string_view prefix) -{ - using namespace std::chrono; - static std::uint64_t num = 1; - return fmt::format( - "{}-{}-{}-{}-{}", - prefix, - hostname(), - getpid(), - duration_cast<milliseconds>(ceph::coarse_real_clock::now() - .time_since_epoch()).count(), - num++); -} - -boost::system::error_code noisy_list(RADOS::RADOS& r, - int64_t p) { - ceph::async::waiter<boost::system::error_code> w; - RADOS::Cursor next; - std::vector<RADOS::Entry> v; - auto b = RADOS::Cursor::begin(); - auto e = RADOS::Cursor::end(); - - std::cout << "begin = " << b.to_str() << std::endl; - std::cout << "end = " << e.to_str() << std::endl; - r.enumerate_objects(p, b, e, 1000, {}, &v, &next, w, - RADOS::all_nspaces); - auto ec = w.wait(); - if (ec) { - std::cerr << "RADOS::enumerate_objects: " << ec << std::endl; - return ec; - } - - std::cout << "Got " << v.size() << " entries." << std::endl; - - std::cout << "next cursor = " << next.to_str() << std::endl; - std::cout << "next == end: " << (next == e) << std::endl; - std::cout << "Returned Objects: "; - std::cout << "["; - auto o = v.cbegin(); - while (o != v.cend()) { - std::cout << *o; - if (++o != v.cend()) - std::cout << " "; - } - std::cout << "]" << std::endl; - return {}; -} - -boost::system::error_code create_several(RADOS::RADOS& r, - const RADOS::IOContext& i, - std::initializer_list<std::string> l) { - for (const auto& o : l) { - ceph::async::waiter<boost::system::error_code> w; - RADOS::WriteOp op; - std::cout << "Creating " << o << std::endl; - ceph::bufferlist bl; - bl.append("My bologna has no name."); - op.write_full(std::move(bl)); - r.execute(o, i, std::move(op), w); - auto ec = w.wait(); - if (ec) { - std::cerr << "RADOS::execute: " << ec << std::endl; - return ec; - } - } - return {}; -} - -int main(int argc, char** argv) -{ - using namespace std::literals; - - std::vector<const char*> args; - argv_to_vec(argc, const_cast<const char**>(argv), args); - env_to_vec(args); - - auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, - CODE_ENVIRONMENT_UTILITY, 0); - common_init_finish(cct.get()); - - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - - auto pool_name = temp_pool_name("ceph_test_RADOS_list_pool"); - - { - ceph::async::waiter<boost::system::error_code> w; - r.create_pool(pool_name, std::nullopt, w); - auto ec = w.wait(); - if (ec) { - std::cerr << "RADOS::create_pool: " << ec << std::endl; - return 1; - } - } - - auto pd = make_scope_guard( - [&pool_name, &r]() { - ceph::async::waiter<boost::system::error_code> w; - r.delete_pool(pool_name, w); - auto ec = w.wait(); - if (ec) - std::cerr << "RADOS::delete_pool: " << ec << std::endl; - }); - - std::int64_t pool; - - { - ceph::async::waiter<boost::system::error_code, std::int64_t> w; - r.lookup_pool(pool_name, w); - boost::system::error_code ec; - std::tie(ec, pool) = w.wait(); - if (ec) { - std::cerr << "RADOS::lookup_pool: " << ec << std::endl; - return 1; - } - } - - RADOS::IOContext i(pool); - - if (noisy_list(r, pool)) { - return 1; - } - - if (create_several(r, i, {"meow", "woof", "squeak"})) { - return 1; - } - - std::this_thread::sleep_for(5s); - - if (noisy_list(r, pool)) { - return 1; - } - - return 0; -} diff --git a/src/test/RADOS/op_speed.cc b/src/test/RADOS/op_speed.cc deleted file mode 100644 index 715404bd359..00000000000 --- a/src/test/RADOS/op_speed.cc +++ /dev/null @@ -1,34 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2019 Red Hat <contact@redhat.com> - * Author: Adam C. Emerson <aemerson@redhat.com> - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#include "include/RADOS/RADOS.hpp" - -constexpr int to_create = 10'000'000; - -int main() { - for (int i = 0; i < to_create; ++i) { - RADOS::ReadOp op; - bufferlist bl; - std::uint64_t sz; - ceph::real_time tm; - boost::container::flat_map<std::string, ceph::buffer::list> xattrs; - boost::container::flat_map<std::string, ceph::buffer::list> omap; - bool trunc; - op.read(0, 0, &bl); - op.stat(&sz, &tm); - op.get_xattrs(&xattrs); - op.get_omap_vals(std::nullopt, std::nullopt, 1000, &omap, &trunc); - } -} diff --git a/src/test/RADOS/start_stop.cc b/src/test/RADOS/start_stop.cc deleted file mode 100644 index 42132ba1a20..00000000000 --- a/src/test/RADOS/start_stop.cc +++ /dev/null @@ -1,173 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2019 Red Hat <contact@redhat.com> - * Author: Adam C. Emerson <aemerson@redhat.com> - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#include <thread> -#include <vector> - -#include "include/RADOS/RADOS.hpp" - -#include "common/async/context_pool.h" -#include "common/ceph_argparse.h" - -#include "global/global_init.h" - - -int main(int argc, char** argv) -{ - using namespace std::literals; - - std::vector<const char*> args; - argv_to_vec(argc, const_cast<const char**>(argv), args); - env_to_vec(args); - - auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, - CODE_ENVIRONMENT_UTILITY, 0); - common_init_finish(cct.get()); - - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(30s); - } - std::this_thread::sleep_for(30s); - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(30s); - } - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(1s); - } - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(1s); - } - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(1s); - } - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(1s); - } - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(1s); - } - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(1s); - } - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(1s); - } - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(500ms); - } - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(500ms); - } - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(50ms); - } - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(50ms); - } - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(50ms); - } - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(5ms); - } - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(5ms); - } - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(5ms); - } - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(5ms); - } - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(5ms); - } - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(5us); - } - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(5us); - } - { - ceph::async::io_context_pool p(1); - auto r = RADOS::RADOS::make_with_cct(cct.get(), p, - boost::asio::use_future).get(); - std::this_thread::sleep_for(5us); - } - return 0; -} diff --git a/src/test/crimson/test_socket.cc b/src/test/crimson/test_socket.cc index 557a0cf6f06..ec306700bd7 100644 --- a/src/test/crimson/test_socket.cc +++ b/src/test/crimson/test_socket.cc @@ -32,7 +32,7 @@ class SocketFactoryBase public: virtual ~SocketFactoryBase() = default; - virtual seastar::future<> bind_accept() { + virtual future<> bind_accept() { return this->container().invoke_on_all([] (auto& factory) { entity_addr_t addr; addr.parse(server_addr, nullptr); @@ -77,7 +77,7 @@ class SocketFactoryBase }); } - seastar::future<> shutdown() { + future<> shutdown() { return this->container().invoke_on_all([] (auto& factory) { if (factory.listener) { factory.listener.value().abort_accept(); @@ -86,22 +86,22 @@ class SocketFactoryBase }); } - seastar::future<> stop() { return seastar::now(); } + future<> stop() { return seastar::now(); } - static seastar::future<SocketFRef> connect() { + static future<SocketFRef> connect() { entity_addr_t addr; addr.parse(server_addr, nullptr); return Socket::connect(addr); } protected: - virtual seastar::future<> handle_server_socket(SocketFRef&& socket) = 0; + virtual future<> handle_server_socket(SocketFRef&& socket) = 0; }; class AcceptTest final : public SocketFactoryBase<AcceptTest> { public: - seastar::future<> handle_server_socket(SocketFRef&& socket) override { + future<> handle_server_socket(SocketFRef&& socket) override { return seastar::sleep(100ms ).then([socket = std::move(socket)] () mutable { return socket->close() @@ -110,7 +110,7 @@ class AcceptTest final } }; -seastar::future<> test_refused() { +future<> test_refused() { logger.info("test_refused()..."); return AcceptTest::connect().discard_result( ).then([] { @@ -127,7 +127,7 @@ seastar::future<> test_refused() { }); } -seastar::future<> test_bind_same() { +future<> test_bind_same() { logger.info("test_bind_same()..."); return crimson::net::create_sharded<AcceptTest>().then( [] (AcceptTest* factory) { @@ -157,7 +157,7 @@ seastar::future<> test_bind_same() { }); } -seastar::future<> test_accept() { +future<> test_accept() { logger.info("test_accept()"); return crimson::net::create_sharded<AcceptTest>( ).then([] (AcceptTest* factory) { @@ -187,25 +187,25 @@ class SocketFactory final const seastar::shard_id target_shard; seastar::promise<SocketFRef> socket_promise; - seastar::future<> bind_accept() override { + future<> bind_accept() override { return SocketFactoryBase<SocketFactory>::bind_accept(); } - seastar::future<SocketFRef> get_accepted() { + future<SocketFRef> get_accepted() { return socket_promise.get_future(); } public: SocketFactory(seastar::shard_id shard) : target_shard{shard} {} - seastar::future<> handle_server_socket(SocketFRef&& socket) override { + future<> handle_server_socket(SocketFRef&& socket) override { return container().invoke_on(target_shard, [socket = std::move(socket)] (auto& factory) mutable { factory.socket_promise.set_value(std::move(socket)); }); } -static seastar::future<tuple<SocketFRef, SocketFRef>> get_sockets() { + static future<tuple<SocketFRef, SocketFRef>> get_sockets() { return crimson::net::create_sharded<SocketFactory>(seastar::engine().cpu_id() ).then([] (SocketFactory* factory) { return factory->bind_accept().then([factory] { @@ -241,7 +241,7 @@ class Connection { data[DATA_SIZE - 1] = DATA_TAIL; } - seastar::future<> dispatch_write(unsigned round = 0, bool force_shut = false) { + future<> dispatch_write(unsigned round = 0, bool force_shut = false) { return seastar::repeat([this, round, force_shut] { if (round != 0 && round <= write_count) { return seastar::futurize_apply([this, force_shut] { @@ -265,7 +265,7 @@ class Connection { }); } - seastar::future<> dispatch_write_unbounded() { + future<> dispatch_write_unbounded() { return dispatch_write( ).then([] { ceph_abort(); @@ -282,7 +282,7 @@ class Connection { }); } - seastar::future<> dispatch_read(unsigned round = 0, bool force_shut = false) { + future<> dispatch_read(unsigned round = 0, bool force_shut = false) { return seastar::repeat([this, round, force_shut] { if (round != 0 && round <= read_count) { return seastar::futurize_apply([this, force_shut] { @@ -318,7 +318,7 @@ class Connection { }); } - seastar::future<> dispatch_read_unbounded() { + future<> dispatch_read_unbounded() { return dispatch_read( ).then([] { ceph_abort(); @@ -339,12 +339,12 @@ class Connection { socket->shutdown(); } - seastar::future<> close() { + future<> close() { return socket->close(); } public: - static seastar::future<> dispatch_rw_bounded(SocketFRef&& socket, bool is_client, + static future<> dispatch_rw_bounded(SocketFRef&& socket, bool is_client, unsigned round, bool force_shut = false) { return seastar::smp::submit_to(is_client ? 0 : 1, [socket = std::move(socket), round, force_shut] () mutable { @@ -365,7 +365,7 @@ class Connection { }); } - static seastar::future<> dispatch_rw_unbounded(SocketFRef&& socket, bool is_client, + static future<> dispatch_rw_unbounded(SocketFRef&& socket, bool is_client, bool preemptive_shut = false) { return seastar::smp::submit_to(is_client ? 0 : 1, [socket = std::move(socket), preemptive_shut, is_client] () mutable { @@ -393,7 +393,7 @@ class Connection { } }; -seastar::future<> test_read_write() { +future<> test_read_write() { logger.info("test_read_write()..."); return SocketFactory::get_sockets().then([] (auto sockets) { auto [client_socket, server_socket] = std::move(sockets); @@ -407,7 +407,7 @@ seastar::future<> test_read_write() { }); } -seastar::future<> test_unexpected_down() { +future<> test_unexpected_down() { logger.info("test_unexpected_down()..."); return SocketFactory::get_sockets().then([] (auto sockets) { auto [client_socket, server_socket] = std::move(sockets); @@ -421,7 +421,7 @@ seastar::future<> test_unexpected_down() { }); } -seastar::future<> test_shutdown_propagated() { +future<> test_shutdown_propagated() { logger.info("test_shutdown_propagated()..."); return SocketFactory::get_sockets().then([] (auto sockets) { auto [client_socket, server_socket] = std::move(sockets); @@ -437,7 +437,7 @@ seastar::future<> test_shutdown_propagated() { }); } -seastar::future<> test_preemptive_down() { +future<> test_preemptive_down() { logger.info("test_preemptive_down()..."); return SocketFactory::get_sockets().then([] (auto sockets) { auto [client_socket, server_socket] = std::move(sockets); diff --git a/src/test/encoding.cc b/src/test/encoding.cc index 6d252fae18b..4f91ecc4deb 100644 --- a/src/test/encoding.cc +++ b/src/test/encoding.cc @@ -320,8 +320,8 @@ TEST(EncodingRoundTrip, Integers) { } const char* expected_what[] = { - "void lame_decoder(int) no longer understand old encoding version 100 < 200: Malformed input", - "void lame_decoder(int) decode past end of struct encoding: Malformed input" + "buffer::malformed_input: void lame_decoder(int) no longer understand old encoding version 100 < 200", + "buffer::malformed_input: void lame_decoder(int) decode past end of struct encoding", }; void lame_decoder(int which) { diff --git a/src/test/librados/CMakeLists.txt b/src/test/librados/CMakeLists.txt index b0faa7c76ac..4fc53d24066 100644 --- a/src/test/librados/CMakeLists.txt +++ b/src/test/librados/CMakeLists.txt @@ -187,15 +187,3 @@ target_link_libraries(unittest_librados_config librados ${BLKID_LIBRARIES} ${GSSAPI_LIBRARIES} ${OPENLDAP_LIBRARIES}) -# Removing this test. We can't shove it into Finisher as it's not a -# Context any more, and wrapping it to adapt it would be less fair. - -#add_executable(ceph_test_rados_completion_speed -# completion_speed.cc) -#target_link_libraries(ceph_test_rados_completion_speed -# librados ${UNITTEST_LIBS} radostest-cxx) - -add_executable(ceph_test_rados_op_speed - op_speed.cc) -target_link_libraries(ceph_test_rados_op_speed - librados ${UNITTEST_LIBS} radostest-cxx) diff --git a/src/test/librados/completion_speed.cc b/src/test/librados/completion_speed.cc deleted file mode 100644 index 708a58425e1..00000000000 --- a/src/test/librados/completion_speed.cc +++ /dev/null @@ -1,38 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab - -#include "include/rados/librados.hpp" -#include "common/ceph_context.h" -#include "common/Finisher.h" -#include "librados/AioCompletionImpl.h" - - -constexpr int max_completions = 10'000'000; -int completed = 0; -auto cct = (new CephContext(CEPH_ENTITY_TYPE_CLIENT))->get(); -Finisher f(cct); - -void completion_cb(librados::completion_t cb, void* arg) { - auto c = static_cast<librados::AioCompletion*>(arg); - delete c; - if (++completed < max_completions) { - auto aio = librados::Rados::aio_create_completion(); - aio->set_complete_callback(static_cast<void*>(aio), &completion_cb); - f.queue(new librados::C_AioComplete(aio->pc)); - } -} - -int main(void) { - auto aio = librados::Rados::aio_create_completion(); - aio->set_complete_callback(static_cast<void*>(aio), &completion_cb); - f.queue(new librados::C_AioComplete(aio->pc)); - f.start(); - - while (completed < max_completions) - f.wait_for_empty(); - - f.stop(); - - assert(completed == max_completions); - cct->put(); -} diff --git a/src/test/librados/op_speed.cc b/src/test/librados/op_speed.cc deleted file mode 100644 index 90c7bdac571..00000000000 --- a/src/test/librados/op_speed.cc +++ /dev/null @@ -1,22 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -* -// vim: ts=8 sw=2 smarttab - -#include "include/rados/librados.hpp" - -constexpr int to_create = 10'000'000; - -int main() { - for (int i = 0; i < to_create; ++i) { - librados::ObjectReadOperation op; - bufferlist bl; - std::uint64_t sz; - struct timespec tm; - std::map<std::string, ceph::buffer::list> xattrs; - std::map<std::string, ceph::buffer::list> omap; - bool more; - op.read(0, 0, &bl, nullptr); - op.stat2(&sz, &tm, nullptr); - op.getxattrs(&xattrs, nullptr); - op.omap_get_vals2({}, 1000, &omap, &more, nullptr); - } -} diff --git a/src/test/mon/test-mon-msg.cc b/src/test/mon/test-mon-msg.cc index 4c551cab810..ad7ab6c8e23 100644 --- a/src/test/mon/test-mon-msg.cc +++ b/src/test/mon/test-mon-msg.cc @@ -20,7 +20,6 @@ #include "global/global_init.h" #include "global/global_context.h" -#include "common/async/context_pool.h" #include "common/ceph_argparse.h" #include "common/version.h" #include "common/dout.h" @@ -52,7 +51,6 @@ class MonClientHelper : public Dispatcher { protected: CephContext *cct; - ceph::async::io_context_pool poolctx; Messenger *msg; MonClient monc; @@ -65,9 +63,8 @@ public: explicit MonClientHelper(CephContext *cct_) : Dispatcher(cct_), cct(cct_), - poolctx(1), msg(NULL), - monc(cct_, poolctx) + monc(cct_) { } diff --git a/src/test/mon/test_mon_workloadgen.cc b/src/test/mon/test_mon_workloadgen.cc index 613a18f247e..15792a63af5 100644 --- a/src/test/mon/test_mon_workloadgen.cc +++ b/src/test/mon/test_mon_workloadgen.cc @@ -39,7 +39,6 @@ #include "mon/MonClient.h" #include "msg/Dispatcher.h" #include "msg/Messenger.h" -#include "common/async/context_pool.h" #include "common/Timer.h" #include "common/ceph_argparse.h" #include "global/global_init.h" @@ -83,7 +82,6 @@ class TestStub : public Dispatcher { protected: MessengerRef messenger; - ceph::async::io_context_pool poolctx; MonClient monc; ceph::mutex lock; @@ -165,7 +163,6 @@ class TestStub : public Dispatcher monc.shutdown(); timer.shutdown(); messenger->shutdown(); - poolctx.finish(); return 0; } @@ -180,7 +177,7 @@ class TestStub : public Dispatcher TestStub(CephContext *cct, string who) : Dispatcher(cct), - monc(cct, poolctx), + monc(cct), lock(ceph::make_mutex(who.append("::lock"))), timer(cct, lock), do_shutdown(false), @@ -247,7 +244,6 @@ class ClientStub : public TestStub int init() override { int err; - poolctx.start(1); err = monc.build_initial_monmap(); if (err < 0) { derr << "ClientStub::" << __func__ << " ERROR: build initial monmap: " @@ -263,7 +259,7 @@ class ClientStub : public TestStub dout(10) << "ClientStub::" << __func__ << " starting messenger at " << messenger->get_myaddrs() << dendl; - objecter.reset(new Objecter(cct, messenger.get(), &monc, poolctx, 0, 0)); + objecter.reset(new Objecter(cct, messenger.get(), &monc, NULL, 0, 0)); ceph_assert(objecter.get() != NULL); objecter->set_balanced_budget(); diff --git a/src/test/osd/TestOSDScrub.cc b/src/test/osd/TestOSDScrub.cc index 810d77521bb..34a3b8d81af 100644 --- a/src/test/osd/TestOSDScrub.cc +++ b/src/test/osd/TestOSDScrub.cc @@ -22,7 +22,6 @@ #include <stdio.h> #include <signal.h> #include <gtest/gtest.h> -#include "common/async/context_pool.h" #include "osd/OSD.h" #include "os/ObjectStore.h" #include "mon/MonClient.h" @@ -42,9 +41,8 @@ public: Messenger *hb_front_server, Messenger *hb_back_server, Messenger *osdc_messenger, - MonClient *mc, const std::string &dev, const std::string &jdev, - ceph::async::io_context_pool& ictx) : - OSD(cct_, store_, id, internal, external, hb_front_client, hb_back_client, hb_front_server, hb_back_server, osdc_messenger, mc, dev, jdev, ictx) + MonClient *mc, const std::string &dev, const std::string &jdev) : + OSD(cct_, store_, id, internal, external, hb_front_client, hb_back_client, hb_front_server, hb_back_server, osdc_messenger, mc, dev, jdev) { } @@ -54,7 +52,6 @@ public: }; TEST(TestOSDScrub, scrub_time_permit) { - ceph::async::io_context_pool icp(1); ObjectStore *store = ObjectStore::create(g_ceph_context, g_conf()->osd_objectstore, g_conf()->osd_data, @@ -66,9 +63,9 @@ TEST(TestOSDScrub, scrub_time_permit) { ms->set_cluster_protocol(CEPH_OSD_PROTOCOL); ms->set_default_policy(Messenger::Policy::stateless_server(0)); ms->bind(g_conf()->public_addr); - MonClient mc(g_ceph_context, icp); + MonClient mc(g_ceph_context); mc.build_initial_monmap(); - TestOSDScrub* osd = new TestOSDScrub(g_ceph_context, store, 0, ms, ms, ms, ms, ms, ms, ms, &mc, "", "", icp); + TestOSDScrub* osd = new TestOSDScrub(g_ceph_context, store, 0, ms, ms, ms, ms, ms, ms, ms, &mc, "", ""); g_ceph_context->_conf.set_val("osd_scrub_begin_hour", "0"); g_ceph_context->_conf.set_val("osd_scrub_end_hour", "24"); diff --git a/src/test/rgw/test_rgw_common.h b/src/test/rgw/test_rgw_common.h index 29ab3e4ac38..c360e3b0ad5 100644 --- a/src/test/rgw/test_rgw_common.h +++ b/src/test/rgw/test_rgw_common.h @@ -414,7 +414,7 @@ public: } else { ssize_t pos = object.find('_', 1); if (pos < 0) { - throw buffer::malformed_input(); + throw buffer::error(); } orig_obj = object.substr(pos); } diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index c0814c888f7..0f8120a7775 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -16,14 +16,6 @@ else() endif() install(TARGETS rados DESTINATION bin) -set(neorados_srcs - neorados.cc) -add_executable(neorados ${neorados_srcs}) - -target_link_libraries(neorados libRADOS global Boost::coroutine ${CMAKE_DL_LIBS}) -#install(TARGETS neorados DESTINATION bin) - - if(WITH_TESTS) add_executable(ceph_scratchtool scratchtool.c) target_link_libraries(ceph_scratchtool librados global) diff --git a/src/tools/ceph_monstore_tool.cc b/src/tools/ceph_monstore_tool.cc index c3b3089bd23..030f8b437a9 100644 --- a/src/tools/ceph_monstore_tool.cc +++ b/src/tools/ceph_monstore_tool.cc @@ -924,7 +924,7 @@ int main(int argc, char **argv) { } } catch (const buffer::error &err) { std::cerr << "Could not decode for human readable output (you may still" - " use non-readable mode). Detail: " << err.what() << std::endl; + " use non-readable mode). Detail: " << err << std::endl; } out.append(ss); diff --git a/src/tools/ceph_objectstore_tool.cc b/src/tools/ceph_objectstore_tool.cc index 2bec6603a87..229c9f628ee 100644 --- a/src/tools/ceph_objectstore_tool.cc +++ b/src/tools/ceph_objectstore_tool.cc @@ -676,7 +676,7 @@ int do_trim_pg_log(ObjectStore *store, const coll_t &coll, try { e.decode_with_checksum(bp); } catch (const buffer::error &e) { - cerr << "Error reading pg log entry: " << e.what() << std::endl; + cerr << "Error reading pg log entry: " << e << std::endl; } if (debug) { cerr << "read entry " << e << std::endl; diff --git a/src/tools/cephfs/DataScan.cc b/src/tools/cephfs/DataScan.cc index 38e74301095..4dfbe48ccd9 100644 --- a/src/tools/cephfs/DataScan.cc +++ b/src/tools/cephfs/DataScan.cc @@ -1288,7 +1288,7 @@ int DataScan::scan_frags() auto q = parent_bl.cbegin(); backtrace.decode(q); } catch (buffer::error &e) { - dout(4) << "Corrupt backtrace on '" << oid << "': " << e.what() << dendl; + dout(4) << "Corrupt backtrace on '" << oid << "': " << e << dendl; if (!force_corrupt) { return -EINVAL; } else { @@ -1303,7 +1303,7 @@ int DataScan::scan_frags() auto q = layout_bl.cbegin(); decode(loaded_layout, q); } catch (buffer::error &e) { - dout(4) << "Corrupt layout on '" << oid << "': " << e.what() << dendl; + dout(4) << "Corrupt layout on '" << oid << "': " << e << dendl; if (!force_corrupt) { return -EINVAL; } @@ -1586,8 +1586,7 @@ int MetadataDriver::get_frag_of( backtrace.decode(q); have_backtrace = true; } catch (buffer::error &e) { - dout(4) << "Corrupt backtrace on '" << root_frag_oid << "': " - << e.what() << dendl; + dout(4) << "Corrupt backtrace on '" << root_frag_oid << "': " << e << dendl; } } diff --git a/src/tools/cephfs/MDSUtility.cc b/src/tools/cephfs/MDSUtility.cc index cc4de9ff1b8..839b4aea050 100644 --- a/src/tools/cephfs/MDSUtility.cc +++ b/src/tools/cephfs/MDSUtility.cc @@ -25,10 +25,10 @@ MDSUtility::MDSUtility() : waiting_for_mds_map(NULL), inited(false) { - monc = new MonClient(g_ceph_context, poolctx); + monc = new MonClient(g_ceph_context); messenger = Messenger::create_client_messenger(g_ceph_context, "mds"); fsmap = new FSMap(); - objecter = new Objecter(g_ceph_context, messenger, monc, poolctx, 0, 0); + objecter = new Objecter(g_ceph_context, messenger, monc, NULL, 0, 0); } @@ -52,7 +52,6 @@ int MDSUtility::init() if (r < 0) return r; - poolctx.start(1); messenger->start(); objecter->set_client_incarnation(0); @@ -126,7 +125,6 @@ void MDSUtility::shutdown() monc->shutdown(); messenger->shutdown(); messenger->wait(); - poolctx.finish(); } diff --git a/src/tools/cephfs/MDSUtility.h b/src/tools/cephfs/MDSUtility.h index 09f1918ba44..e5097ec48fe 100644 --- a/src/tools/cephfs/MDSUtility.h +++ b/src/tools/cephfs/MDSUtility.h @@ -20,7 +20,6 @@ #include "msg/Dispatcher.h" #include "msg/Messenger.h" #include "auth/Auth.h" -#include "common/async/context_pool.h" #include "common/Finisher.h" #include "common/Timer.h" @@ -39,7 +38,6 @@ protected: ceph::mutex lock = ceph::make_mutex("MDSUtility::lock"); Finisher finisher; - ceph::async::io_context_pool poolctx; Context *waiting_for_mds_map; diff --git a/src/tools/neorados.cc b/src/tools/neorados.cc deleted file mode 100644 index 6bfd2fb0f42..00000000000 --- a/src/tools/neorados.cc +++ /dev/null @@ -1,368 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2019 Red Hat <contact@redhat.com> - * Author: Adam C. Emerson <aemerson@redhat.com> - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#define BOOST_COROUTINES_NO_DEPRECATION_WARNING - -#include <algorithm> -#include <cassert> -#include <iostream> -#include <string> -#include <string_view> -#include <tuple> -#include <vector> - -#include <boost/asio.hpp> -#include <boost/asio/spawn.hpp> -#include <boost/io/ios_state.hpp> -#include <boost/program_options.hpp> -#include <boost/system/system_error.hpp> - -#include <fmt/format.h> -#include <fmt/ostream.h> - -#include "include/buffer.h" // :( - -#include "include/RADOS/RADOS.hpp" - -using namespace std::literals; - -namespace ba = boost::asio; -namespace bs = boost::system; -namespace R = RADOS; - -std::string verstr(const std::tuple<uint32_t, uint32_t, uint32_t>& v) { - const auto [maj, min, p] = v; - return fmt::format("v{}.{}.{}", maj, min, p); -} - -template<typename V> -void printseq(const V& v, std::ostream& m) { - std::for_each(v.cbegin(), v.cend(), - [&m](const auto& e) { - fmt::print(m, "{}\n", e); - }); -} - -template<typename V, typename F> -void printseq(const V& v, std::ostream& m, F&& f) { - std::for_each(v.cbegin(), v.cend(), - [&m, &f](const auto& e) { - fmt::print(m, "{}\n", f(e)); - }); -} - -std::int64_t lookup_pool(R::RADOS& r, const std::string& pname, - ba::yield_context y) { - bs::error_code ec; - auto p = r.lookup_pool(pname, y[ec]); - if (ec) - throw bs::system_error( - ec, fmt::format("when looking up '{}'", pname)); - return p; -} - - -void lspools(R::RADOS& r, const std::vector<std::string>&, - ba::yield_context y) { - const auto l = r.list_pools(y); - printseq(l, std::cout, [](const auto& p) -> const std::string& { - return p.second; - }); -} - - -void ls(R::RADOS& r, const std::vector<std::string>& p, ba::yield_context y) { - const auto& pname = p[0]; - const auto pool = lookup_pool(r, pname, y); - - std::vector<R::Entry> ls; - R::Cursor next = R::Cursor::begin(); - bs::error_code ec; - do { - r.enumerate_objects(pool, next, R::Cursor::end(), - 1000, {}, &ls, &next, y[ec], R::all_nspaces); - if (ec) - throw bs::system_error(ec, fmt::format("when listing {}", pname)); - printseq(ls, std::cout); - ls.clear(); - } while (next != R::Cursor::end()); -} - -void mkpool(R::RADOS& r, const std::vector<std::string>& p, - ba::yield_context y) { - const auto& pname = p[0]; - bs::error_code ec; - r.create_pool(pname, std::nullopt, y[ec]); - if (ec) - throw bs::system_error(ec, fmt::format("when creating pool '{}'", pname)); -} - -void rmpool(R::RADOS& r, const std::vector<std::string>& p, - ba::yield_context y) { - const auto& pname = p[0]; - bs::error_code ec; - r.delete_pool(pname, y[ec]); - if (ec) - throw bs::system_error(ec, fmt::format("when removing pool '{}'", pname)); -} - -void create(R::RADOS& r, const std::vector<std::string>& p, - ba::yield_context y) { - const auto& pname = p[0]; - const R::Object obj = p[1]; - const auto pool = lookup_pool(r, pname, y); - - bs::error_code ec; - R::WriteOp op; - op.create(true); - r.execute(obj, pool, std::move(op), y[ec]); - if (ec) - throw bs::system_error(ec, - fmt::format( - "when creating object '{}' in pool '{}'", - obj, pname)); -} - -inline constexpr std::size_t io_size = 4 << 20; - -void write(R::RADOS& r, const std::vector<std::string>& p, ba::yield_context y) { - const auto& pname = p[0]; - const R::Object obj(p[1]); - const auto pool = lookup_pool(r, pname, y); - - bs::error_code ec; - std::unique_ptr<char[]> buf = std::make_unique<char[]>(io_size); - std::size_t off = 0; - boost::io::ios_exception_saver ies(std::cin); - - cin.exceptions(std::istream::badbit); - std::cin.clear(); - - while (!std::cin.eof()) { - auto curoff = off; - std::cin.read(buf.get(), io_size); - auto len = std::cin.gcount(); - off += len; - if (len == 0) - break; // Nothin' to do. - - ceph::buffer::list bl; - bl.append(buffer::create_static(len, buf.get())); - R::WriteOp op; - op.write(curoff, std::move(bl)); - r.execute(obj, pool, std::move(op), y[ec]); - - if (ec) - throw bs::system_error(ec, fmt::format( - "when writing object '{}' in pool '{}'", - obj, pname)); - } -} - -void read(R::RADOS& r, const std::vector<std::string>& p, ba::yield_context y) { - const auto& pname = p[0]; - const R::Object obj(p[1]); - const auto pool = lookup_pool(r, pname, y); - - bs::error_code ec; - std::uint64_t len; - { - R::ReadOp op; - op.stat(&len, nullptr); - r.execute(obj, pool, std::move(op), - nullptr, y[ec]); - if (ec) - throw bs::system_error( - ec, - fmt::format("when getting length of object '{}' in pool '{}'", - obj, pname)); - } - - std::size_t off = 0; - ceph::buffer::list bl; - while (auto toread = std::max(len - off, io_size)) { - R::ReadOp op; - op.read(off, toread, &bl); - r.execute(obj, pool, std::move(op), nullptr, y[ec]); - if (ec) - throw bs::system_error( - ec, - fmt::format("when reading from object '{}' in pool '{}'", - obj, pool)); - - off += bl.length(); - bl.write_stream(std::cout); - bl.clear(); - } -} - -void rm(R::RADOS& r, const std::vector<std::string>& p, ba::yield_context y) { - const auto& pname = p[0]; - const R::Object obj = p[1]; - const auto pool = lookup_pool(r, pname, y); - - bs::error_code ec; - R::WriteOp op; - op.remove(); - r.execute(obj, pool, std::move(op), y[ec]); - if (ec) - throw bs::system_error(ec, fmt::format( - "when removing object '{}' in pool '{}'", - obj, pname)); -} - -static constexpr auto version = std::make_tuple(0ul, 0ul, 1ul); - -using cmdfunc = void (*)(R::RADOS& r, const std::vector<std::string>& p, - ba::yield_context); - -struct cmdesc { - std::string_view name; - std::size_t arity; - cmdfunc f; - std::string_view usage; - std::string_view desc; -}; - -const std::array commands = { - // Pools operations ;) - - cmdesc{ "lspools"sv, - 0, &lspools, - ""sv, - "List all pools"sv }, - - // Pool operations - - cmdesc{ "ls"sv, - 1, &ls, - "POOL"sv, - "list all objects in POOL"sv }, - cmdesc{ "mkpool"sv, - 1, &mkpool, - "POOL"sv, - "create POOL"sv }, - cmdesc{ "rmpool"sv, - 1, &rmpool, - "POOL"sv, - "remove POOL"sv }, - - // Object operations - - cmdesc{ "create"sv, - 2, &create, - "POOL OBJECT"sv, - "exclusively create OBJECT in POOL"sv }, - cmdesc{ "write"sv, - 2, &write, - "POOL OBJECT"sv, - "write to OBJECT in POOL from standard input"sv }, - cmdesc{ "read"sv, - 2, &read, - "POOL OBJECT"sv, - "read contents of OBJECT in POOL to standard out"sv }, - cmdesc{ "rm"sv, - 2, &rm, - "POOL OBJECT"sv, - "remove OBJECT in POOL"sv } -}; - -int main(int argc, char* argv[]) -{ - const std::string_view prog(argv[0]); - std::string command; - namespace po = boost::program_options; - try { - std::vector<std::string> parameters; - - po::options_description desc(fmt::format("{} options", prog)); - desc.add_options() - ("help", "show help") - ("version", "show version") - ("command", po::value<std::string>(&command), "the operation to perform") - ("parameters", po::value<std::vector<std::string>>(¶meters), - "parameters to the command"); - - po::positional_options_description p; - p.add("command", 1); - p.add("parameters", -1); - - po::variables_map vm; - - po::store(po::command_line_parser(argc, argv). - options(desc).positional(p).run(), vm); - - po::notify(vm); - - if (vm.count("help")) { - fmt::print("{}", desc); - fmt::print("\nCommands:\n"); - for (const auto& cmd : commands) { - fmt::print("\t{} {}\n\t\t{}\n", - cmd.name, cmd.usage, cmd.desc); - } - return 0; - } - - if (vm.count("version")) { - fmt::print( - "{}: RADOS command exerciser, {},\n" - "RADOS library version {}\n" - "Copyright (C) 2019 Red Hat <contact@redhat.com>\n" - "This is free software; you can redistribute it and/or\n" - "modify it under the terms of the GNU Lesser General Public\n" - "License version 2.1, as published by the Free Software\n" - "Foundation. See file COPYING.\n", prog, - verstr(version), verstr(R::RADOS::version())); - return 0; - } - - if (vm.find("command") == vm.end()) { - fmt::print(std::cerr, "{}: A command is required\n", prog); - return 1; - } - - ba::io_context c; - - if (auto ci = std::find_if(commands.begin(), commands.end(), - [&command](const cmdesc& c) { - return c.name == command; - }); ci != commands.end()) { - if (parameters.size() < ci->arity) { - fmt::print(std::cerr, "{}: {}: too few arguments\n\t{} {}\n", - prog, command, ci->name, ci->usage); - return 1; - } - if (parameters.size() > ci->arity) { - fmt::print(std::cerr, "{}: {}: too many arguments\n\t{} {}\n", - prog, command, ci->name, ci->usage); - return 1; - } - ba::spawn(c, [&](ba::yield_context y) { - auto r = R::RADOS::Builder{}.build(c, y); - ci->f(r, parameters, y); - }); - } else { - fmt::print(std::cerr, "{}: {}: unknown command\n", prog, command); - return 1; - } - c.run(); - } catch (const std::exception& e) { - fmt::print(std::cerr, "{}: {}: {}\n", prog, command, e.what()); - return 1; - } - - return 0; -} |