]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
Revert "Merge pull request #16715 from adamemerson/wip-I-Object!"
authorSage Weil <sage@redhat.com>
Fri, 22 Nov 2019 15:24:11 +0000 (09:24 -0600)
committerSage Weil <sage@redhat.com>
Fri, 22 Nov 2019 15:24:25 +0000 (09:24 -0600)
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:
.gitignore
src/CMakeLists.txt
src/RADOS/CMakeLists.txt [deleted file]
src/RADOS/RADOS.cc [deleted file]
src/RADOS/RADOSImpl.cc [deleted file]
src/RADOS/RADOSImpl.h [deleted file]
src/ceph_fuse.cc
src/ceph_mds.cc
src/ceph_osd.cc
src/ceph_syn.cc
src/client/Client.cc
src/client/Client.h
src/cls/rgw/cls_rgw_types.h
src/common/async/context_pool.h [deleted file]
src/common/async/waiter.h [deleted file]
src/common/buffer.cc
src/common/ceph_context.h
src/common/ceph_time.h
src/common/ceph_timer.h
src/common/config.cc
src/common/detail/construct_suspended.h [deleted file]
src/common/entity_name.cc
src/common/entity_name.h
src/common/error_code.cc [deleted file]
src/common/error_code.h [deleted file]
src/common/options.cc
src/common/snap_types.h
src/crimson/osd/osd.h
src/crimson/osd/osd_operations/client_request.h
src/crimson/osd/pg.h
src/crimson/osd/pg_backend.h
src/global/global_init.cc
src/global/global_init.h
src/include/Context.h
src/include/RADOS/RADOS.hpp [deleted file]
src/include/RADOS/buffer_fwd.h [deleted symlink]
src/include/RADOS/completion.h [deleted symlink]
src/include/buffer.h
src/include/expected.hpp [deleted file]
src/include/object.h
src/libcephfs.cc
src/librados/AioCompletionImpl.h
src/librados/IoCtxImpl.cc
src/librados/ListObjectImpl.h
src/librados/PoolAsyncCompletionImpl.h
src/librados/RadosClient.cc
src/librados/RadosClient.h
src/librados/librados_c.cc
src/librados/librados_cxx.cc
src/libradosstriper/MultiAioCompletionImpl.cc
src/libradosstriper/MultiAioCompletionImpl.h
src/libradosstriper/RadosStriperImpl.h
src/librbd/Journal.cc
src/mds/CDir.cc
src/mds/CInode.cc
src/mds/MDCache.cc
src/mds/MDSDaemon.cc
src/mds/MDSDaemon.h
src/mds/MDSRank.cc
src/mds/MDSRank.h
src/mds/PurgeQueue.h
src/mds/Server.cc
src/messages/MGetPoolStats.h
src/messages/MGetPoolStatsReply.h
src/messages/MOSDOp.h
src/mgr/BaseMgrModule.cc
src/mgr/MgrContext.h
src/mgr/MgrStandby.cc
src/mgr/MgrStandby.h
src/mon/AuthMonitor.cc
src/mon/ConfigMap.cc
src/mon/ConfigMap.h
src/mon/MonClient.cc
src/mon/MonClient.h
src/mon/MonMap.cc
src/mon/error_code.cc [deleted file]
src/mon/error_code.h [deleted file]
src/mount/conf.cc
src/msg/MessageRef.h
src/msg/async/ProtocolV2.cc
src/osd/OSD.cc
src/osd/OSD.h
src/osd/OSDMap.h
src/osd/PG.h
src/osd/PrimaryLogPG.cc
src/osd/PrimaryLogPG.h
src/osd/error_code.cc [deleted file]
src/osd/error_code.h [deleted file]
src/osd/osd_types.cc
src/osd/osd_types.h
src/osdc/CMakeLists.txt
src/osdc/Filer.cc
src/osdc/Objecter.cc
src/osdc/Objecter.h
src/osdc/error_code.cc [deleted file]
src/osdc/error_code.h [deleted file]
src/rgw/rgw_bucket.cc
src/rgw/rgw_common.h
src/test/CMakeLists.txt
src/test/RADOS/CMakeLists.txt [deleted file]
src/test/RADOS/completions.cc [deleted file]
src/test/RADOS/list_pool.cc [deleted file]
src/test/RADOS/op_speed.cc [deleted file]
src/test/RADOS/start_stop.cc [deleted file]
src/test/crimson/test_socket.cc
src/test/encoding.cc
src/test/librados/CMakeLists.txt
src/test/librados/completion_speed.cc [deleted file]
src/test/librados/op_speed.cc [deleted file]
src/test/mon/test-mon-msg.cc
src/test/mon/test_mon_workloadgen.cc
src/test/osd/TestOSDScrub.cc
src/test/rgw/test_rgw_common.h
src/tools/CMakeLists.txt
src/tools/ceph_monstore_tool.cc
src/tools/ceph_objectstore_tool.cc
src/tools/cephfs/DataScan.cc
src/tools/cephfs/MDSUtility.cc
src/tools/cephfs/MDSUtility.h
src/tools/neorados.cc [deleted file]

