template <class Func>
struct OpsExecuter::RollbackHelper {
+ void rollback_obc_if_modified();
void rollback_obc_if_modified(const std::error_code& e);
seastar::lw_shared_ptr<OpsExecuter> ox;
Func func;
return {shared_from_this(), std::forward<Func>(func)};
}
+template <class Func>
+void OpsExecuter::RollbackHelper<Func>::rollback_obc_if_modified()
+{
+ // Oops, an operation had failed. do_osd_ops() altogether with
+ // OpsExecuter already dropped the ObjectStore::Transaction if
+ // there was any. However, this is not enough to completely
+ // rollback as we gave OpsExecuter the very single copy of `obc`
+ // we maintain and we did it for both reading and writing.
+ // Now all modifications must be reverted.
+ //
+ // The conditional's purpose is to efficiently handle hot errors
+ // which may appear as a result of e.g. CEPH_OSD_OP_CMPXATTR or
+ // CEPH_OSD_OP_OMAP_CMP. These are read-like ops and clients
+ // typically append them before any write. If OpsExecuter hasn't
+ // seen any modifying operation, `obc` is supposed to be kept
+ // unchanged.
+ assert(ox);
+ const auto need_rollback = ox->has_seen_write();
+ crimson::get_logger(ceph_subsys_osd).debug(
+ "{}: object {} got error, need_rollback={}",
+ __func__,
+ ox->obc->get_oid(),
+ need_rollback);
+ if (need_rollback) {
+ func(ox->obc);
+ }
+}
template <class Func>
void OpsExecuter::RollbackHelper<Func>::rollback_obc_if_modified(