Compare commits

..

1 commit

Author SHA1 Message Date
99d2213302 implement repair procedure to fix inconsistent bucket aliases
Some checks failed
ci/woodpecker/pr/debug Pipeline failed
ci/woodpecker/push/debug Pipeline failed
2025-03-19 13:03:46 +01:00

View file

@ -492,79 +492,84 @@ impl<'a> LockedHelper<'a> {
// 2. List all aliases declared in bucket_alias_table and key_table // 2. List all aliases declared in bucket_alias_table and key_table
// Take note of aliases that point to non-existing buckets // Take note of aliases that point to non-existing buckets
let mut global_aliases: HashMap<String, Uuid> = HashMap::new(); let mut global_aliases: HashMap<String, Uuid> = HashMap::new();
let mut local_aliases: HashMap<(String, String), Uuid> = HashMap::new();
let mut delete_global = vec![]; {
let mut delete_local = vec![]; let mut delete_global = vec![];
for item in tx.range::<&[u8], _>(&self.0.bucket_alias_table.data.store, ..)? {
for item in tx.range::<&[u8], _>(&self.0.bucket_alias_table.data.store, ..)? { let mut alias = self
let mut alias = self .0
.0 .bucket_alias_table
.bucket_alias_table .data
.data .decode_entry(&(item?.1))
.decode_entry(&(item?.1)) .map_err(db::TxError::Abort)?;
.map_err(db::TxError::Abort)?; if let Some(id) = alias.state.get() {
if let Some(id) = alias.state.get() { if all_buckets.contains(id) {
if all_buckets.contains(&id) { // keep aliases
// keep aliases global_aliases.insert(alias.name().to_string(), *id);
global_aliases.insert(alias.name().to_string(), *id);
} else {
// delete alias
warn!(
"global alias: remove {} -> {:?} (bucket is deleted)",
alias.name(),
id
);
alias.state.update(None);
delete_global.push(alias);
}
}
}
for item in tx.range::<&[u8], _>(&self.0.key_table.data.store, ..)? {
let mut key = self
.0
.key_table
.data
.decode_entry(&(item?.1))
.map_err(db::TxError::Abort)?;
let Some(p) = key.state.as_option_mut() else {
continue;
};
let mut has_changes = false;
for (name, _, to) in p.local_aliases.items().to_vec() {
if let Some(id) = to {
if all_buckets.contains(&id) {
local_aliases.insert((key.key_id.clone(), name.clone()), id);
} else { } else {
// delete alias
warn!( warn!(
"local alias: remove ({}, {}) -> {:?} (bucket is deleted)", "global alias: remove {} -> {:?} (bucket is deleted)",
key.key_id, name, id alias.name(),
id
); );
p.local_aliases.update_in_place(name.clone(), None); alias.state.update(None);
has_changes = true; delete_global.push(alias);
} }
} }
} }
if has_changes {
delete_local.push(key); info!("number of global aliases: {}", global_aliases.len());
info!("global alias table: {} entries fixed", delete_global.len());
for ga in delete_global {
debug!("Enqueue update to global alias table: {:?}", ga);
self.0.bucket_alias_table.queue_insert(tx, &ga)?;
} }
} }
info!("number of global aliases: {}", global_aliases.len()); let mut local_aliases: HashMap<(String, String), Uuid> = HashMap::new();
info!("number of local aliases: {}", local_aliases.len());
// 3. Enqueue non-existing aliases for deletion {
info!("global alias table: {} entries fixed", delete_global.len()); let mut delete_local = vec![];
for ga in delete_global {
debug!("Enqueue update to global alias table: {:?}", ga);
self.0.bucket_alias_table.queue_insert(tx, &ga)?;
}
info!("local alias table: {} entries fixed", delete_local.len()); for item in tx.range::<&[u8], _>(&self.0.key_table.data.store, ..)? {
for la in delete_local { let mut key = self
debug!("Enqueue update to local alias table: {:?}", la); .0
self.0.key_table.queue_insert(tx, &la)?; .key_table
.data
.decode_entry(&(item?.1))
.map_err(db::TxError::Abort)?;
let Some(p) = key.state.as_option_mut() else {
continue;
};
let mut has_changes = false;
for (name, _, to) in p.local_aliases.items().to_vec() {
if let Some(id) = to {
if all_buckets.contains(&id) {
local_aliases.insert((key.key_id.clone(), name.clone()), id);
} else {
warn!(
"local alias: remove ({}, {}) -> {:?} (bucket is deleted)",
key.key_id, name, id
);
p.local_aliases.update_in_place(name.clone(), None);
has_changes = true;
}
}
}
if has_changes {
delete_local.push(key);
}
}
info!("number of local aliases: {}", local_aliases.len());
info!("local alias table: {} entries fixed", delete_local.len());
for la in delete_local {
debug!("Enqueue update to local alias table: {:?}", la);
self.0.key_table.queue_insert(tx, &la)?;
}
} }
// 4. Reverse the alias maps to determine the aliases per-bucket // 4. Reverse the alias maps to determine the aliases per-bucket
@ -594,32 +599,36 @@ impl<'a> LockedHelper<'a> {
}; };
// fix global aliases // fix global aliases
let ga = bucket_global.remove(&bucket.id).unwrap_or_default(); {
for (name, _, active) in param.aliases.items().to_vec() { let ga = bucket_global.remove(&bucket.id).unwrap_or_default();
if active && !ga.contains(&name) { for (name, _, active) in param.aliases.items().to_vec() {
warn!("bucket {:?}: remove global alias {}", bucket.id, name); if active && !ga.contains(&name) {
param.aliases.update_in_place(name, false); warn!("bucket {:?}: remove global alias {}", bucket.id, name);
param.aliases.update_in_place(name, false);
}
} }
} for name in ga.iter() {
for name in ga.iter() { if param.aliases.get(&name).copied().unwrap_or(false) == false {
if param.aliases.get(&name).copied().unwrap_or(false) == false { warn!("bucket {:?}: add global alias {}", bucket.id, name);
warn!("bucket {:?}: add global alias {}", bucket.id, name); param.aliases.update_in_place(name.to_string(), true);
param.aliases.update_in_place(name.to_string(), true); }
} }
} }
// fix local aliases // fix local aliases
let la = bucket_local.remove(&bucket.id).unwrap_or_default(); {
for (pair, _, active) in param.local_aliases.items().to_vec() { let la = bucket_local.remove(&bucket.id).unwrap_or_default();
if active && !la.contains(&pair) { for (pair, _, active) in param.local_aliases.items().to_vec() {
warn!("bucket {:?}: remove local alias {:?}", bucket.id, pair); if active && !la.contains(&pair) {
param.local_aliases.update_in_place(pair, false); warn!("bucket {:?}: remove local alias {:?}", bucket.id, pair);
param.local_aliases.update_in_place(pair, false);
}
} }
} for pair in la.iter() {
for pair in la.iter() { if param.local_aliases.get(&pair).copied().unwrap_or(false) == false {
if param.local_aliases.get(&pair).copied().unwrap_or(false) == false { warn!("bucket {:?}: add local alias {:?}", bucket.id, pair);
warn!("bucket {:?}: add local alias {:?}", bucket.id, pair); param.local_aliases.update_in_place(pair.clone(), true);
param.local_aliases.update_in_place(pair.clone(), true); }
} }
} }