]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
osd: Use coroutines to perform synchronous reads in EC without blocking any threads 67079/head
authorMatty Williams <Matty.Williams@ibm.com>
Fri, 1 May 2026 11:08:30 +0000 (12:08 +0100)
committerMatty Williams <Matty.Williams@ibm.com>
Tue, 5 May 2026 15:35:31 +0000 (16:35 +0100)
Coroutines.h file added containing type and struct definitions.
Coroutine spawned in PrimaryLogPG::do_op if the message contains a CEPH_OSD_OP_CALL op.
ECBackend::objects_read_sync yields while running ECBackend::objects_read_async. Coroutine is resumed once the read is complete.
When a coroutine op is being processed, all other ops to the same PG are blocked.

Fixes: https://tracker.ceph.com/issues/74531
Signed-off-by: Matty Williams <Matty.Williams@ibm.com>
19 files changed:
src/CMakeLists.txt
src/osd/CMakeLists.txt
src/osd/Coroutines.h [new file with mode: 0644]
src/osd/ECBackend.cc
src/osd/ECBackend.h
src/osd/ECBackendL.cc
src/osd/ECBackendL.h
src/osd/ECSwitch.h
src/osd/OpRequest.h
src/osd/PGBackend.h
src/osd/PrimaryLogPG.cc
src/osd/PrimaryLogPG.h
src/osd/ReplicatedBackend.cc
src/osd/ReplicatedBackend.h
src/osd/osd_op_util.cc
src/osd/osd_op_util.h
src/test/osd/MockPGBackend.h
src/test/osd/PGBackendTestFixture.cc
src/test/osd/TestBackendBasics.cc