index 2600c2c614e5eca6c3c587d35df5beff807e842b..a04d59a632edcb165ba5beee0fb46f5b365c0e20 100644 (file)
@@ -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/
index ca1631c2e202ebacd07f8245577d450810369752..5b89d03937450f81a68fb6715c18771285c93a73 100644 (file)
@@ -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 (file)
index c8d4f1b..0000000
+++ /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 (file)
index e0a900f..0000000
+++ /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 (file)
index 4dd816d..0000000
+++ /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 (file)
index c7ce18a..0000000
+++ /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
index 4f889328f9574e8b4ebd293c6f4b5d0fd0e1e2b3..5ac18116f12cddbc0157076745937e1850bea0e6 100644 (file)
@@ -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);
index 4e6714ac44e4837d46006c2db801075cd08fc2eb..38e673755a95a470dba6a303ffe5547e0324da23 100644 (file)
@@ -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;
 }
+
index 18101dee1221be00eb3230fce874f04475b49c39..3e03e8632396e461f45efa134aec0c4264d55e98 100644 (file)
@@ -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;
index 165ea42308ac6db2e7faf97a63e382654c8803ab..50e26f2815a00b0f812015f342e56642e7cdbb10 100644 (file)
@@ -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;
 }
+
index a9528891fa8e6f8d078f8add615d04053629e33f..e042539c3b52edee6cfdd0ee3c2b4c250351f97f 100644 (file)
@@ -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"
 
 
 #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);
index b75aa47fc1c6eb38bf3a6b1795d0d80db172b2c4..a88abb5d86e8489e47ee0b48ca76bed72d4d19d4 100644 (file)
@@ -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;
 
index 1f519acb75189ba9cdc322b2cf2baf2d1357628b..2b2907ba6fab060a1fc13b2fe8ac8cda12c3bbce 100644 (file)
@@ -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 (file)
index 2e90ba9..0000000
+++ /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 (file)
index 1e95d00..0000000
+++ /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
index 9ea83101826a5f51b89586f1ee339498484fc53d..b7d3591600a5000cbc19349d6201bb26d87c0c60 100644 (file)
@@ -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;
-}
-}
-}
index ae590865945c53194c132a5ead2f9199676050c4..6b6e9482b997e0fcf82922ddd922adfb87c025a8 100644 (file)
@@ -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
index a2018703a27748c767ef0ee15dd3329e4bac72de..ae4a17c781296e851fdce9d71423b04cc74e81f9 100644 (file)
@@ -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);
index 0090f7ccdfe392225f6793ea9ac4081cdd3a037a..b29fac9c3fcb3024f6a6b45156b685ee7dc991dc 100644 (file)
 #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;
index 4c2af4ce6044c2d0144b79c8b7b51caea8592df0..0259ef2f8ee22de3eb4303f9357addb009e06208 100644 (file)
@@ -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 (file)
index 521bda0..0000000
+++ /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
index 2eb24829a1c86adf0d3ca95137a4f7df805377e1..37d02bd94df46f974c1552020827c714b2b1d73c 100644 (file)
@@ -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);
index 886c4b4946f8ed94bc29e435388b6e1942b7ffac..1dd56f66d740af8d4c690dbec1aef26e9a01eb98 100644 (file)
@@ -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 (file)
index 52eee7f..0000000
+++ /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 (file)
index 2fc7cdd..0000000
+++ /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
index 7f65b8bd048d693546bcf8128615344b7ca18e29..ddfef20fce211700bfb263c37cd06972d7ee4fd6 100644 (file)
@@ -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")
   });
 }
 
