]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
spawn: use explicit strand executor
authorCasey Bodley <cbodley@redhat.com>
Mon, 1 Nov 2021 17:14:16 +0000 (13:14 -0400)
committerCory Snyder <csnyder@iland.com>
Tue, 16 Nov 2021 14:55:17 +0000 (09:55 -0500)
the default spawn::yield_context uses the polymorphic boost::asio::executor
to support any executor type

rgw's beast frontend always uses the same executor type for these
coroutines, so we can use that type directly to avoid the overhead of
type erasure and virtual function calls

Signed-off-by: Casey Bodley <cbodley@redhat.com>
(cherry picked from commit 9d9258e06b78bb47fd0156d9bd7bb00b52a726b0)

Conflicts:
src/common/async/yield_context.h
src/rgw/rgw_d3n_cacherequest.h
src/rgw/rgw_notify.cc
src/rgw/rgw_sync_checkpoint.cc

Cherry-pick notes:
- src/rgw/rgw_d3n_cacherequest.h doesn't exist in Octopus
- src/rgw/rgw_sync_checkpoint.cc doesn't exist in Octopus
- conflicts due to rename of structs after Octopus
- conflicts due to macro for conditional inclusion of beast context in Octopus

src/common/async/yield_context.h
src/rgw/rgw_aio.cc
src/rgw/rgw_aio_throttle.h
src/rgw/rgw_asio_frontend.cc
src/test/rgw/test_rgw_dmclock_scheduler.cc
src/test/rgw/test_rgw_reshard_wait.cc
src/test/rgw/test_rgw_throttle.cc

index fdfb3f5b8fe1a4586981c239af5a4df0f15975b0..7720bc37e091df6f5e0fafe22068fa3e97110835 100644 (file)
 #ifndef HAVE_BOOST_CONTEXT
 
 // hide the dependency on boost::context
-namespace spawn {
 struct yield_context;
-}
 
 #else // HAVE_BOOST_CONTEXT
 #include <spawn/spawn.hpp>
 
-#endif // HAVE_BOOST_CONTEXT
+// use explicit executor types instead of the type-erased boost::asio::executor.
+// coroutines wrap the default io_context executor with a strand executor
+using yield_context = spawn::basic_yield_context<
+    boost::asio::executor_binder<void(*)(),
+        boost::asio::strand<boost::asio::io_context::executor_type>>>;
 
+#endif // HAVE_BOOST_CONTEXT
 
 /// optional-like wrapper for a spawn::yield_context and its associated
 /// boost::asio::io_context. operations that take an optional_yield argument
@@ -39,11 +42,11 @@ struct yield_context;
 /// of the blocking the thread of execution
 class optional_yield {
   boost::asio::io_context *c = nullptr;
-  spawn::yield_context *y = nullptr;
+  yield_context *y = nullptr;
  public:
   /// construct with a valid io and yield_context
   explicit optional_yield(boost::asio::io_context& c,
-                          spawn::yield_context& y) noexcept
+                          yield_context& y) noexcept
     : c(&c), y(&y) {}
 
   /// type tag to construct an empty object
@@ -57,7 +60,7 @@ class optional_yield {
   boost::asio::io_context& get_io_context() const noexcept { return *c; }
 
   /// return a reference to the yield_context. only valid if non-empty
-  spawn::yield_context& get_yield_context() const noexcept { return *y; }
+  yield_context& get_yield_context() const noexcept { return *y; }
 };
 
 // type tag object to construct an empty optional_yield
