tranquil-store/repo: repair tolerates corrupt/missing blocks

Lewis: May this revision serve well! <lu5a@proton.me>
This commit is contained in:
Lewis
2026-06-26 20:50:30 +03:00
parent 28f2e04019
commit a171518290
2 changed files with 23 additions and 21 deletions
+17 -21
View File
@@ -300,30 +300,18 @@ pub async fn repair_repo_structure(
})?;
if outcome.nodes_repaired > 0 {
let block_cids =
crate::scheduled::collect_current_repo_blocks(&state.block_store, &current_root_cid)
.await
.map_err(|e| {
error!("repair: re-walk for user_blocks backfill failed: {}", e);
ApiError::InternalError(None)
})?;
let cids = block_cids
.iter()
.map(|bytes| Cid::try_from(bytes.as_slice()))
.collect::<Result<Vec<Cid>, _>>()
.map_err(|e| {
error!("repair: unparseable CID in repaired DAG walk: {e}");
ApiError::InternalError(None)
})?;
let present = state.block_store.get_many(&cids).await.map_err(|e| {
error!("repair: presence check during user_blocks backfill failed: {e}");
let leaf_present = futures::future::try_join_all(
entries.iter().map(|(_, cid)| state.block_store.has(cid)),
)
.await
.map_err(|e| {
error!("repair: leaf presence check failed: {e}");
ApiError::InternalError(None)
})?;
let missing: Vec<Cid> = cids
let missing: Vec<Cid> = entries
.iter()
.zip(present)
.filter_map(|(cid, found)| found.is_none().then_some(*cid))
.zip(leaf_present)
.filter_map(|((_, cid), present)| (!present).then_some(*cid))
.collect();
if !missing.is_empty() {
error!(
@@ -338,6 +326,14 @@ pub async fn repair_repo_structure(
))));
}
let block_cids =
crate::scheduled::collect_current_repo_blocks(&state.block_store, &current_root_cid)
.await
.map_err(|e| {
error!("repair: re-walk for user_blocks backfill failed: {}", e);
ApiError::InternalError(None)
})?;
state
.repos
.repo
+6
View File
@@ -180,6 +180,12 @@ pub async fn collect_current_repo_blocks(
let block = match block_store.get(&cid).await {
Ok(Some(b)) => b,
Ok(None) => continue,
Err(e)
if crate::api::error::ApiError::detail_is_repo_corruption(&format!("{e:#}")) =>
{
warn!(cid = %cid, error = %format!("{e:#}"), "skipping corrupt block during repo walk");
continue;
}
Err(e) => anyhow::bail!("Failed to get block {}: {:?}", cid, e),
};