ObjectContextRef head,
std::set<snapid_t> &snaps)
{
+ LOG_PREFIX(ClientRequest::process_op);
co_await ihref.enter_stage<interruptor>(
client_pp(*pg).recover_missing_snaps, *this);
for (auto &snap : snaps) {
* we skip the oid as there is no corresponding clone to recover.
* See https://tracker.ceph.com/issues/63821 */
if (oid) {
- co_await do_recover_missing(pg, *oid, m->get_reqid());
+ auto unfound = co_await do_recover_missing(pg, *oid, m->get_reqid());
+ if (unfound) {
+ DEBUGDPP("{} unfound, hang it for now", *pg, m->get_hobj().get_head());
+ co_await interruptor::make_interruptible(
+ pg->get_recovery_backend()->add_unfound(m->get_hobj().get_head()));
+ }
}
}
}
"Skipping recover_missings on non primary pg for soid {}",
*pg, m->get_hobj());
} else {
- co_await do_recover_missing(pg, m->get_hobj().get_head(), m->get_reqid());
+ auto unfound = co_await do_recover_missing(
+ pg, m->get_hobj().get_head(), m->get_reqid());
+ if (unfound) {
+ DEBUGDPP("{} unfound, hang it for now", *pg, m->get_hobj().get_head());
+ co_await interruptor::make_interruptible(
+ pg->get_recovery_backend()->add_unfound(m->get_hobj().get_head()));
+ }
+
std::set<snapid_t> snaps = snaps_need_to_recover();
if (!snaps.empty()) {
// call with_obc() in order, but wait concurrently for loading.
namespace crimson::osd {
-typename InterruptibleOperation::template interruptible_future<>
+typename InterruptibleOperation::template interruptible_future<bool>
CommonClientRequest::do_recover_missing(
Ref<PG> pg,
const hobject_t& soid,
if (!needs_recovery_or_backfill) {
logger().debug("{} reqid {} nothing to recover {}",
__func__, reqid, soid);
- return seastar::now();
+ return seastar::make_ready_future<bool>(false);
}
+ if (pg->get_peering_state().get_missing_loc().is_unfound(soid)) {
+ return seastar::make_ready_future<bool>(true);
+ }
logger().debug("{} reqid {} need to wait for recovery, {} version {}",
__func__, reqid, soid, ver);
if (pg->get_recovery_backend()->is_recovering(soid)) {
logger().debug("{} reqid {} object {} version {}, already recovering",
__func__, reqid, soid, ver);
- return pg->get_recovery_backend()->get_recovering(soid).wait_for_recovered();
+ return pg->get_recovery_backend()->get_recovering(
+ soid).wait_for_recovered(
+ ).then([] {
+ return seastar::make_ready_future<bool>(false);
+ });
} else {
logger().debug("{} reqid {} object {} version {}, starting recovery",
__func__, reqid, soid, ver);
auto [op, fut] =
pg->get_shard_services().start_operation<UrgentRecovery>(
soid, ver, pg, pg->get_shard_services(), pg->get_osdmap_epoch());
- return std::move(fut);
+ return fut.then([] { return seastar::make_ready_future<bool>(false); });
}
}
struct CommonClientRequest {
- static InterruptibleOperation::template interruptible_future<>
+ static InterruptibleOperation::template interruptible_future<bool>
do_recover_missing(
Ref<PG> pg,
const hobject_t& soid,
client_pp().recover_missing);
}).then_interruptible([this] {
return do_recover_missing(pg, get_target_oid(), osd_reqid_t());
- }).then_interruptible([this] {
+ }).then_interruptible([this](bool unfound) {
+ if (unfound) {
+ throw std::system_error(
+ std::make_error_code(std::errc::operation_canceled),
+ fmt::format("{} is unfound, drop it!", get_target_oid()));
+ }
return enter_stage<interruptor>(
client_pp().get_obc);
}).then_interruptible([this] () -> PG::load_obc_iertr::future<> {
}, pg, start_epoch);
}).then([this] {
track_event<CompletionEvent>();
+ }).handle_exception_type([](std::system_error &error) {
+ logger().debug("error {}, message: {}", error.code(), error.what());
+ return seastar::now();
}).finally([this] {
logger().debug("{}: exit", *this);
handle.exit();
auto& recovery_waiter = pg->get_recovery_backend()->get_recovering(soid);
recovery_waiter.set_recovered();
pg->get_recovery_backend()->remove_recovering(soid);
+ pg->get_recovery_backend()->found_and_remove(soid);
}
void PGRecovery::on_failed_recover(
assert(it->second);
return {*(it->second), added};
}
+ seastar::future<> add_unfound(const hobject_t &soid) {
+ auto [it, added] = unfound.emplace(soid, seastar::shared_promise());
+ return it->second.get_shared_future();
+ }
+ void found_and_remove(const hobject_t &soid) {
+ auto it = unfound.find(soid);
+ if (it != unfound.end()) {
+ auto &found_promise = it->second;
+ found_promise.set_value();
+ unfound.erase(it);
+ }
+ }
WaitForObjectRecovery& get_recovering(const hobject_t& soid) {
assert(is_recovering(soid));
return *(recovering.at(soid));
for (auto& [soid, recovery_waiter] : recovering) {
recovery_waiter->stop();
}
+ for (auto& [soid, promise] : unfound) {
+ promise.set_exception(
+ crimson::common::system_shutdown_exception());
+ }
return on_stop();
}
protected:
using WaitForObjectRecoveryRef = boost::intrusive_ptr<WaitForObjectRecovery>;
protected:
std::map<hobject_t, WaitForObjectRecoveryRef> recovering;
+ std::map<hobject_t, seastar::shared_promise<>> unfound;
hobject_t get_temp_recovery_object(
const hobject_t& target,
eversion_t version) const;