index 48c83be98ac8ac210754aea01530a8e6c2552fda..14662e536122b09d984a93d437319e9a8514eb1b 100644 (file)
@@ -80,12 +80,12 @@ struct Handler {
 
 template <typename Op>
 Aio::OpFunc aio_abstract(Op&& op, boost::asio::io_context& context,
-                         spawn::yield_context yield) {
+                         yield_context yield) {
   return [op = std::move(op), &context, yield] (Aio* aio, AioResult& r) mutable {
       // arrange for the completion Handler to run on the yield_context's strand
       // executor so it can safely call back into Aio without locking
       using namespace boost::asio;
-      async_completion<spawn::yield_context, void()> init(yield);
+      async_completion<yield_context, void()> init(yield);
       auto ex = get_associated_executor(init.completion_handler);
 
       auto& ref = r.obj.get_ref();
index 764469d7ed38b6d3d77ce3e0430ee83f3cb8a523..e3c485c7eb9da2070aece0a15a6feb952ab00c21 100644 (file)
@@ -83,7 +83,7 @@ class BlockingAioThrottle final : public Aio, private Throttle {
 // functions must be called within the coroutine strand
 class YieldingAioThrottle final : public Aio, private Throttle {
   boost::asio::io_context& context;
-  spawn::yield_context yield;
+  yield_context yield;
   struct Handler;
 
   // completion callback associated with the waiter
@@ -97,7 +97,7 @@ class YieldingAioThrottle final : public Aio, private Throttle {
 
  public:
   YieldingAioThrottle(uint64_t window, boost::asio::io_context& context,
-                      spawn::yield_context yield)
+                      yield_context yield)
     : Throttle(window), context(context), yield(yield)
   {}
 
index 321f6178299a55b1436cad1711401161b863d1bf..c8533d8563439a2709a24a435a6d9b455f72afd5 100644 (file)
@@ -53,13 +53,12 @@ template <typename Stream>
 class StreamIO : public rgw::asio::ClientIO {
   CephContext* const cct;
   Stream& stream;
-  spawn::yield_context yield;
+  yield_context yield;
   parse_buffer& buffer;
   ceph::timespan request_timeout;
  public:
   StreamIO(CephContext *cct, Stream& stream, rgw::asio::parser_type& parser,
-           spawn::yield_context yield,
-           parse_buffer& buffer, bool is_ssl,
+           yield_context yield, parse_buffer& buffer, bool is_ssl,
            const tcp::endpoint& local_endpoint,
            const tcp::endpoint& remote_endpoint,
            ceph::timespan request_timeout)
@@ -148,7 +147,7 @@ void handle_connection(boost::asio::io_context& context,
                        SharedMutex& pause_mutex,
                        rgw::dmclock::Scheduler *scheduler,
                        boost::system::error_code& ec,
-                       spawn::yield_context yield,
+                       yield_context yield,
                        ceph::timespan request_timeout)
 {
   // limit header to 4k, since we read it all into a single flat_buffer
@@ -923,7 +922,7 @@ void AsioFrontend::accept(Listener& l, boost::system::error_code ec)
 #ifdef WITH_RADOSGW_BEAST_OPENSSL
   if (l.use_ssl) {
     spawn::spawn(context,
-      [this, s=std::move(stream)] (spawn::yield_context yield) mutable {
+      [this, s=std::move(stream)] (yield_context yield) mutable {
         Connection conn{s.socket()};
         auto c = connections.add(conn);
         // wrap the tcp_stream in an ssl stream
@@ -954,7 +953,7 @@ void AsioFrontend::accept(Listener& l, boost::system::error_code ec)
   {
 #endif // WITH_RADOSGW_BEAST_OPENSSL
     spawn::spawn(context,
-      [this, s=std::move(stream)] (spawn::yield_context yield) mutable {
+      [this, s=std::move(stream)] (yield_context yield) mutable {
         Connection conn{s.socket()};
         auto c = connections.add(conn);
         auto buffer = std::make_unique<parse_buffer>();
index 2943df218750e308d138dccef4330b1bc23ce54e..c8e16421cd27f7c0505f194fa7538eeaa7b3f690 100644 (file)
@@ -401,7 +401,7 @@ TEST(Queue, SpawnAsyncRequest)
 {
   boost::asio::io_context context;
 
-  spawn::spawn(context, [&] (spawn::yield_context yield) {
+  spawn::spawn(context, [&] (yield_context yield) {
     ClientCounters counters(g_ceph_context);
     AsyncScheduler queue(g_ceph_context, context, std::ref(counters), nullptr,
                     [] (client_id client) -> ClientInfo* {
index a1f55b5a71686d202d87905e4bd1f21fc1cef1cb..0c42c536f45442a199020827b8e9ade2cf272bbe 100644 (file)
@@ -67,7 +67,7 @@ TEST(ReshardWait, wait_yield)
   RGWReshardWait waiter(wait_duration);
 
   boost::asio::io_context context;
-  spawn::spawn(context, [&] (spawn::yield_context yield) {
+  spawn::spawn(context, [&] (yield_context yield) {
       EXPECT_EQ(0, waiter.wait(optional_yield{context, yield}));
     });
 
@@ -93,7 +93,7 @@ TEST(ReshardWait, stop_yield)
 
   boost::asio::io_context context;
   spawn::spawn(context,
-    [&] (spawn::yield_context yield) {
+    [&] (yield_context yield) {
       EXPECT_EQ(-ECANCELED, long_waiter.wait(optional_yield{context, yield}));
     });
 
@@ -136,7 +136,7 @@ TEST(ReshardWait, stop_multiple)
   // spawn 4 coroutines
   boost::asio::io_context context;
   {
-    auto async_waiter = [&] (spawn::yield_context yield) {
+    auto async_waiter = [&] (yield_context yield) {
         EXPECT_EQ(-ECANCELED, long_waiter.wait(optional_yield{context, yield}));
       };
     spawn::spawn(context, async_waiter);
index fff680012f4df02282a99037cd5760d6e6257b58..6ac4a89c9063abf31f054be344aa8b0925fba8e1 100644 (file)
@@ -173,7 +173,7 @@ TEST_F(Aio_Throttle, YieldCostOverWindow)
 
   boost::asio::io_context context;
   spawn::spawn(context,
-    [&] (spawn::yield_context yield) {
+    [&] (yield_context yield) {
       YieldingAioThrottle throttle(4, context, yield);
       scoped_completion op;
       auto c = throttle.get(obj, wait_on(op), 8, 0);
@@ -195,7 +195,7 @@ TEST_F(Aio_Throttle, YieldingThrottleOverMax)
 
   boost::asio::io_context context;
   spawn::spawn(context,
-    [&] (spawn::yield_context yield) {
+    [&] (yield_context yield) {
       YieldingAioThrottle throttle(window, context, yield);
       for (uint64_t i = 0; i < total; i++) {
         using namespace std::chrono_literals;