Skip to content

Commit 859bc2d

Browse files
committed
avoid data loss on recreate
1 parent 4c2f450 commit 859bc2d

2 files changed

Lines changed: 61 additions & 5 deletions

File tree

crates/fula-cli/src/state.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,15 @@ impl AppState {
9191
info!("Starting with empty bucket registry");
9292
}
9393
Err(e) => {
94-
warn!("Failed to load bucket registry: {}. Starting fresh.", e);
94+
// CRITICAL: Don't continue with empty registry if load failed!
95+
// This prevents overwriting the CID file with an empty registry.
96+
return Err(anyhow::anyhow!(
97+
"Failed to load bucket registry: {}. \
98+
Refusing to start to prevent data loss. \
99+
Ensure IPFS is running and the registry block is available, \
100+
then restart the gateway.",
101+
e
102+
));
95103
}
96104
}
97105

crates/fula-core/src/bucket.rs

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -380,10 +380,41 @@ impl<S: BlockStore + PinStore> BucketManager<S> {
380380

381381
info!(cid = %cid, "Loading bucket registry from IPFS");
382382

383-
// Fetch registry from IPFS
384-
let registry: BucketRegistry = self.store.get_ipld(&cid).await.map_err(|e| {
385-
CoreError::StorageError(format!("Failed to load registry from IPFS: {}", e))
386-
})?;
383+
// Fetch registry from IPFS with retry logic and exponential backoff
384+
let max_attempts = 5;
385+
let mut attempts = 0;
386+
let mut delay = std::time::Duration::from_secs(1);
387+
388+
let registry: BucketRegistry = loop {
389+
match self.store.get_ipld(&cid).await {
390+
Ok(reg) => break reg,
391+
Err(e) if attempts < max_attempts - 1 => {
392+
attempts += 1;
393+
warn!(
394+
attempt = attempts,
395+
max_attempts = max_attempts,
396+
delay_secs = delay.as_secs(),
397+
error = %e,
398+
cid = %cid,
399+
"Failed to fetch registry from IPFS, retrying..."
400+
);
401+
tokio::time::sleep(delay).await;
402+
delay *= 2; // Exponential backoff
403+
}
404+
Err(e) => {
405+
error!(
406+
cid = %cid,
407+
error = %e,
408+
attempts = max_attempts,
409+
"Failed to load registry from IPFS after all retry attempts"
410+
);
411+
return Err(CoreError::StorageError(format!(
412+
"Failed to load registry from IPFS after {} attempts: {}",
413+
max_attempts, e
414+
)));
415+
}
416+
}
417+
};
387418

388419
// Validate version
389420
if registry.version > BucketRegistry::CURRENT_VERSION {
@@ -463,6 +494,23 @@ impl<S: BlockStore + PinStore> BucketManager<S> {
463494
}
464495
}
465496

497+
// Backup existing CID file before overwriting to prevent data loss
498+
if path.exists() {
499+
let backup_path = path.with_extension("cid.bak");
500+
if let Err(e) = std::fs::copy(path, &backup_path) {
501+
warn!(
502+
error = %e,
503+
backup_path = %backup_path.display(),
504+
"Failed to backup registry CID file"
505+
);
506+
} else {
507+
info!(
508+
backup_path = %backup_path.display(),
509+
"Backed up previous registry CID"
510+
);
511+
}
512+
}
513+
466514
std::fs::write(path, cid.to_string()).map_err(|e| {
467515
CoreError::StorageError(format!(
468516
"Failed to write registry CID to {}: {}",

0 commit comments

Comments
 (0)