index e323eb92cda250056fa8222f5073e4ff93d3941f..de3443fbd4fae13cdad9642765a5fff6dc7d56e3 100644 (file)
@@ -597,6 +597,7 @@ set(ceph_common_deps
   common_utf8 extblkdev arch crc32
   ${LIB_RESOLV}
   Boost::thread
+  Boost::context
   Boost::random
   Boost::program_options
   Boost::date_time
index 9dc832a94060309f47f7189b87dd5f24557e91c5..1d0cc271127349641a109d3d1d81636592e6d454 100644 (file)
@@ -52,6 +52,7 @@ set(osd_srcs
   ECUtil.cc
   ECInject.cc
   ECInject.h
+  Coroutines.h
   ${CMAKE_SOURCE_DIR}/src/common/TrackedOp.cc
   ${CMAKE_SOURCE_DIR}/src/mgr/OSDPerfMetricTypes.cc
   ${osd_cyg_functions_src}
diff --git a/src/osd/Coroutines.h b/src/osd/Coroutines.h
new file mode 100644 (file)
index 0000000..e3bbb0b
--- /dev/null
@@ -0,0 +1,33 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*-
+// vim: ts=8 sw=2 sts=2 expandtab
+
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2026 IBM
+ *
+ * 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.
+ */
+
+/*
+ * This header file contains types required to integrate boost coroutines into
+ * the OSD backend.
+ *
+ * - yield_token_t (pull_type): Is used by a coroutine to suspend execution (yield)
+ * while waiting for an I/O operation to complete.
+ * - resume_token_t (push_type): Is used by the completion callback to
+ */
+
+#pragma once
+#include <boost/coroutine2/all.hpp>
+
+using yield_token_t = boost::coroutines2::coroutine<void>::pull_type;
+using resume_token_t = boost::coroutines2::coroutine<void>::push_type;
+
+struct CoroHandles {
+  yield_token_t& yield;
+  resume_token_t& resume;
+};
\ No newline at end of file
index 36b16f47b9dcc4e7ae6a1df6bb4de70515eb28d6..a9f3ce4af195ecf0a44cdeb771d5514230eb8e32 100644 (file)
@@ -1004,6 +1004,38 @@ void ECBackend::submit_transaction(
 }
 
 int ECBackend::objects_read_sync(
+  const hobject_t &hoid,
+  uint64_t object_size,
+  const std::list<std::pair<ec_align_t,
+  std::pair<ceph::buffer::list*, Context*>>> &to_read,
+  CoroHandles coro)
+{
+  int result = 0;
+  bool done = false;
+  bool waiting = false;
+
+  // Callback for the async read
+  Context *on_finish = new LambdaContext([&, coro](int r) {
+    result = r;
+    done = true;
+
+    if (waiting) {
+      coro.resume();
+    }
+  });
+
+  objects_read_async(hoid, object_size, to_read, on_finish, true);
+
+  // If the async read is not yet complete, yield and wait for it to complete
+  if (!done) {
+    waiting = true;
+    coro.yield();
+  }
+
+  return result;
+}
+
+int ECBackend::objects_read_local(
     const hobject_t &hoid,
     uint64_t off,
     uint64_t len,
index 0068dfec01c2ee67447dc806a137e4929f227b60..fbc74d2febc84f50c743bf7bcfd4e05f40c6c7d5 100644 (file)
@@ -28,6 +28,7 @@
 #include "erasure-code/ErasureCodeInterface.h"
 #include "include/buffer.h"
 #include "osd/scrubber/scrub_backend.h"
+#include "Coroutines.h"
 
 /* This file is soon going to be replaced (before next release), so we are going
  * to simply ignore all deprecated warnings.
@@ -131,12 +132,20 @@ class ECBackend : public ECCommon {
     );
 
   int objects_read_sync(
-      const hobject_t &hoid,
-      uint64_t off,
-      uint64_t len,
-      uint32_t op_flags,
-      ceph::buffer::list *bl
-    );
+    const hobject_t &hoid,
+    uint64_t object_size,
+    const std::list<std::pair<ec_align_t,
+    std::pair<ceph::buffer::list*, Context*>>> &to_read,
+    CoroHandles coro
+  );
+
+  int objects_read_local(
+    const hobject_t &hoid,
+    uint64_t off,
+    uint64_t len,
+    uint32_t op_flags,
+    ceph::buffer::list *bl
+  );
 
   std::pair<uint64_t, uint64_t> extent_to_shard_extent(uint64_t off, uint64_t len);
 
index 3e0183eb54751ac6f431eeaa0c12c01c433a2992..487c7d53d597b899dd5180a11174e41d583599f8 100644 (file)
@@ -1562,7 +1562,7 @@ void ECBackendL::submit_transaction(
   rmw_pipeline.start_rmw(std::move(op));
 }
 
-int ECBackendL::objects_read_sync(
+int ECBackendL::objects_read_local(
   const hobject_t &hoid,
   uint64_t off,
   uint64_t len,
index f560b42a7c99c0fe558cca4ea8168a8372f3c81e..4a9d22062a0267677f8d8391be44b089211b6f16 100644 (file)
@@ -117,7 +117,7 @@ public:
     OpRequestRef op
     );
 
-  int objects_read_sync(
+  int objects_read_local(
     const hobject_t &hoid,
     uint64_t off,
     uint64_t len,
index 641e939eddee619af4e0c322152d652abd75f7dc..100b1c38aa07c31abd14b104117192acd84b5b03 100644 (file)
@@ -259,12 +259,27 @@ public:
   }
 
   int objects_read_sync(const hobject_t &hoid, uint64_t off, uint64_t len,
-                        uint32_t op_flags, ceph::buffer::list *bl) override
+                        uint32_t op_flags, ceph::buffer::list *bl, uint64_t object_size,
+                        std::optional<CoroHandles> coro) override
+  {
+    // Sync reads are only supported in FastEC, and from a coroutine
+    if (!is_optimized() || !coro.has_value()) {
+      return -EOPNOTSUPP;
+    }
+
+    ec_align_t align{off, len, op_flags};
+    std::list<std::pair<ec_align_t, std::pair<bufferlist*, Context*>>> to_read;
+    to_read.push_back({ align, { bl, nullptr } });
+    return optimized.objects_read_sync(hoid, object_size, to_read, *coro);
+  }
+
+  int objects_read_local(const hobject_t &hoid, uint64_t off, uint64_t len,
+                      uint32_t op_flags, ceph::buffer::list *bl) override
   {
     if (is_optimized()) {
-      return optimized.objects_read_sync(hoid, off, len, op_flags, bl);
+      return optimized.objects_read_local(hoid, off, len, op_flags, bl);
     }
-    return legacy.objects_read_sync(hoid, off, len, op_flags, bl);
+    return legacy.objects_read_local(hoid, off, len, op_flags, bl);
   }
 
   int objects_readv_sync(const hobject_t &hoid,
index 57304f9e3a9a64cef17a5602f731e6d8f71adee6..6a63442d54a7daef84fe73cd0bf48757ed34cce2 100644 (file)
@@ -19,6 +19,8 @@
 #include "osd/osd_types.h"
 #include "common/TrackedOp.h"
 #include "common/tracer.h"
+#include "osd/Coroutines.h"
+
 /**
  * The OpRequest takes in a Message* and takes over a single reference
  * to it, which it puts() when destroyed.
@@ -30,6 +32,8 @@ private:
   OpInfo op_info;
 
 public:
+  std::optional<CoroHandles> coro_handles = std::nullopt;
+
   int maybe_init_op_info(const OSDMap &osdmap);
 
   auto get_flags() const { return op_info.get_flags(); }
@@ -51,6 +55,8 @@ public:
   bool allows_returnvec() const { return op_info.allows_returnvec(); }
   bool ec_direct_read() const { return op_info.ec_direct_read(); }
   void set_ec_direct_read() { return op_info.set_ec_direct_read(); }
+  bool ec_sync_read() const { return op_info.ec_sync_read(); }
+  void set_ec_sync_read() { return op_info.set_ec_sync_read(); }
 
   std::vector<OpInfo::ClassInfo> classes() const {
     return op_info.get_classes();
index a3110b6fe559353ffe4a5e622e07a0faf161e49e..d681c36b53c251ebb4f078f960522221bee696e9 100644 (file)
@@ -33,6 +33,7 @@
 #include <string>
 #include "PGTransaction.h"
 #include "common/ostream_temp.h"
+#include "Coroutines.h"
 
 namespace Scrub {
   class Store;
@@ -600,7 +601,17 @@ typedef std::shared_ptr<const OSDMap> OSDMapRef;
      uint64_t off,
      uint64_t len,
      uint32_t op_flags,
-     ceph::buffer::list *bl) = 0;
+     ceph::buffer::list *bl,
+     uint64_t object_size,
+     std::optional<CoroHandles> coro
+   ) = 0;
+
+   virtual int objects_read_local(
+      const hobject_t &hoid,
+      uint64_t off,
+      uint64_t len,
+      uint32_t op_flags,
+      ceph::buffer::list *bl) = 0;
 
    virtual int objects_readv_sync(
      const hobject_t &hoid,
index 7f69f63ea618e3b009e8553eb2b3aed8d31cd83a..c40a1deaa39eac7678a3caa7394ec6a56c6a2656 100644 (file)
@@ -1983,24 +1983,24 @@ void PrimaryLogPG::do_request(
   }
 }
 
-/** do_op - do an op
- * pg lock will be held (if multithreaded)
- * osd_lock NOT held.
- */
-void PrimaryLogPG::do_op(OpRequestRef& op)
+bool PrimaryLogPG::should_use_coroutine(MOSDOp* m)
 {
-  FUNCTRACE(cct);
-  // NOTE: take a non-const pointer here; we must be careful not to
-  // change anything that will break other reads on m (operator<<).
-  MOSDOp *m = static_cast<MOSDOp*>(op->get_nonconst_req());
-  ceph_assert(m->get_type() == CEPH_MSG_OSD_OP);
-  if (m->finish_decode()) {
-    op->reset_desc();   // for TrackedOp
-    m->clear_payload();
+  if (!pool.info.allows_ecoptimizations()) {
+    return false;
   }
 
-  dout(20) << __func__ << ": op " << *m << dendl;
+  for (const auto& osd_op : m->ops) {
+    if (osd_op.op.op == CEPH_OSD_OP_CALL) {
+      return true;
+    }
+  }
+
+  return false;
+}
 
+void PrimaryLogPG::do_op_impl(OpRequestRef op)
+{
+  MOSDOp *m = static_cast<MOSDOp*>(op->get_nonconst_req());
   const hobject_t head = m->get_hobj().get_head();
 
   if (!info.pgid.pgid.contains(
@@ -2489,6 +2489,10 @@ void PrimaryLogPG::do_op(OpRequestRef& op)
 
   OpContext *ctx = new OpContext(op, m->get_reqid(), &m->ops, obc, this);
 
+  if (coro_op_in_flight && op == active_coro_op) {
+    active_coro_ctx = ctx;
+  }
+
   if (m->has_flag(CEPH_OSD_FLAG_SKIPRWLOCKS)) {
     dout(20) << __func__ << ": skipping rw locks" << dendl;
   } else if (m->get_flags() & CEPH_OSD_FLAG_FLUSH) {
@@ -2567,6 +2571,75 @@ void PrimaryLogPG::do_op(OpRequestRef& op)
   maybe_force_recovery();
 }
 
+/** do_op - do an op
+ * pg lock will be held (if multithreaded)
+ * osd_lock NOT held.
+ */
+void PrimaryLogPG::do_op(OpRequestRef& op)
+{
+  FUNCTRACE(cct);
+  MOSDOp *m = static_cast<MOSDOp*>(op->get_nonconst_req());
+  ceph_assert(m->get_type() == CEPH_MSG_OSD_OP);
+  if (m->finish_decode()) {
+    op->reset_desc();
+    m->clear_payload();
+  }
+
+  if (coro_op_in_flight) {
+    dout(20) << __func__ << ": coroutine op in flight, queuing " << op << dendl;
+    waiting_for_coro_op.push_back(op);
+    return;
+  }
+
+  dout(20) << __func__ << ": op " << *m << dendl;
+
+  if (should_use_coroutine(m)) {
+    dout(20) << __func__ << ": spawning a coroutine for EC optimized CALL op" << dendl;
+    coro_op_in_flight = true;
+    active_coro_op = op;
+    OpRequest* op_raw = op.get();
+
+    // Spawn a coroutine to handle the message
+    auto resumer = std::make_unique<resume_token_t>(
+      [this, op_raw](yield_token_t& yield) {
+        op_raw->coro_handles.emplace(CoroHandles{ yield, *coro_resumer });
+        {
+          const OpRequestRef op_ref(op_raw);
+          do_op_impl(op_ref);
+        }
+
+        // Cleanup
+        coro_resumer = nullptr;
+        on_coroutine_complete();
+      });
+
+    coro_resumer = std::move(resumer);
+
+    // Startup the coroutine
+    (*coro_resumer)();
+  } else {
+    // Handle the message directly in the current thread
+    do_op_impl(op);
+  }
+}
+
+void PrimaryLogPG::on_coroutine_complete()
+{
+  ceph_assert(coro_op_in_flight);
+  coro_op_in_flight = false;
+  active_coro_op = nullptr;
+
+  if (active_coro_ctx) {
+    dout(20) << __func__ << ": Warning - OpContext not cleaned up normally" << dendl;
+    active_coro_ctx = nullptr;
+  }
+
+  if (!waiting_for_coro_op.empty()) {
+    dout(20) << __func__ << ": requeuing " << waiting_for_coro_op.size() << " ops" << dendl;
+    requeue_ops(waiting_for_coro_op);
+  }
+}
+
 PrimaryLogPG::cache_result_t PrimaryLogPG::maybe_handle_manifest_detail(
   OpRequestRef op,
   bool write_ordered,
@@ -4433,6 +4506,11 @@ void PrimaryLogPG::close_op_ctx(OpContext *ctx) {
        ctx->on_finish.erase(p++)) {
     (*p)();
   }
+
+  if (ctx == active_coro_ctx) {
+    active_coro_ctx = nullptr;
+  }
+
   delete ctx;
 }
 
@@ -5894,10 +5972,14 @@ int PrimaryLogPG::do_read(OpContext *ctx, OSDOp& osd_op) {
       maybe_crc = oi.data_digest;
 
     if (ctx->op->ec_direct_read()) {
-      result = pgbackend->objects_read_sync(
+      result = pgbackend->objects_read_local(
         soid, op.extent.offset, op.extent.length, op.flags, &osd_op.outdata);
-
-        dout(20) << " EC sync read for " << soid << " result=" << result << dendl;
+      dout(20) << " EC local read for " << soid << " result=" << result << dendl;
+    } else if (ctx->op->ec_sync_read()) {
+      result = pgbackend->objects_read_sync(
+        soid, op.extent.offset, op.extent.length, op.flags, &osd_op.outdata,
+        oi.size, ctx->op->coro_handles);
+      dout(20) << " EC sync read for " << soid << " result=" << result << dendl;
     } else {
     ctx->pending_async_reads.push_back(
       make_pair(
@@ -5913,7 +5995,8 @@ int PrimaryLogPG::do_read(OpContext *ctx, OSDOp& osd_op) {
     }
   } else {
     int r = pgbackend->objects_read_sync(
-      soid, op.extent.offset, op.extent.length, op.flags, &osd_op.outdata);
+      soid, op.extent.offset, op.extent.length, op.flags, &osd_op.outdata,
+      oi.size, ctx->op->coro_handles);
     // whole object?  can we verify the checksum?
     if (r >= 0 && op.extent.offset == 0 &&
         (uint64_t)r == oi.size && oi.is_data_digest()) {
@@ -6148,9 +6231,11 @@ int PrimaryLogPG::do_osd_ops(OpContext *ctx, vector<OSDOp>& ops)
       break;
 
     case CEPH_OSD_OP_SYNC_READ:
-      if (pool.info.is_erasure()) {
+      if (pool.info.is_erasure() && !pool.info.allows_ecoptimizations()) {
        result = -EOPNOTSUPP;
        break;
+      } else if (pool.info.is_erasure() && pool.info.allows_ecoptimizations()) {
+        ctx->op->set_ec_sync_read();
       }
       // fall through
     case CEPH_OSD_OP_READ:
@@ -9399,8 +9484,9 @@ int PrimaryLogPG::do_copy_get(OpContext *ctx, bufferlist::const_iterator& bp,
 
        dout(10) << __func__ << ": async_read noted for " << soid << dendl;
       } else {
-       result = pgbackend->objects_read_sync(
-         oi.soid, cursor.data_offset, max_read, osd_op.op.flags, &bl);
+ result = pgbackend->objects_read_sync(
+   oi.soid, cursor.data_offset, max_read, osd_op.op.flags, &bl,
+   oi.size, ctx->op->coro_handles);
        if (result < 0)
          return result;
       }
@@ -10710,7 +10796,7 @@ int PrimaryLogPG::do_cdc(const object_info_t& oi,
    * As s result, we leave this as a future work.
    */
   int r = pgbackend->objects_read_sync(
-      oi.soid, 0, oi.size, 0, &bl);
+      oi.soid, 0, oi.size, 0, &bl, oi.size, std::nullopt);
   if (r < 0) {
     dout(0) << __func__ << " read fail " << oi.soid
             << " len: " << oi.size << " r: " << r << dendl;
@@ -13147,6 +13233,26 @@ void PrimaryLogPG::on_change(ObjectStore::Transaction &t)
 {
   dout(10) << __func__ << dendl;
 
+  if (coro_resumer != nullptr) {
+    dout(20) << __func__ << ": Stopping active coroutine" << dendl;
+    if (active_coro_ctx) {
+      dout(20) << __func__ << ": Cleaning up orphaned OpContext from coroutine" << dendl;
+      // Remove from in_progress_async_reads if present
+      for (auto it = in_progress_async_reads.begin();
+          it != in_progress_async_reads.end(); ++it) {
+        if (it->second == active_coro_ctx) {
+          in_progress_async_reads.erase(it);
+          break;
+        }
+      }
+      // Close the context to release all resources
+      close_op_ctx(active_coro_ctx);
+      active_coro_ctx = nullptr;
+    }
+    coro_resumer = nullptr;
+    coro_op_in_flight = false;
+  }
+
   if (hit_set && hit_set->insert_count() == 0) {
     dout(20) << " discarding empty hit_set" << dendl;
     hit_set_clear();
@@ -13163,6 +13269,11 @@ void PrimaryLogPG::on_change(ObjectStore::Transaction &t)
   requeue_ops(waiting_for_flush);
   requeue_ops(waiting_for_active);
   requeue_ops(waiting_for_readable);
+  requeue_ops(waiting_for_coro_op);
+  if (active_coro_op) {
+    requeue_op(active_coro_op);
+    active_coro_op = nullptr;
+  }
 
   vector<ceph_tid_t> tids;
   cancel_copy_ops(is_primary(), &tids);
index b01472c09bbb729b13290b1985e9b7c62b32ee64..8e0b29f72bccf35ea7ad181f83528c79b97bbec4 100644 (file)
@@ -34,6 +34,7 @@
 #include "ReplicatedBackend.h"
 #include "PGTransaction.h"
 #include "cls/cas/cls_cas_ops.h"
+#include "Coroutines.h"
 
 class CopyFromCallback;
 class PromoteCallback;
@@ -937,6 +938,12 @@ public:
 
 protected:
 
+  OpRequestRef active_coro_op = nullptr;
+  std::unique_ptr<resume_token_t> coro_resumer = nullptr;
+  bool coro_op_in_flight = false;
+  std::list<OpRequestRef> waiting_for_coro_op;
+  OpContext* active_coro_ctx = nullptr;
+
   /**
    * Grabs locks for OpContext, should be cleaned up in close_op_ctx
    *
@@ -1562,7 +1569,10 @@ public:
   void do_request(
     OpRequestRef& op,
     ThreadPool::TPHandle &handle) override;
+  bool should_use_coroutine(MOSDOp* m);
+  void do_op_impl(OpRequestRef op);
   void do_op(OpRequestRef& op);
+  void on_coroutine_complete();
   void record_write_error(OpRequestRef op, const hobject_t &soid,
                          MOSDOpReply *orig_reply, int r,
                          OpContext *ctx_for_op_returns=nullptr);
index df7a056d570cf94bd598234e560fd5949bfdf3bc..06bde7f24186c06970ce076898465d074f09c422 100644 (file)
@@ -277,6 +277,18 @@ void ReplicatedBackend::on_change()
 }
 
 int ReplicatedBackend::objects_read_sync(
+  const hobject_t &hoid,
+  uint64_t off,
+  uint64_t len,
+  uint32_t op_flags,
+  bufferlist *bl,
+  uint64_t object_size,
+  std::optional<CoroHandles> coro)
+{
+  return store->read(ch, ghobject_t(hoid), off, len, *bl, op_flags);
+}
+
+int ReplicatedBackend::objects_read_local(
   const hobject_t &hoid,
   uint64_t off,
   uint64_t len,
index 4ce6c3aa34e13e18c626f80106b7e76fe6a65656..da06b20face92e0560e26bd5a2c0f585715465f5 100644 (file)
@@ -139,7 +139,17 @@ public:
     uint64_t off,
     uint64_t len,
     uint32_t op_flags,
-    ceph::buffer::list *bl) override;
+    ceph::buffer::list *bl,
+    uint64_t object_size,
+    std::optional<CoroHandles> coro
+  ) override;
+
+  int objects_read_local(
+   const hobject_t &hoid,
+   uint64_t off,
+   uint64_t len,
+   uint32_t op_flags,
+   ceph::buffer::list *bl) override;
 
   int objects_readv_sync(
     const hobject_t &hoid,
index 1bf4945e05128e6ecdca7ec8210595885ebfe23a..b40dcab3050237dca307de29cfc2399c89bf21d2 100644 (file)
@@ -55,6 +55,9 @@ bool OpInfo::allows_returnvec() const {
 bool OpInfo::ec_direct_read() const {
   return check_rmw(CEPH_OSD_RMW_FLAG_EC_DIRECT_READ);
 }
+bool OpInfo::ec_sync_read() const {
+  return check_rmw(CEPH_OSD_RMW_FLAG_EC_SYNC_READ);
+}
 /**
  * may_read_data()
  * 
@@ -94,6 +97,7 @@ void OpInfo::set_force_rwordered() { set_rmw_flags(CEPH_OSD_RMW_FLAG_RWORDERED);
 void OpInfo::set_returnvec() { set_rmw_flags(CEPH_OSD_RMW_FLAG_RETURNVEC); }
 void OpInfo::set_read_data() { set_rmw_flags(CEPH_OSD_RMW_FLAG_READ_DATA); }
 void OpInfo::set_ec_direct_read() { set_rmw_flags(CEPH_OSD_RMW_FLAG_EC_DIRECT_READ); }
+void OpInfo::set_ec_sync_read() { set_rmw_flags(CEPH_OSD_RMW_FLAG_EC_SYNC_READ); }
 
 
 int OpInfo::set_from_op(
index 5a9ea77c9666a843ec94b5cb0dc8f0a75295c28b..b089f2cfbae9b044089afc65825e974fa2fba0df 100644 (file)
@@ -61,6 +61,7 @@ public:
   bool need_skip_promote() const;
   bool allows_returnvec() const;
   bool ec_direct_read() const;
+  bool ec_sync_read() const;
 
   void set_read();
   void set_write();
@@ -75,6 +76,7 @@ public:
   void set_returnvec();
   void set_read_data();
   void set_ec_direct_read();
+  void set_ec_sync_read();
 
   int set_from_op(
     const MOSDOp *m,
index a5834bd766d92c5e2b572c235b2669653ad6f8a6..f2d66a4f3f4c44af38ad0cabe06e11552f5e89e2 100644 (file)
@@ -116,11 +116,23 @@ public:
 
   // Object operations
   int objects_read_sync(
-    const hobject_t &hoid,
-    uint64_t off,
-    uint64_t len,
-    uint32_t op_flags,
-    ceph::buffer::list *bl) override {
+     const hobject_t &hoid,
+     uint64_t off,
+     uint64_t len,
+     uint32_t op_flags,
+     ceph::buffer::list *bl,
+     uint64_t object_size,
+     std::optional<CoroHandles> coro
+     ) override {
+    return 0;
+  }
+
+  int objects_read_local(
+     const hobject_t &hoid,
+     uint64_t off,
+     uint64_t len,
+     uint32_t op_flags,
+     ceph::buffer::list *bl) override {
     return 0;
   }
 
index 39b1fc9a3c1e4c79db35e7238007355cfb703d2f..a877769e778d03e7007cdfa3096118a8b291bb5e 100644 (file)
@@ -638,7 +638,7 @@ int PGBackendTestFixture::read_object(
     ReplicatedBackend* rep_backend = dynamic_cast<ReplicatedBackend*>(primary_backend);
     ceph_assert(rep_backend != nullptr);
 
-    int result = rep_backend->objects_read_sync(
+    int result = rep_backend->objects_read_local(
       hoid,
       offset,
       length,
index 2fae5b6da5affe98ba8dd14eb0eab3d613eec6ab..d8389db792de7f6694e42d025de2ae0893aa78db 100644 (file)
@@ -343,7 +343,7 @@ TEST_P(TestBackendBasics, DirectRead) {
     
     // Perform sync read with EC_DIRECT_READ flag
     // Read the entire stripe - we expect only this shard's data back
-    int read_result = ec_switch->objects_read_sync(
+    int read_result = ec_switch->objects_read_local(
       hoid,
       0,                                    // offset
       stripe_width,                         // length (full stripe)