]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
rgw: RGWDeleteMultiObj spawns a coroutine on null_yield
authorCasey Bodley <cbodley@redhat.com>
Tue, 22 Jul 2025 18:25:37 +0000 (14:25 -0400)
committerCasey Bodley <cbodley@redhat.com>
Mon, 28 Jul 2025 15:56:18 +0000 (11:56 -0400)
if called with null_yield, RGWDeleteMultiObj::execute() creates an
io_context and spawns a coroutine to run on it. this ensures that
spawn_throttle always gets a valid yield context

Signed-off-by: Casey Bodley <cbodley@redhat.com>
src/rgw/rgw_op.cc
src/rgw/rgw_op.h

index 4965625c9324dec1650f4f0aba90aca8014525c9..41ca7ad2c437d8af2732f14f0c8cf92a23f08cfd 100644 (file)
@@ -7642,6 +7642,22 @@ void RGWDeleteMultiObj::handle_individual_object(const RGWMultiDelObject& object
   send_partial_response(o, del_op->result.delete_marker, del_op->result.version_id, op_ret);
 }
 
+void RGWDeleteMultiObj::handle_objects(const std::vector<RGWMultiDelObject>& objects,
+                                       uint32_t max_aio,
+                                       boost::asio::yield_context yield)
+{
+  auto group = ceph::async::spawn_throttle{yield, max_aio};
+
+  for (const auto& object : objects) {
+    group.spawn([this, &object] (boost::asio::yield_context yield) {
+                  handle_individual_object(object, yield);
+                });
+
+    rgw_flush_formatter(s, s->formatter);
+  }
+  group.wait();
+}
+
 void RGWDeleteMultiObj::execute(optional_yield y)
 {
   const char* buf = data.c_str();
@@ -7710,16 +7726,25 @@ void RGWDeleteMultiObj::execute(optional_yield y)
 
   // process up to max_aio object deletes in parallel
   const uint32_t max_aio = std::max<uint32_t>(1, s->cct->_conf->rgw_multi_obj_del_max_aio);
-  auto group = ceph::async::spawn_throttle{y, max_aio};
 
-  for (const auto& object : multi_delete->objects) {
-    group.spawn([this, &object] (boost::asio::yield_context yield) {
-                  handle_individual_object(object, yield);
-                });
-
-    rgw_flush_formatter(s, s->formatter);
+  // if we're not already running in a coroutine, spawn one
+  if (!y) {
+    auto& objects = multi_delete->objects;
+
+    boost::asio::io_context context;
+    boost::asio::spawn(context,
+        [this, &objects, max_aio] (boost::asio::yield_context yield) {
+          handle_objects(objects, max_aio, yield);
+        },
+        [] (std::exception_ptr eptr) {
+          if (eptr) std::rethrow_exception(eptr);
+        });
+    context.run();
+  } else {
+    // use the existing coroutine's yield context
+    handle_objects(multi_delete->objects, max_aio,
+                   y.get_yield_context());
   }
-  group.wait();
 
   /*  set the return code to zero, errors at this point will be
   dumped to the response */
index eb79bb9b8a6074b15d32289ec5e86305807ce7d7..35d7fb637eed6afff32d6b56229e96e3b136bf57 100644 (file)
@@ -2178,6 +2178,9 @@ class RGWDeleteMultiObj : public RGWOp {
    */
   void handle_individual_object(const RGWMultiDelObject& object, optional_yield y);
 
+  void handle_objects(const std::vector<RGWMultiDelObject>& objects,
+                      uint32_t max_aio, boost::asio::yield_context yield);
+
 protected:
   std::vector<delete_multi_obj_entry> ops_log_entries;
   bufferlist data;