Remove spare and unallocated bridges rather than replacing them

This commit is contained in:
onyinyang 2024-03-13 13:41:59 -04:00
parent b771a40a3d
commit d881cf2fec
No known key found for this signature in database
GPG Key ID: 156A6435430C2036
3 changed files with 100 additions and 13 deletions

View File

@ -13,7 +13,6 @@ use serde::{Deserialize, Serialize};
use lox_zkp::ProofError;
use serde_json::json;
use std::{
cmp::Ordering,
collections::HashMap,
sync::{Arc, Mutex},
};

View File

@ -73,6 +73,7 @@ pub enum ReplaceSuccess {
NotFound = 0,
NotReplaced = 1,
Replaced = 2,
Removed = 3,
}
/// This error is thrown if the number of buckets/keys in the bridge table
@ -546,6 +547,25 @@ impl BridgeAuth {
Ok(())
}
// Remove an unallocated resource
pub fn remove_unallocated(&mut self, bridge: &BridgeLine) -> ReplaceSuccess {
// Check if the bridge is in the unallocated bridges and remove the bridge if so
// Bridges in spare buckets should have been moved to the unallocated bridges
if self.bridge_table.unallocated_bridges.contains(bridge) {
let index = self
.bridge_table
.unallocated_bridges
.iter()
.position(|x| x == bridge)
.unwrap();
self.bridge_table.unallocated_bridges.swap_remove(index);
// A bridge that is in the unallocated_bridges is not exactly replaced
// but is successfully handled and no further action is needed
return ReplaceSuccess::Removed;
}
ReplaceSuccess::NotFound
}
/// Attempt to remove a bridge that is failing tests and replace it with a bridge from
/// available_bridge or from a spare bucket
pub fn bridge_replace(
@ -555,8 +575,23 @@ impl BridgeAuth {
) -> ReplaceSuccess {
let reachable_bridges = &self.bridge_table.reachable.clone();
let Some(positions) = reachable_bridges.get(bridge) else {
return ReplaceSuccess::NotFound;
return self.remove_unallocated(bridge);
};
// Check if the bridge is in a spare bucket first, if it is, dissolve the bucket
if let Some(spare) = self
.bridge_table
.spares
.iter()
.find(|x| positions.iter().any(|(bucketnum, _)| &bucketnum == x))
.cloned()
{
let Ok(_) = self.dissolve_spare_bucket(spare) else {
return ReplaceSuccess::NotReplaced;
};
// Next Check if the bridge is in the unallocated bridges and remove the bridge if so
// Bridges in spare buckets should have been moved to the unallocated bridges
return self.remove_unallocated(bridge);
}
// select replacement:
// - first try the given bridge
// - second try to pick one from the set of available bridges

View File

@ -1032,22 +1032,39 @@ fn test_update_bridge() {
#[test]
fn test_bridge_replace() {
// Create 3 open invitation buckets and 3 spare buckets
let cases = vec!["not found", "available", "unallocated", "spare", "failed"];
let cases = vec![
"not found",
"available",
"unallocated",
"use_spare",
"remove_spare",
"failed",
];
let num_buckets = 5;
let hot_spare = 0;
for case in cases {
let table_size: usize;
let mut th: TestHarness;
if String::from(case) != "failed" {
th = TestHarness::new();
} else {
th = TestHarness::new_buckets(num_buckets, hot_spare);
match case {
"failed" => {
th = TestHarness::new_buckets(num_buckets, hot_spare);
table_size = th.ba.bridge_table.buckets.len();
}
"remove_spare" => {
th = TestHarness::new_buckets(0, 5);
table_size = th.ba.bridge_table.buckets.len();
}
_ => {
th = TestHarness::new();
// Ensure that a randomly selected bucket isn't taken from the set of spare bridges
table_size = th.ba.bridge_table.buckets.len() - 5;
}
}
// Randomly select a bridge to replace
let table_size = th.ba.bridge_table.buckets.len();
let mut num = 100000;
while !th.ba.bridge_table.buckets.contains_key(&num) {
num = rand::thread_rng().gen_range(0..th.ba.bridge_table.counter);
num = rand::thread_rng().gen_range(0..table_size as u32);
}
println!("chosen num is: {:?}", num);
let replaceable_bucket = *th.ba.bridge_table.buckets.get(&num).unwrap();
@ -1108,8 +1125,10 @@ fn test_bridge_replace() {
.is_some(),
"Replacement bridge not added to reachable bridges"
);
println!("Table Size {:?}", table_size);
println!("Bucket length {:?}", th.ba.bridge_table.buckets.len() - 5);
assert!(
table_size == th.ba.bridge_table.buckets.len(),
table_size == th.ba.bridge_table.buckets.len() - 5,
"Number of buckets changed size"
);
assert!(
@ -1150,7 +1169,7 @@ fn test_bridge_replace() {
"Replacement bridge not added to reachable bridges"
);
assert!(
table_size == th.ba.bridge_table.buckets.len(),
table_size == th.ba.bridge_table.buckets.len() - 5,
"Number of buckets changed size"
);
assert!(
@ -1160,7 +1179,7 @@ fn test_bridge_replace() {
println!("Successfully added unallocated bridgeline");
}
"spare" => {
"use_spare" => {
// Case three: available_bridge == null and unallocated_bridges == null
assert!(
th.ba.bridge_table.unallocated_bridges.is_empty(),
@ -1180,7 +1199,7 @@ fn test_bridge_replace() {
);
// Remove a spare bucket to replace bridge, buckets decrease by 1
assert!(
(table_size - 1) == th.ba.bridge_table.buckets.len(),
(table_size - 1) == th.ba.bridge_table.buckets.len() - 5,
"Number of buckets changed size"
);
assert!(
@ -1190,6 +1209,40 @@ fn test_bridge_replace() {
println!("Successfully added bridgeline from spare");
}
"remove_spare" => {
// Case three: available_bridge == null and unallocated_bridges == null
assert!(
th.ba.bridge_table.unallocated_bridges.is_empty(),
"Unallocated bridges should have a length of 0"
);
assert!(
th.ba.bridge_replace(replacement_bridge, None) == ReplaceSuccess::Removed,
"Bridge was replaced with available spare, instead of being removed"
);
assert!(
th.ba.bridge_table.unallocated_bridges.len() == 2,
"Unallocated bridges should have a length of 2"
);
assert!(
th.ba
.bridge_table
.reachable
.get(replacement_bridge)
.is_none(),
"Replacement bridge still marked as reachable"
);
// Remove a spare bucket to replace bridge, buckets decrease by 1
assert!(
(table_size - 1) == th.ba.bridge_table.buckets.len(),
"Number of buckets changed size"
);
assert!(
th.ba.bridge_table.unallocated_bridges.len() == 2,
"Extra spare bridges not added to unallocated bridges"
);
println!("Successfully removed a spare bridgeline marked to be replaced");
}
"failed" => {
// Case four: available_bridge == None and unallocated_bridges == None and spare buckets == None
assert!(