index 5fd1e08bc21e32fc57b6f329ce34ac8acab9d5b8..9802bdea126b954be3e0a52d0536f0dbacb7d85a 100644 (file)
@@ -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;
index d0beee2fad812bd2a3357391a65c0d3ffb5a163a..843c57e6f733007215c9178b1149a62d01e6c46a 100644 (file)
 #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;
index 09658e2bf9da87be095e713909447eb2fa22ecff..8940194f62f555df4644d4557acdf027c0eee6e8 100644 (file)
@@ -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;
index ecc2dfd59740398715bc936ec4d3176cb7aa734e..4c5cd11b542d1183399c98d0d10a7f683ec9c5db 100644 (file)
@@ -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"
index 60f14b443d94aa2055190e72410dfb8bdb73858d..6530ef11602d83aa221b86fc4728d3b43bbbad6f 100644 (file)
 #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;
index 314cf3def03000693f039cc0b0f64350e9988ccc..dff97e5c7ee04c4385d8ab3d1f4c51e8f6534eab 100644 (file)
@@ -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();
index f4c9a4a8c826d174bcc54837ce7accf92ebc3bc6..fe6f557bb253ea139455be4c6dbdaf8bcd218348 100644 (file)
 #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,
index bef85ca5b52fd7a82e91df35ef0fa33a81c7bed1..6d39be55ba1a25fa0703a98fb6282a1c939c5746 100644 (file)
 
 #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 (file)
index a2242c9..0000000
+++ /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 (symlink)
index bd1f6f1..0000000
+++ /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 (symlink)
index 100678f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../../common/async/completion.h
\ No newline at end of file
index 3d41eaa6e676a2f09107ff84d9d71591572b7e48..98358e450f647e5e3192947c10b55d22174a446b 100644 (file)
 #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
@@ -101,28 +98,6 @@ struct unique_leakable_ptr : public std::unique_ptr<T, ceph::nop_delete<T>> {
   using std::unique_ptr<T, ceph::nop_delete<T>>::unique_ptr;
 };
 
-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 {
 
@@ -130,43 +105,26 @@ 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 (file)
index 740c6ad..0000000
+++ /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
index 96951e74de79b881028348d86c05b72d747d15ef..b0f21bc455806804bcf50e51873f8aa88929abc2 100644 (file)
 
 #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);
index 8cde7fb32193008e89300839277d336d434b892b..8a6b14d1ed8dda06e322a32fce0348188eaeb1ec 100644 (file)
@@ -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;
index 7b49bc68d7371a1ac3d9825165270f145b07a497..d3a674e8ee7d7e3ebf226070672bd5568fddce60 100644 (file)
@@ -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
index 8d3ba1e16fb74822b3530000020c11cc28587441..ddcd4c6fea1b8e8a05e08c5e942c27bc16b12b65 100644 (file)
 #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, &notify_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, &notify_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)
index 7396c12108d0c9c0961ac63d419e20273b14b228..95c2e21a4ec57c1f2481f725d709a9e2f30dd595 100644 (file)
  * 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;
index 73420fe359c45ba2c4f9b715c01eed34c92d0a64..b52d7fada201cb7d4ba385abf1ecd5113c8e42f8 100644 (file)
@@ -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();
     }
   };
 }
index 15fef61f7ea8ad1167088bb2267eaca886faf1be..372419816d8b34166d79185922aeac8ed79d6895 100644 (file)
@@ -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"
 #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"));
-  }
-}
index eb97a765fafaee42f07ce735a2adee7cc4dac974..0f2b153def4a7fd27f55182c61132f6954a98a4b 100644 (file)
 #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
index bbdd91209556f1040f54494d1d013e44defdef5b..41cdbf6a42f8038b80cfb0f2f489289b69a3e9b7 100644 (file)
@@ -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;
 }
 
