summaryrefslogtreecommitdiffstats
path: root/src/crimson/osd/object_context_loader.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/crimson/osd/object_context_loader.cc')
-rw-r--r--src/crimson/osd/object_context_loader.cc322
1 files changed, 139 insertions, 183 deletions
diff --git a/src/crimson/osd/object_context_loader.cc b/src/crimson/osd/object_context_loader.cc
index 12aa40b925a..483251a23b5 100644
--- a/src/crimson/osd/object_context_loader.cc
+++ b/src/crimson/osd/object_context_loader.cc
@@ -1,3 +1,4 @@
+#include "crimson/common/coroutine.h"
#include "crimson/osd/object_context_loader.h"
#include "osd/osd_types_fmt.h"
#include "osd/object_state_fmt.h"
@@ -8,207 +9,162 @@ namespace crimson::osd {
using crimson::common::local_conf;
- template<RWState::State State>
- ObjectContextLoader::load_obc_iertr::future<>
- ObjectContextLoader::with_head_obc(const hobject_t& oid,
- with_obc_func_t&& func)
- {
- return with_locked_obc<State, true /* track */>(
- oid,
- [func=std::move(func)](auto obc) {
- // The template with_obc_func_t wrapper supports two obcs (head and clone).
- // In the 'with_head_obc' case, however, only the head is in use.
- // Pass the same head obc twice in order to
- // to support the generic with_obc sturcture.
- return std::invoke(std::move(func), obc, obc);
- });
+
+ObjectContextLoader::load_and_lock_fut
+ObjectContextLoader::load_and_lock_head(Manager &manager, RWState::State lock_type)
+{
+ LOG_PREFIX(ObjectContextLoader::load_and_lock_head);
+ DEBUGDPP("{} {}", dpp, manager.target, lock_type);
+ auto releaser = manager.get_releaser();
+ ceph_assert(manager.target.is_head());
+
+ if (manager.head_state.is_empty()) {
+ auto [obc, _] = obc_registry.get_cached_obc(manager.target);
+ manager.set_state_obc(manager.head_state, obc);
+ }
+ ceph_assert(manager.target_state.is_empty());
+ manager.set_state_obc(manager.target_state, manager.head_state.obc);
+
+ if (manager.target_state.obc->loading_started) {
+ co_await manager.target_state.lock_to(lock_type);
+ } else {
+ manager.target_state.lock_excl_sync();
+ manager.target_state.obc->loading_started = true;
+ co_await load_obc(manager.target_state.obc);
+ manager.target_state.demote_excl_to(lock_type);
}
+ releaser.cancel();
+}
+
+ObjectContextLoader::load_and_lock_fut
+ObjectContextLoader::load_and_lock_clone(
+ Manager &manager, RWState::State lock_type, bool lock_head)
+{
+ LOG_PREFIX(ObjectContextLoader::load_and_lock_clone);
+ DEBUGDPP("{} {}", dpp, manager.target, lock_type);
+ auto releaser = manager.get_releaser();
- template<RWState::State State>
- ObjectContextLoader::load_obc_iertr::future<>
- ObjectContextLoader::with_clone_obc(const hobject_t& oid,
- with_obc_func_t&& func,
- bool resolve_clone)
- {
- LOG_PREFIX(ObjectContextLoader::with_clone_obc);
- assert(!oid.is_head());
- return with_head_obc<RWState::RWREAD>(
- oid.get_head(),
- [FNAME, oid, func=std::move(func), resolve_clone, this]
- (auto head, auto) mutable -> load_obc_iertr::future<> {
- if (!head->obs.exists) {
- ERRORDPP("head doesn't exist for object {}", dpp, head->obs.oi.soid);
- return load_obc_iertr::future<>{
- crimson::ct_error::enoent::make()
- };
- }
- return this->with_clone_obc_only<State>(std::move(head),
- oid,
- std::move(func),
- resolve_clone);
- });
+ ceph_assert(!manager.target.is_head());
+ ceph_assert(manager.target_state.is_empty());
+
+ if (manager.head_state.is_empty()) {
+ auto [obc, _] = obc_registry.get_cached_obc(manager.target.get_head());
+ manager.set_state_obc(manager.head_state, obc);
}
- template<RWState::State State>
- ObjectContextLoader::load_obc_iertr::future<>
- ObjectContextLoader::with_clone_obc_only(ObjectContextRef head,
- hobject_t clone_oid,
- with_obc_func_t&& func,
- bool resolve_clone)
- {
- LOG_PREFIX(ObjectContextLoader::with_clone_obc_only);
- DEBUGDPP("{}", dpp, clone_oid);
- assert(!clone_oid.is_head());
- if (resolve_clone) {
- auto resolved_oid = resolve_oid(head->get_head_ss(), clone_oid);
- if (!resolved_oid) {
- ERRORDPP("clone {} not found", dpp, clone_oid);
- return load_obc_iertr::future<>{
- crimson::ct_error::enoent::make()
- };
- }
- if (resolved_oid->is_head()) {
- // See resolve_oid
- return std::move(func)(head, head);
- }
- clone_oid = *resolved_oid;
- }
- return with_locked_obc<State, false /* don't track */>(
- clone_oid,
- [head=std::move(head), func=std::move(func)](auto clone) {
- clone->set_clone_ssc(head->ssc);
- return std::move(func)(std::move(head), std::move(clone));
- });
+ if (!manager.head_state.obc->loading_started) {
+ // caller is responsible for pre-populating a loaded obc if lock_head is
+ // false
+ ceph_assert(lock_head);
+ manager.head_state.lock_excl_sync();
+ manager.head_state.obc->loading_started = true;
+ co_await load_obc(manager.head_state.obc);
+ manager.head_state.demote_excl_to(RWState::RWREAD);
+ } else if (lock_head) {
+ co_await manager.head_state.lock_to(RWState::RWREAD);
}
- template<RWState::State State>
- ObjectContextLoader::load_obc_iertr::future<>
- ObjectContextLoader::with_obc(hobject_t oid,
- with_obc_func_t&& func,
- bool resolve_clone)
- {
- if (oid.is_head()) {
- return with_head_obc<State>(oid, std::move(func));
- } else {
- return with_clone_obc<State>(oid, std::move(func), resolve_clone);
+ if (manager.options.resolve_clone) {
+ auto resolved_oid = resolve_oid(
+ manager.head_state.obc->get_head_ss(),
+ manager.target);
+ if (!resolved_oid) {
+ ERRORDPP("clone {} not found", dpp, manager.target);
+ co_await load_obc_iertr::future<>(
+ crimson::ct_error::enoent::make()
+ );
}
+ // note: might be head if snap was taken after most recent write!
+ manager.target = *resolved_oid;
}
- template<RWState::State State, bool track, typename Func>
- ObjectContextLoader::load_obc_iertr::future<>
- ObjectContextLoader::with_locked_obc(const hobject_t& oid,
- Func&& func)
- {
- LOG_PREFIX(ObjectContextLoader::with_locked_obc);
- auto [obc, existed] = obc_registry.get_cached_obc(oid);
- DEBUGDPP("object {} existed {}",
- dpp, obc->get_oid(), existed);
- if constexpr (track) {
- obc->append_to(obc_set_accessing);
+ if (manager.target.is_head()) {
+ /* Yes, we assert at the top that manager.target is not head. However, it's
+ * possible that the requested snap (the resolve_clone path above) actually
+ * maps to head (a read on an rbd snapshot more recent than the most recent
+ * write on this specific rbd block, for example).
+ *
+ * In such an event, it's hypothetically possible that lock_type isn't
+ * RWREAD, in which case we need to drop and reacquire the lock. However,
+ * this case is at present impossible. Actual client requests cannot write
+ * to a snapshot and will therefore always be RWREAD. The pathways that
+ * actually can mutate a clone do not set resolve_clone, so target will not
+ * become head here.
+ */
+ manager.set_state_obc(manager.target_state, manager.head_state.obc);
+ if (lock_type != manager.head_state.state) {
+ // This case isn't actually possible at the moment for the above reason.
+ manager.head_state.release_lock();
+ co_await manager.target_state.lock_to(lock_type);
+ } else {
+ manager.target_state.state = manager.head_state.state;
+ manager.head_state.state = RWState::RWNONE;
}
- if (existed) {
- return obc->with_lock<State, IOInterruptCondition>(
- [func=std::move(func), obc=ObjectContextRef(obc)] {
- return std::invoke(std::move(func), obc);
- }
- ).finally([FNAME, this, obc=ObjectContextRef(obc)] {
- DEBUGDPP("released object {}, {}", dpp, obc->get_oid(), obc->obs);
- if constexpr (track) {
- obc->remove_from(obc_set_accessing);
- }
- });
+ } else {
+ auto [obc, _] = obc_registry.get_cached_obc(manager.target);
+ manager.set_state_obc(manager.target_state, obc);
+
+ if (manager.target_state.obc->loading_started) {
+ co_await manager.target_state.lock_to(RWState::RWREAD);
} else {
- return obc->load_then_with_lock<State> (
- [this, obc=ObjectContextRef(obc)] {
- return load_obc(obc);
- },
- [func=std::move(func), obc=ObjectContextRef(obc)] {
- return std::invoke(std::move(func), obc);
- }
- ).finally([FNAME, this, obc=ObjectContextRef(obc)] {
- DEBUGDPP("released object {}, {}", dpp, obc->get_oid(), obc->obs);
- if constexpr (track) {
- obc->remove_from(obc_set_accessing);
- }
- });
+ manager.target_state.lock_excl_sync();
+ manager.target_state.obc->loading_started = true;
+ co_await load_obc(manager.target_state.obc);
+ manager.target_state.obc->set_clone_ssc(manager.head_state.obc->ssc);
+ manager.target_state.demote_excl_to(RWState::RWREAD);
}
}
+ releaser.cancel();
+}
+
+ObjectContextLoader::load_and_lock_fut
+ObjectContextLoader::load_and_lock(Manager &manager, RWState::State lock_type)
+{
+ LOG_PREFIX(ObjectContextLoader::load_and_lock);
+ DEBUGDPP("{} {}", dpp, manager.target, lock_type);
+ if (manager.target.is_head()) {
+ return load_and_lock_head(manager, lock_type);
+ } else {
+ return load_and_lock_clone(manager, lock_type);
+ }
+}
- ObjectContextLoader::load_obc_iertr::future<>
- ObjectContextLoader::load_obc(ObjectContextRef obc)
- {
- LOG_PREFIX(ObjectContextLoader::load_obc);
- return backend.load_metadata(obc->get_oid())
+ObjectContextLoader::load_obc_iertr::future<>
+ObjectContextLoader::load_obc(ObjectContextRef obc)
+{
+ LOG_PREFIX(ObjectContextLoader::load_obc);
+ return backend.load_metadata(obc->get_oid())
.safe_then_interruptible(
[FNAME, this, obc=std::move(obc)](auto md)
-> load_obc_ertr::future<> {
- const hobject_t& oid = md->os.oi.soid;
- DEBUGDPP("loaded obs {} for {}", dpp, md->os.oi, oid);
- if (oid.is_head()) {
- if (!md->ssc) {
- ERRORDPP("oid {} missing snapsetcontext", dpp, oid);
- return crimson::ct_error::object_corrupted::make();
- }
- obc->set_head_state(std::move(md->os),
- std::move(md->ssc));
- } else {
- // we load and set the ssc only for head obc.
- // For clones, the head's ssc will be referenced later.
- // See set_clone_ssc
- obc->set_clone_state(std::move(md->os));
- }
- DEBUGDPP("loaded obc {} for {}", dpp, obc->obs.oi, obc->obs.oi.soid);
- return seastar::now();
- });
- }
-
- ObjectContextLoader::load_obc_iertr::future<>
- ObjectContextLoader::reload_obc(ObjectContext& obc) const
- {
- LOG_PREFIX(ObjectContextLoader::reload_obc);
- assert(obc.is_head());
- return backend.load_metadata(obc.get_oid())
- .safe_then_interruptible<false>(
- [FNAME, this, &obc](auto md)-> load_obc_ertr::future<> {
- DEBUGDPP("reloaded obs {} for {}", dpp, md->os.oi, obc.get_oid());
- if (!md->ssc) {
- ERRORDPP("oid {} missing snapsetcontext", dpp, obc.get_oid());
- return crimson::ct_error::object_corrupted::make();
- }
- obc.set_head_state(std::move(md->os), std::move(md->ssc));
- return load_obc_ertr::now();
- });
- }
+ const hobject_t& oid = md->os.oi.soid;
+ DEBUGDPP("loaded obs {} for {}", dpp, md->os.oi, oid);
+ if (oid.is_head()) {
+ if (!md->ssc) {
+ ERRORDPP("oid {} missing snapsetcontext", dpp, oid);
+ return crimson::ct_error::object_corrupted::make();
+ }
+ obc->set_head_state(std::move(md->os),
+ std::move(md->ssc));
+ } else {
+ // we load and set the ssc only for head obc.
+ // For clones, the head's ssc will be referenced later.
+ // See set_clone_ssc
+ obc->set_clone_state(std::move(md->os));
+ }
+ DEBUGDPP("loaded obc {} for {}", dpp, obc->obs.oi, obc->obs.oi.soid);
+ return seastar::now();
+ });
+}
- void ObjectContextLoader::notify_on_change(bool is_primary)
- {
- LOG_PREFIX(ObjectContextLoader::notify_on_change);
- DEBUGDPP("is_primary: {}", dpp, is_primary);
- for (auto& obc : obc_set_accessing) {
- DEBUGDPP("interrupting obc: {}", dpp, obc.get_oid());
- obc.interrupt(::crimson::common::actingset_changed(is_primary));
- }
+void ObjectContextLoader::notify_on_change(bool is_primary)
+{
+ LOG_PREFIX(ObjectContextLoader::notify_on_change);
+ DEBUGDPP("is_primary: {}", dpp, is_primary);
+ for (auto& obc : obc_set_accessing) {
+ DEBUGDPP("interrupting obc: {}", dpp, obc.get_oid());
+ obc.interrupt(::crimson::common::actingset_changed(is_primary));
}
-
- // explicitly instantiate the used instantiations
- template ObjectContextLoader::load_obc_iertr::future<>
- ObjectContextLoader::with_obc<RWState::RWNONE>(hobject_t,
- with_obc_func_t&&,
- bool resolve_clone);
-
- template ObjectContextLoader::load_obc_iertr::future<>
- ObjectContextLoader::with_obc<RWState::RWREAD>(hobject_t,
- with_obc_func_t&&,
- bool resolve_clone);
-
- template ObjectContextLoader::load_obc_iertr::future<>
- ObjectContextLoader::with_obc<RWState::RWWRITE>(hobject_t,
- with_obc_func_t&&,
- bool resolve_clone);
-
- template ObjectContextLoader::load_obc_iertr::future<>
- ObjectContextLoader::with_obc<RWState::RWEXCL>(hobject_t,
- with_obc_func_t&&,
- bool resolve_clone);
+}
}