From: Samuel Just Date: Thu, 4 Aug 2022 07:13:04 +0000 (+0000) Subject: crimson/common: introduce local_shared_foreign_ptr X-Git-Tag: v18.1.0~639^2~19^2~31 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=6385b865201a568a8c2209a680baa21a815118e9;p=ceph-ci.git crimson/common: introduce local_shared_foreign_ptr Introduces a foreign_ptr wrapper to allow core-local refcounting. Signed-off-by: Samuel Just --- diff --git a/src/crimson/common/local_shared_foreign_ptr.h b/src/crimson/common/local_shared_foreign_ptr.h new file mode 100644 index 00000000000..ca4edd4d37a --- /dev/null +++ b/src/crimson/common/local_shared_foreign_ptr.h @@ -0,0 +1,121 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#pragma once + +#include +#include + +#include +#include +#include + +namespace crimson { + +/** + * local_shared_foreign_ptr + * + * See seastar/include/seastar/core/sharded.hh:foreign_ptr + * + * seastar::foreign_ptr wraps a smart ptr by proxying the copy() and destructor + * operations back to the original core. This works well except that copy() + * requires a cross-core call. We need a smart_ptr which allows cross-core + * caching of (for example) OSDMaps, but we want to avoid the overhead inherent + * in incrementing the source smart_ptr on every copy. Thus, + * local_shared_foreign_ptr maintains a core-local foreign_ptr back to the + * original core instance with core-local ref counting. + */ +template +class local_shared_foreign_ptr { + using element_type = typename std::pointer_traits::element_type; + using pointer = element_type*; + + seastar::lw_shared_ptr> ptr; + + /// Wraps a pointer object and remembers the current core. + local_shared_foreign_ptr(seastar::foreign_ptr &&fptr) + : ptr(seastar::make_lw_shared(std::move(fptr))) {} + + template + friend local_shared_foreign_ptr make_local_shared_foreign( + seastar::foreign_ptr &&); + +public: + /// Constructs a null local_shared_foreign_ptr<>. + local_shared_foreign_ptr() = default; + + /// Constructs a null local_shared_foreign_ptr<>. + local_shared_foreign_ptr(std::nullptr_t) : local_shared_foreign_ptr() {} + + /// Moves a local_shared_foreign_ptr<> to another object. + local_shared_foreign_ptr(local_shared_foreign_ptr&& other) = default; + + /// Copies a local_shared_foreign_ptr<> + local_shared_foreign_ptr(const local_shared_foreign_ptr &other) = default; + + /// Releases reference to ptr eventually releasing the contained foreign_ptr + ~local_shared_foreign_ptr() = default; + + /// Creates a copy of this foreign ptr. Only works if the stored ptr is copyable. + seastar::future> get_foreign() { + return ptr->copy(); + } + + /// Accesses the wrapped object. + element_type& operator*() const noexcept { + assert(ptr && *ptr); + return **ptr; + } + /// Accesses the wrapped object. + element_type* operator->() const noexcept { + assert(ptr && *ptr); + return &**ptr; + } + + /// Access the raw pointer to the wrapped object. + pointer get() const noexcept { + assert(!ptr || (ptr && *ptr)); + return ptr ? ptr->get() : nullptr; + } + + /// Return the owner-shard of the contained foreign_ptr. + unsigned get_owner_shard() const noexcept { + assert(ptr && *ptr); + return ptr->get_owner_shard(); + } + + /// Checks whether the wrapped pointer is non-null. + operator bool() const noexcept { + assert(!ptr || (ptr && *ptr)); + return static_cast(ptr); + } + + /// Move-assigns a \c local_shared_foreign_ptr<>. + local_shared_foreign_ptr& operator=(local_shared_foreign_ptr&& other) noexcept { + ptr = std::move(other.ptr); + return *this; + } +}; + +/// Wraps a smart_ptr T in a local_shared_foreign_ptr<>. +template +local_shared_foreign_ptr make_local_shared_foreign( + seastar::foreign_ptr &&ptr) { + return local_shared_foreign_ptr(std::move(ptr)); +} + +/// Wraps ptr in a local_shared_foreign_ptr<>. +template +local_shared_foreign_ptr make_local_shared_foreign(T &&ptr) { + return make_local_shared_foreign( + seastar::make_foreign(std::forward(ptr))); +} + +} + +namespace seastar { + +template +struct is_smart_ptr> : std::true_type {}; + +}