index 4e240fe0c027c7435ef2b2e46f1f12508be7c203..a021c26280ddd0e6d3d28865ea520e7c746138be 100644 (file)
@@ -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;
index acf9e0b6b8b1b3ec071801ca1ccc694d8919d012..901bb1366640ce1aa3e67c4177eadf0285e084af 100644 (file)
@@ -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();
+}
index 3ac3aae44920fcef0ea3526da0d06c6d8e78d6ea..32f7b9a84cf92274f2b420de7edd40893a8988f0 100644 (file)
@@ -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
index 8226a9ba2a23436d539975a815c65c2119726e6a..160db7b6f8d36e917c8f001a803e0fb0270c2a38 100644 (file)
@@ -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 {
 
index 4a32d93c94b8de7d5b52ff7ec89b09d02d841f64..66849c461fad21b87eff0092d5822aae68075001 100644 (file)
@@ -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;
   }
 
index 540c8461b05deebc562b47637a8d8165b4990ed9..771eb4a890a74f86d1241705b853482729c4b3f5 100644 (file)
@@ -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
index 8e917aad64c914de6d0687a778536fdcafd8322d..e3c4ef1e24af6ea213ef2df15e33778361ac5fc3 100644 (file)
@@ -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;
   }
index 2a9248ab558444a79c9c51563d179d913e8421f0..c32118dd48c84ff18c9cce43e2397a2818e836c0 100644 (file)
@@ -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;
     }
index eb7626d64e517fb1c0c77cb8a60c10824efe0377..45356177b990c6da84b90fb0fe39438efc963d1f 100644 (file)
@@ -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();
index 1b9e79c4543aae25b442ffa2e801f0b54d20c945..a4568ee9c738b74849d9b1be11c760589da9a4fe 100644 (file)
@@ -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;
index f214416555b874bd704f2e05df265fd77c118dcd..924768f6bbe7e54a8404435bbdcc4efb48af8b6f 100644 (file)
@@ -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) {
index fac6b08e47ee2d86c12d14218ebd4bca3d4548b5..4187ee7c5ec3c29fa13117b0801c13291bb80665 100644 (file)
@@ -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();
index 7e3f093c3d89c8f2370bfe573fe2032aab1ce28a..7f42ac05be92f45509a7813a77ffda2cbb2d9c0c 100644 (file)
@@ -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"
 
index c1017e96d311ce213c29ad19b555b252d7304b8e..2e50ccbdb7dadd4a2d32b9f826ea302b55f4dca7 100644 (file)
@@ -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;
     }
   }
index 6b64e4feee2a38c0e878f76d59668490bf4a3552..51bc134a21f7704bbd9fd2361fc5f86c3ddc870a 100644 (file)
 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);
index 063b6f7cb289904f6c2dc4de7d0888912ef07ee4..ff474d3d5db55083d533427591c401f82bae6bfc 100644 (file)
@@ -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,
index 5301f0a43b255703910ab7743cee16629891011c..43bd400546982a7e3b8d0317f5f0783113adbcfa 100644 (file)
  *
  */
 
-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
index d18b35e947e0235b6fefe13a66d750ed96a56124..b340f74f1a1f4666317d6282449759c583b4c8fd 100644 (file)
@@ -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 {
index c6e647365b505317b75de76c9107b53e63a6b103..bec51a3687188e3c86b61b05dc02abe93e3f9423 100644 (file)
@@ -17,7 +17,6 @@
 #include <memory>
 
 #include "common/ceph_json.h"
-#include "common/Cond.h"
 #include "mon/MonClient.h"
 
 class Command
index 913009e7e10fb95344457d96b42090e461fa22c9..b021a1829715efe43da75f23f0d0194523408bad 100644 (file)
@@ -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()
index cac31a5764017ce6e566e8e7e7117f8f95a7a526..d79fef2d5e577cab03c295f00a3e2f7426253a30 100644 (file)
@@ -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;
index aee0e33a4eaf386c9792a6863d3d1688f7c24811..3cb261b412a060abe0edcdfe3de3dc804492ba1b 100644 (file)
@@ -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
index 696b18edbc48c286e399ff3816739fc89a4b302b..b7343ce4264b5b84e12c8457ea4413c408b18fa2 100644 (file)
@@ -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 == '.'; });
index 2b16c43eef3ea09be27dbeeae4418b5b6d694663..17b52af1d1d1d99b2113ca522d7d363a204d7ac7 100644 (file)
@@ -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") {
index 63e3d5cfa3cfde8b0a946b6192788164b9b3244e..dbb4287a2a2ebda4f398daabc5e96b9f6b303031 100644 (file)
@@ -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"
 #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;
