]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
crimson/osd: implement ObjectContext relocking.
authorRadoslaw Zarzynski <rzarzyns@redhat.com>
Mon, 29 Mar 2021 16:01:47 +0000 (16:01 +0000)
committerRadoslaw Zarzynski <rzarzyns@redhat.com>
Mon, 10 May 2021 16:01:32 +0000 (18:01 +0200)
This commit introduces a `ObjectContext`-taking variant of
`PG::with_locked_obc()`. The upcoming internal counterpart
for the `ClientRequest` is the intended audience.

Signed-off-by: Radoslaw Zarzynski <rzarzyns@redhat.com>
src/crimson/osd/object_context.h
src/crimson/osd/pg.cc
src/crimson/osd/pg.h

index 99285d735eb95dc9edc2bbedb34105985a4fe2f4..f1613564e8c1bf33f8e36c2bb58a43f012a76f54 100644 (file)
@@ -59,6 +59,14 @@ public:
     return get_oid().is_head();
   }
 
+  Ref get_head_obc() const {
+    return head;
+  }
+
+  hobject_t get_head_oid() const {
+    return get_oid().get_head();
+  }
+
   const SnapSet &get_ro_ss() const {
     if (is_head()) {
       ceph_assert(ss);
index 298f5223a7f516aea2d900d993dcd8ee73bd4f54..1b52c2067bc9cb8e6d20797f319819d0e96038fe 100644 (file)
@@ -857,13 +857,10 @@ std::optional<hobject_t> PG::resolve_oid(
 
 template<RWState::State State>
 PG::load_obc_iertr::future<>
-PG::with_head_obc(hobject_t oid, with_obc_func_t&& func)
+PG::with_head_obc(ObjectContextRef obc, bool existed, with_obc_func_t&& func)
 {
-  logger().debug("{} {}", __func__, oid);
-  boost::intrusive_ptr<PG> pgref{this};
-  assert(oid.is_head());
-  auto [obc, existed] =
-    shard_services.obc_registry.get_cached_obc(std::move(oid));
+  logger().debug("{} {}", __func__, obc->get_oid());
+  assert(obc->is_head());
   obc->append_to(obc_set_accessing);
   return obc->with_lock<State, IOInterruptCondition>(
     [existed=existed, obc=obc, func=std::move(func), this] {
@@ -879,12 +876,31 @@ PG::with_head_obc(hobject_t oid, with_obc_func_t&& func)
     return loaded.safe_then_interruptible([func = std::move(func)](auto obc) {
       return std::move(func)(std::move(obc));
     });
-  }).finally([this, pgref, obc=std::move(obc)] {
+  }).finally([this, pgref=boost::intrusive_ptr<PG>{this}, obc=std::move(obc)] {
     logger().debug("with_head_obc: released {}", obc->get_oid());
     obc->remove_from(obc_set_accessing);
   });
 }
 
+template<RWState::State State>
+PG::load_obc_iertr::future<>
+PG::with_head_obc(hobject_t oid, with_obc_func_t&& func)
+{
+  auto [obc, existed] =
+    shard_services.obc_registry.get_cached_obc(std::move(oid));
+  return with_head_obc<State>(std::move(obc), existed, std::move(func));
+}
+
+template<RWState::State State>
+PG::interruptible_future<>
+PG::with_existing_head_obc(ObjectContextRef obc, with_obc_func_t&& func)
+{
+  constexpr bool existed = true;
+  return with_head_obc<State>(
+    std::move(obc), existed, std::move(func)
+  ).handle_error_interruptible(load_obc_ertr::assert_all{"can't happen"});
+}
+
 template<RWState::State State>
 PG::load_obc_iertr::future<>
 PG::with_clone_obc(hobject_t oid, with_obc_func_t&& func)
@@ -928,6 +944,23 @@ PG::with_clone_obc(hobject_t oid, with_obc_func_t&& func)
 template PG::load_obc_iertr::future<>
 PG::with_head_obc<RWState::RWNONE>(hobject_t, with_obc_func_t&&);
 
+template<RWState::State State>
+PG::interruptible_future<>
+PG::with_existing_clone_obc(ObjectContextRef clone, with_obc_func_t&& func)
+{
+  assert(clone);
+  assert(clone->get_head_obc());
+  assert(!clone->get_oid().is_head());
+  return with_existing_head_obc<RWState::RWREAD>(clone->get_head_obc(),
+    [clone=std::move(clone), func=std::move(func)] ([[maybe_unused]] auto head) {
+    assert(head == clone->get_head_obc());
+    return clone->template with_lock<State>(
+      [clone=std::move(clone), func=std::move(func)] {
+      std::move(func)(std::move(clone));
+    });
+  });
+}
+
 PG::load_obc_iertr::future<crimson::osd::ObjectContextRef>
 PG::load_head_obc(ObjectContextRef obc)
 {
@@ -1007,6 +1040,26 @@ PG::with_locked_obc(Ref<MOSDOp> &m, const OpInfo &op_info,
   };
 }
 
+template <RWState::State State>
+PG::interruptible_future<>
+PG::with_locked_obc(ObjectContextRef obc, PG::with_obc_func_t &&f)
+{
+  // TODO: a question from rebase: do we really need such checks when
+  // the interruptible stuff is being used?
+  if (__builtin_expect(stopping, false)) {
+    throw crimson::common::system_shutdown_exception();
+  }
+  if (obc->is_head()) {
+    return with_existing_head_obc<State>(obc, std::move(f));
+  } else {
+    return with_existing_clone_obc<State>(obc, std::move(f));
+  }
+}
+
+// explicitly instantiate the used instantiations
+template PG::interruptible_future<>
+PG::with_locked_obc<RWState::RWEXCL>(ObjectContextRef, with_obc_func_t&&);
+
 PG::interruptible_future<> PG::handle_rep_op(Ref<MOSDRepOp> req)
 {
   if (__builtin_expect(stopping, false)) {
index f633f89636c777336ef8e8205bc904108a47c0c5..9de11f7dda9e47a9250f1ebc77c1e2bdb6350c5f 100644 (file)
@@ -517,6 +517,10 @@ public:
   template<RWState::State State>
   load_obc_iertr::future<> with_head_obc(hobject_t oid, with_obc_func_t&& func);
 
+  template<RWState::State State>
+  interruptible_future<> with_locked_obc(
+    ObjectContextRef obc,
+    with_obc_func_t&& f);
   load_obc_iertr::future<> with_locked_obc(
     Ref<MOSDOp> &m,
     const OpInfo &op_info,
@@ -530,8 +534,21 @@ public:
   void dump_primary(Formatter*);
 
 private:
+  template<RWState::State State>
+  load_obc_iertr::future<> with_head_obc(
+    ObjectContextRef obc,
+    bool existed,
+    with_obc_func_t&& func);
+  template<RWState::State State>
+  interruptible_future<> with_existing_head_obc(
+    ObjectContextRef head,
+    with_obc_func_t&& func);
+
   template<RWState::State State>
   load_obc_iertr::future<> with_clone_obc(hobject_t oid, with_obc_func_t&& func);
+  template<RWState::State State>
+  interruptible_future<> with_existing_clone_obc(
+    ObjectContextRef clone, with_obc_func_t&& func);
 
   load_obc_iertr::future<ObjectContextRef> get_locked_obc(
     Operation *op,