Update lox-context to handle Removed bridges, add test for spare removals

This commit is contained in:
onyinyang 2024-03-13 13:43:57 -04:00
parent d881cf2fec
commit d0407e9e5d
No known key found for this signature in database
GPG Key ID: 156A6435430C2036
1 changed files with 128 additions and 47 deletions

View File

@ -95,7 +95,6 @@ impl LoxServerContext {
} }
} }
accounted_for_bridges accounted_for_bridges
} }
@ -143,33 +142,37 @@ impl LoxServerContext {
// Next, handle the failing bridges. If resource last passed tests >= ACCEPTED_HOURS_OF_FAILURE ago, // Next, handle the failing bridges. If resource last passed tests >= ACCEPTED_HOURS_OF_FAILURE ago,
// it should be replaced with a working resource and be removed from the bridgetable. // it should be replaced with a working resource and be removed from the bridgetable.
for bridge in failing { for bridge in failing {
let res = self.replace_with_new(bridge); match self.replace_with_new(bridge) {
if res == lox_library::ReplaceSuccess::Replaced { lox_library::ReplaceSuccess::Replaced => {
println!( println!(
"Failing BridgeLine {:?} successfully replaced.", "Failing BridgeLine {:?} successfully replaced.",
bridge.uid_fingerprint bridge.uid_fingerprint
); );
accounted_for_bridges.push(bridge.uid_fingerprint); accounted_for_bridges.push(bridge.uid_fingerprint);
self.metrics.removed_bridges.inc(); self.metrics.removed_bridges.inc();
} else if res == lox_library::ReplaceSuccess::NotReplaced { }
// Add the bridge to the list of to_be_replaced bridges in the Lox context and try lox_library::ReplaceSuccess::NotReplaced => {
// again to replace at the next update (nothing changes in the Lox Authority) // Add the bridge to the list of to_be_replaced bridges in the Lox context and try
println!( // again to replace at the next update (nothing changes in the Lox Authority)
"Failing BridgeLine {:?} NOT replaced, saved for next update!", println!(
bridge.uid_fingerprint "Failing BridgeLine {:?} NOT replaced, saved for next update!",
); bridge.uid_fingerprint
self.metrics.existing_or_updated_bridges.inc(); );
accounted_for_bridges.push(bridge.uid_fingerprint); self.metrics.existing_or_updated_bridges.inc();
} else { accounted_for_bridges.push(bridge.uid_fingerprint);
// NotFound }
assert!( lox_library::ReplaceSuccess::Removed => {
res == lox_library::ReplaceSuccess::NotFound, println!(
"ReplaceSuccess incorrectly set" "Failing BridgeLine {:?} successfully removed.",
); bridge.uid_fingerprint
println!( );
accounted_for_bridges.push(bridge.uid_fingerprint);
self.metrics.removed_bridges.inc();
}
lox_library::ReplaceSuccess::NotFound => println!(
"Failing BridgeLine {:?} not found in bridge table.", "Failing BridgeLine {:?} not found in bridge table.",
bridge.uid_fingerprint bridge.uid_fingerprint
); ),
} }
} }
accounted_for_bridges accounted_for_bridges
@ -193,32 +196,49 @@ impl LoxServerContext {
accounted_for_bridges, accounted_for_bridges,
); );
} }
let unaccounted_for = self.ba.lock().unwrap().find_and_remove_unaccounted_for_bridges(accounted_for_bridges);
let unaccounted_for = self
.ba
.lock()
.unwrap()
.find_and_remove_unaccounted_for_bridges(accounted_for_bridges);
for bridgeline in unaccounted_for { for bridgeline in unaccounted_for {
match self.replace_with_new(bridgeline) { match self.replace_with_new(bridgeline) {
lox_library::ReplaceSuccess::Replaced => { lox_library::ReplaceSuccess::Replaced => {
println!("BridgeLine {:?} not found in rdsys update was successfully replaced.", bridgeline.uid_fingerprint); println!(
self.metrics.removed_bridges.inc(); "BridgeLine {:?} not found in rdsys update was successfully replaced.",
} bridgeline.uid_fingerprint
lox_library::ReplaceSuccess::NotReplaced => { );
// Try again to replace at the next update (nothing changes in the Lox Authority) self.metrics.removed_bridges.inc();
println!("BridgeLine {:?} not found in rdsys update NOT replaced, saved for next update!",
bridgeline.uid_fingerprint);
self.metrics.existing_or_updated_bridges.inc();
}
lox_library::ReplaceSuccess::NotFound => println!(
"BridgeLine {:?} no longer in reachable bridges.",
bridgeline.uid_fingerprint
),
}
} }
lox_library::ReplaceSuccess::Removed => {
println!("BridgeLine {:?} not found in rdsys update was not distributed to a bucket so was removed", bridgeline.uid_fingerprint);
self.metrics.removed_bridges.inc();
}
lox_library::ReplaceSuccess::NotReplaced => {
// Try again to replace at the next update (nothing changes in the Lox Authority)
println!("BridgeLine {:?} not found in rdsys update NOT replaced, saved for next update!",
bridgeline.uid_fingerprint);
self.metrics.existing_or_updated_bridges.inc();
}
lox_library::ReplaceSuccess::NotFound => println!(
"BridgeLine {:?} no longer in reachable bridges.",
bridgeline.uid_fingerprint
),
}
}
// Finally, assign any extra_bridges to new buckets if there are enough // Finally, assign any extra_bridges to new buckets if there are enough
while self.extra_bridges.lock().unwrap().len() >= MAX_BRIDGES_PER_BUCKET { while self.extra_bridges.lock().unwrap().len() >= MAX_BRIDGES_PER_BUCKET {
let bucket = self.remove_extra_bridges(); let bucket = self.remove_extra_bridges();
// TODO: Decide the circumstances under which a bridge is allocated to an open_inv or spare bucket, // TODO: Decide the circumstances under which a bridge is allocated to an open_inv or spare bucket,
// eventually also do some more fancy grouping of new resources, i.e., by type or region // eventually also do some more fancy grouping of new resources, i.e., by type or region
let mut db_obj = self.db.lock().unwrap(); let mut db_obj = self.db.lock().unwrap();
match self.ba.lock().unwrap().add_spare_bucket(bucket, &mut db_obj) { match self
.ba
.lock()
.unwrap()
.add_spare_bucket(bucket, &mut db_obj)
{
Ok(_) => (), Ok(_) => (),
Err(e) => { Err(e) => {
println!("Error: {:?}", e); println!("Error: {:?}", e);
@ -765,7 +785,7 @@ mod tests {
} }
} }
fn get_config()-> BridgeConfig { fn get_config() -> BridgeConfig {
env::set_var("BRIDGE_CONFIG_PATH", "bridge_config.json"); env::set_var("BRIDGE_CONFIG_PATH", "bridge_config.json");
let path = env::var("BRIDGE_CONFIG_PATH").unwrap(); let path = env::var("BRIDGE_CONFIG_PATH").unwrap();
let config_file = fs::File::open(&path).unwrap(); let config_file = fs::File::open(&path).unwrap();
@ -799,7 +819,7 @@ mod tests {
// Extra bridges should be cleared from the Lox Context after each sync // Extra bridges should be cleared from the Lox Context after each sync
assert!( assert!(
th.context.extra_bridges.lock().unwrap().is_empty(), th.context.extra_bridges.lock().unwrap().is_empty(),
"Extra bridges should be empty after syncUnexpected number of extra bridges" "Extra bridges should be empty after sync"
); );
} }
@ -831,11 +851,72 @@ mod tests {
reachable_expected_length, reachable_expected_length,
"Unexpected number of reachable bridges" "Unexpected number of reachable bridges"
); );
// Extra bridges should be cleared from the Lox Context after each sync
assert!(
th.context.extra_bridges.lock().unwrap().is_empty(),
"Extra bridges should be empty after sync"
);
}
#[test]
fn test_sync_with_preloaded_obsolete_bridgetable() {
// Tests the case where all bridges in the bridgetable are no longer in rdsys.
// In this case, all bridges should be replaced. If it's a bridge in a spare bucket, just remove the other bridges
// from the spare bucket and delete the bridge
let bridge_config = get_config();
// Sync bridges to non-empty bridge table with disparate sets of bridges
let th_with_bridges = TestHarness::new_with_bridges(); //Creates 5 open invitation and 5 hot spare buckets, so 30 total buckets to be replaced
let mut rs = TestResourceState::default();
for _ in 0..5 {
rs.add_working_resource();
}
assert_ne!(rs.rstate.working, None);
assert_eq!(rs.rstate.not_working, None);
assert_eq!(th_with_bridges.context.ba.lock().unwrap().bridge_table.reachable.len(), 15+15, "Unexpected number of reachable bridges should equal the number of open invitation bridges plus the number of spares added: 2x5x3");
assert_eq!( assert_eq!(
th.context.extra_bridges.lock().unwrap().len(), th_with_bridges
.context
.ba
.lock()
.unwrap()
.bridge_table
.spares
.len(),
5,
"Unexpected number of spare bridges, should be 5"
);
// All potentially distributed resources (i.e., those assigned to open invitation/trusted buckets)
// not found in the rdsys update will first be replaced with any new resources coming in from rdsys then
// by bridges from the hot spare buckets. In this case, the hot spare buckets are also not in the bridge table
// so will also be replaced.
// Since there are fewer working resources than resources that have populated the bridge table, this update will
// exhaust the spare buckets and leave some obsolete bridges. The set of open invitation/trusted buckets should be
// preserved (5 open invitation buckets * 3)
th_with_bridges
.context
.sync_with_bridgetable(bridge_config.watched_blockages, rs.rstate.clone());
assert_eq!(th_with_bridges.context.ba.lock().unwrap().bridge_table.reachable.len(), 15, "Unexpected number of reachable bridges should equal the number of open invitation bridges added: 5x3");
assert_eq!(
th_with_bridges
.context
.ba
.lock()
.unwrap()
.bridge_table
.spares
.len(),
0,
"Unexpected number of spare bridges, should be exhausted"
);
assert_eq!(th_with_bridges.context.ba.lock().unwrap().bridge_table.unallocated_bridges.len(), 0, "Unexpected number of unallocated bridges, should be 0 (All spare buckets and new resources for replacement exhausted)"
);
assert_eq!(
th_with_bridges.context.extra_bridges.lock().unwrap().len(),
0, 0,
"Unexpected number of extra bridges" "Unexpected number of extra bridges"
); );
} }
} }