-}
index 2d97440df8f6dc27af95f71a225f58195debf506..52c55fb18f321e8ef77b0e5af5426c1a7ce9ad36 100644 (file)
 #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"
 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;
 };
index 95b92ec8f4a6525f45c4210e14426afcf7db76bc..d63bada0fd6fef8b07fb971fb0830dddeb2ed2d1 100644 (file)
@@ -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 (file)
index 67ff736..0000000
+++ /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 (file)
index c247c68..0000000
+++ /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() };
-}
index 0ec86b29fcb284c99cf0277e0b44380fcb4f1b47..228f53e72187fcd6f1d8a2cbaf360b88d74d45eb 100644 (file)
@@ -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;
index 4f30f0b352a91f769e514fad8ea9ba0a4c4882b5..5eb3655cb848e1378373f6f5d8f52a2371eb6c4c 100644 (file)
@@ -133,6 +133,8 @@ class MOSDForceRecovery;
 class MOSDFull;
 class MOSDMap;
 class MOSDMarkMeDown;
+class MOSDOp;
+class MOSDOpReply;
 class MOSDPeeringOp;
 class MOSDPGBackfill;
 class MOSDPGBackfillRemove;
index aa864cf3311750bed22529727a1c8a09ba404486..fe2158289a50b2e623de83f52d6bf58ea8af28c8 100644 (file)
@@ -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) {
index 446ddfbad877149814fd2f41e1ea8f010469a9d1..4c85cd82f981e447f7e8e3195bc8a61f37f93f8d 100644 (file)
@@ -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;
 }
index 174c9dac6454bd7c9b60689f9adb52c911ef30f7..56f6149180a5258cb1a91e8fb68dc1cc929a58da 100644 (file)
@@ -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
index f87e38f45f7c15d1d3247d62299752b5f840d1ff..f0055611b2731b270bb84a6cd6435a8c82d6ea67 100644 (file)
@@ -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;
index e372f8896d765704f68cd03259e12dae5901a5e3..1ed490a0a9aff310aa29fae82ec45a05509e9636 100644 (file)
@@ -61,6 +61,7 @@ class OSD;
 class OSDService;
 class OSDShard;
 class OSDShardPGSlot;
+class MOSDOp;
 class MOSDPGScan;
 class MOSDPGBackfill;
 class MOSDPGInfo;
index da3f52be83ffda82da7b3cfee4bd1335a782d02d..e06fa6c8c55896bc6a3749d1e371f8a2043a8790 100644 (file)
@@ -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;
index 59ff68bfac980a90f0e647dc66a068d11b83b45e..a350714bbfc7ba990b1b35833493b06ca39fb28e 100644 (file)
@@ -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 (file)
index 074064d..0000000
+++ /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 (file)
index f738569..0000000
+++ /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() };
-}
index 70250c12443c4d0e0cb7fecc48d4cb1ae4c9a97c..7cf74108ae7a46582381d53674e803080a83aead 100644 (file)
@@ -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,
index 6e482ee8dbf9a95ea03b2ef1f9644bd918c51f9d..1976456c6cac7b0346d433cc9dc9b224f4e6ecef 100644 (file)
@@ -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);
index 551b105f893fb280c7bcbdccc3eb82f476ad19d7..6dd97b39362377ef6d0b586698522c70c9c96ccf 100644 (file)
@@ -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)
index 4a2aeb8807784a0079aec11fc35942f526a12da8..83370d8c08bd6c2b69e68c6eda26e39dcdbac19b 100644 (file)
@@ -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;
index f1c9552fb57470667b13543056c1b46adbfee2ad..37dc01d0144d5639e69d809065798c011d2d674a 100644 (file)
  *
  */
 
-#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"
 #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_tp = 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_tinterval;
+    ceph::buffer::list bl;
+    uint32_t *interval;
     std::vector<inconsistent_obj_t> *objects = nullptr;
     std::vector<inconsistent_snapset_t> *snapsets = nullptr;
-    intrval;
+    int *rval;
 
-    C_ObjectOperation_scrub_ls(uint32_tinterval,
-                              std::vector<inconsistent_obj_t>objects,
-                              intrval)
+    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_tinterval,
-                              std::vector<inconsistent_snapset_t>snapsets,
-                              intrval)
+    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(::ObjectOperationop,
+  void do_scrub_ls(::ObjectOperation *op,
                   const scrub_ls_arg_t& arg,
                   std::vector<T> *items,
-                  uint32_tinterval,
-                  intrval)
+                  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_tinterval,
-                                intrval)
+                                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);
index a684fbcc83e65de04966412f281dd79234e7a9da..f669ce31c5fbf6c23c899bca45f0751af0088ecf 100644 (file)
 #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;
 
-  PerfCounterslogger = 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 (file)
index 8017f7a..0000000
+++ /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 (file)
index 224c976..0000000
+++ /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() };
-}
index f702d8d5e12a1644a1b2a5d47b7f23b8437ba139..1a3b6b1a4c5562dd67c8ed7cd6fbcc7c04364501 100644 (file)
@@ -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;
         }
 
index a45730867eb4e10bcb479116e3e092ca929eb043..cdc85016318cb1d1f928f933c32042eaf8956b85 100644 (file)
@@ -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);
         }
index 401a5151aaca66948b85793aae88603e49bcad1f..c9bfe9399398d2246576969aed1ca3ef8f2c2a67 100644 (file)
@@ -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 (file)
index e95fbc4..0000000
+++ /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 (file)
index d9c0e08..0000000
+++ /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 (file)
index 5d5cb3d..0000000
+++ /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 (file)
index 715404b..0000000
+++ /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 (file)
index 42132ba..0000000
+++ /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;
-}
index 557a0cf6f06790305225a27e5f0f08233eeecfaa..ec306700bd7fda69e8e6b643563d00f77d6793f5 100644 (file)
@@ -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);
index 6d252fae18b71d65e4698c70fcf697de8bdd480a..4f91ecc4debd8b2d11f5306733889e80d43c144d 100644 (file)
@@ -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) {
index b0faa7c76ac1caeacb26056c5c7d6956170a5cf5..4fc53d240661dd825f5e22557b045e9cd5e2d793 100644 (file)
@@ -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 (file)
index 708a584..0000000
+++ /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 (file)
index 90c7bda..0000000
+++ /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);
-  }
-}
index 4c551cab8109e179acbd86e7895d4f697ba2aa4f..ad7ab6c8e23a1505f4704b829726aa60f2fa31f1 100644 (file)
@@ -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_)
   { }
 
 
index 613a18f247e175b4f648126d72a228b8a7dc9552..15792a63af5816f76ad338eda2c19126411f5f68 100644 (file)
@@ -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();
 
index 810d77521bb765d037fe152d9416e6303d3459ac..34a3b8d81afae65437a4d2048f644b393fcc53a1 100644 (file)
@@ -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");
index 29ab3e4ac38a6d14440e05e804bc0c903f940208..c360e3b0ad5036ad534c3d474e2f9a393146ae46 100644 (file)
@@ -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);
       }
index c0814c888f77be66947baa27959120747e53bd41..0f8120a777522293aa2c55304e7731dda6cd93a1 100644 (file)
@@ -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)
index c3b3089bd23b00195b4c0d2d6d740bbe5f5be2e8..030f8b437a90f57608c3db711fc0400070db2f68 100644 (file)
@@ -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);
index 2bec6603a872278d3620739b707613e0bd313723..229c9f628eee1e0ea0970e481fcd93297dbe4f96 100644 (file)
@@ -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;
index 38e743010953d6631a0ddb1c74e83b648d41511a..4dfbe48ccd9ffb55a59af099b628082a38ec69f0 100644 (file)
@@ -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;
     }
   }
 
index cc4de9ff1b8b2586efbc38b48f7cf45beb0ea58e..839b4aea0502d25bea0d20be00670367d58e7049 100644 (file)
@@ -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();
 }
 
 
index 09f1918ba4457c5a0a6de195a7aa546ec4eb22e6..e5097ec48fe25dd7d90a550885b259e09c3c88c3 100644 (file)
@@ -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 (file)
index 6bfd2fb..0000000
+++ /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>>(&parameters),
-       "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;
-}