From 464700d9bac20fe58e6c09af25958ee349e221f7 Mon Sep 17 00:00:00 2001 From: Christien Rioux Date: Fri, 3 Jan 2025 20:45:38 -0500 Subject: [PATCH] [skip ci] checkpoint --- .../state/machine_locations_list.rs | 2 +- .../machine_registry/state/network_state.rs | 501 ++++++++---------- .../machine_registry/state/template_state.rs | 152 +++--- 3 files changed, 320 insertions(+), 335 deletions(-) diff --git a/veilid-tools/src/virtual_network/router_server/machine_registry/state/machine_locations_list.rs b/veilid-tools/src/virtual_network/router_server/machine_registry/state/machine_locations_list.rs index 4925fd28..c503b0b9 100644 --- a/veilid-tools/src/virtual_network/router_server/machine_registry/state/machine_locations_list.rs +++ b/veilid-tools/src/virtual_network/router_server/machine_registry/state/machine_locations_list.rs @@ -1,7 +1,7 @@ use super::*; /// Locations where a machine can be instantiated -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum MachineLocationsList { Networks { networks: WeightedList, diff --git a/veilid-tools/src/virtual_network/router_server/machine_registry/state/network_state.rs b/veilid-tools/src/virtual_network/router_server/machine_registry/state/network_state.rs index 6ffc4080..a32e930a 100644 --- a/veilid-tools/src/virtual_network/router_server/machine_registry/state/network_state.rs +++ b/veilid-tools/src/virtual_network/router_server/machine_registry/state/network_state.rs @@ -156,25 +156,26 @@ impl NetworkState { } pub fn clear_ipv4( - &self, + &mut self, machine_registry_inner: &mut MachineRegistryInner, ) -> MachineRegistryResult<()> { - let Some(ipv4) = inner.ipv4.as_mut() else { + let Some(ipv4) = self.fields.ipv4.clone() else { return Ok(()); }; - inner.address_pool.clear_ipv4(|_n, t| match t { + let mut address_pool = self.fields.address_pool.clone(); + address_pool.clear_ipv4(|_n, t| match t { OwnerTag::Machine(_) => true, - OwnerTag::Network(nsid) => *nsid != self_id, - OwnerTag::Gateway(nsid) => *nsid != self_id, + OwnerTag::Network(nsid) => *nsid != self.id(), + OwnerTag::Gateway(nsid) => *nsid != self.id(), })?; // If we have a gateway, release its external address // if it belongs to a different network if let Some(gateway) = ipv4.gateway.as_ref() { - if gateway.params.external_network != self_id { + if gateway.params.external_network != self.id() { // Get the external network state - let external_network_state = machine_registry_inner + let mut external_network_state = machine_registry_inner .network_states() .get_state(gateway.params.external_network) .expect("must succeed"); @@ -183,35 +184,47 @@ impl NetworkState { external_network_state .release_address_v4(gateway.external_interface_address.ip) .expect("must succeed"); + + // Update external network + machine_registry_inner + .network_states_mut() + .set_state(external_network_state); } } - inner.ipv4 = None; + // Update fields + self.fields = Arc::new(NetworkStateFields { + ipv4: None, + address_pool, + ..(*self.fields).clone() + }); + Ok(()) } pub fn set_ipv4( - &self, + &mut self, machine_registry_inner: &mut MachineRegistryInner, params: NetworkStateIpv4Params, gateway_params: Option, ) -> MachineRegistryResult<()> { - Self::clear_ipv4_inner(self.id(), &mut *inner, machine_registry_inner)?; + self.clear_ipv4(machine_registry_inner)?; - inner.address_pool.add_scope_v4(params.allocation); + let mut address_pool = self.fields.address_pool.clone(); + address_pool.add_scope_v4(params.allocation); let gateway = match gateway_params { Some(gateway_params) => { // Allocate or reserve an internal network address for the gateway let internal_address = if let Some(internal_address) = gateway_params.internal_address { - inner.address_pool.reserve_allocation_v4( + address_pool.reserve_allocation_v4( Ipv4Net::new(internal_address, 32).expect("must succeed"), Some(OwnerTag::Gateway(self.id())), )?; internal_address } else { - let Some(internal_address) = inner.address_pool.allocate_random_v4( + let Some(internal_address) = address_pool.allocate_random_v4( machine_registry_inner.srng(), 32, OwnerTag::Gateway(self.id()), @@ -230,7 +243,7 @@ impl NetworkState { }; // Get the external network state - let external_network_state = machine_registry_inner + let mut external_network_state = machine_registry_inner .network_states() .get_state(gateway_params.external_network) .expect("must succeed"); @@ -255,6 +268,11 @@ impl NetworkState { )? }; + // Update external network + machine_registry_inner + .network_states_mut() + .set_state(external_network_state); + // Return the gateway state Some(NetworkStateIpv4Gateway { params: gateway_params, @@ -267,38 +285,85 @@ impl NetworkState { let ipv4 = NetworkStateIpv4 { params, gateway }; - inner.ipv4 = Some(ipv4); + // Update fields + self.fields = Arc::new(NetworkStateFields { + ipv4: Some(ipv4), + address_pool, + ..(*self.fields).clone() + }); + Ok(()) } pub fn clear_ipv6( - &self, + &mut self, machine_registry_inner: &mut MachineRegistryInner, ) -> MachineRegistryResult<()> { - Self::clear_ipv6_inner(self.id(), &mut *inner, machine_registry_inner) + let Some(ipv6) = self.fields.ipv6.clone() else { + return Ok(()); + }; + + let mut address_pool = self.fields.address_pool.clone(); + address_pool.clear_ipv6(|_n, t| match t { + OwnerTag::Machine(_) => true, + OwnerTag::Network(nsid) => *nsid != self.id(), + OwnerTag::Gateway(nsid) => *nsid != self.id(), + })?; + + // If we have a gateway, release its external address + // if it belongs to a different network + if let Some(gateway) = ipv6.gateway.as_ref() { + if gateway.params.external_network != self.id() { + // Get the external network state + let mut external_network_state = machine_registry_inner + .network_states() + .get_state(gateway.params.external_network) + .expect("must succeed"); + + // Release external address + external_network_state + .release_address_v6(gateway.external_interface_address.ip) + .expect("must succeed"); + + // Update external network + machine_registry_inner + .network_states_mut() + .set_state(external_network_state); + } + } + + // Update fields + self.fields = Arc::new(NetworkStateFields { + ipv6: None, + address_pool, + ..(*self.fields).clone() + }); + + Ok(()) } pub fn set_ipv6( - &self, + &mut self, machine_registry_inner: &mut MachineRegistryInner, params: NetworkStateIpv6Params, gateway_params: Option, ) -> MachineRegistryResult<()> { - Self::clear_ipv6_inner(self.id(), &mut *inner, machine_registry_inner)?; + self.clear_ipv6(machine_registry_inner)?; - inner.address_pool.add_scope_v6(params.allocation); + let mut address_pool = self.fields.address_pool.clone(); + address_pool.add_scope_v6(params.allocation); let gateway = match gateway_params { Some(gateway_params) => { // Allocate or reserve an internal network address for the gateway let internal_address = if let Some(internal_address) = gateway_params.internal_address { - inner.address_pool.reserve_allocation_v6( + address_pool.reserve_allocation_v6( Ipv6Net::new(internal_address, 128).expect("must succeed"), Some(OwnerTag::Gateway(self.id())), )?; internal_address } else { - let Some(internal_address) = inner.address_pool.allocate_random_v6( + let Some(internal_address) = address_pool.allocate_random_v6( machine_registry_inner.srng(), 128, OwnerTag::Gateway(self.id()), @@ -317,7 +382,7 @@ impl NetworkState { }; // Get the external network state - let external_network_state = machine_registry_inner + let mut external_network_state = machine_registry_inner .network_states() .get_state(gateway_params.external_network) .expect("must succeed"); @@ -342,6 +407,11 @@ impl NetworkState { )? }; + // Update external network + machine_registry_inner + .network_states_mut() + .set_state(external_network_state); + // Return the gateway state Some(NetworkStateIpv6Gateway { params: gateway_params, @@ -354,30 +424,36 @@ impl NetworkState { let ipv6 = NetworkStateIpv6 { params, gateway }; - inner.ipv6 = Some(ipv6); + // Update fields + self.fields = Arc::new(NetworkStateFields { + ipv6: Some(ipv6), + address_pool, + ..(*self.fields).clone() + }); + Ok(()) } pub fn is_ipv4(&self) -> bool { - self.fields.lock().ipv4.is_some() + self.fields.ipv4.is_some() } pub fn is_ipv6(&self) -> bool { - self.fields.lock().ipv6.is_some() + self.fields.ipv6.is_some() } pub fn is_active(&self) -> MachineRegistryResult { let mut can_allocate = false; - if inner.ipv4.is_some() { + if self.fields.ipv4.is_some() { // - if !inner.address_pool.can_allocate_v4(32)? { + if !self.fields.address_pool.can_allocate_v4(32)? { can_allocate = false; } } - if inner.ipv6.is_some() { + if self.fields.ipv6.is_some() { // - if !inner.address_pool.can_allocate_v6(128)? { + if !self.fields.address_pool.can_allocate_v6(128)? { can_allocate = false; } } @@ -390,61 +466,103 @@ impl NetworkState { owner_tag: OwnerTag, opt_address: Option, ) -> MachineRegistryResult { - let mut inner = self.fields.lock(); - - let net = Self::allocate_net_v4_inner( - &mut *inner, - machine_registry_inner, - owner_tag, - opt_address, - 32, - )?; + let net = self.allocate_subnet_v4(machine_registry_inner, owner_tag, opt_address, 32)?; let ip = net.addr(); + let ipv4 = self.fields.ipv4.as_ref().unwrap(); + let netmask = ipv4.params.allocation.netmask(); + let broadcast = ipv4.params.allocation.broadcast(); + let ifaddr = Ifv4Addr { ip, - netmask: inner.ipv4.as_ref().unwrap().params.allocation.netmask(), - broadcast: Some(inner.ipv4.as_ref().unwrap().params.allocation.broadcast()), + netmask, + broadcast: Some(broadcast), }; Ok(ifaddr) } pub fn can_allocate_address_v4(&self, opt_address: Option) -> bool { - Self::can_allocate_net_v4_inner(&*inner, opt_address, 32) + self.can_allocate_subnet_v4(opt_address, 32) } pub fn allocate_subnet_v4( - &self, + &mut self, machine_registry_inner: &mut MachineRegistryInner, owner_tag: OwnerTag, opt_address: Option, prefix: u8, ) -> MachineRegistryResult { - let net = Self::allocate_net_v4_inner( - &mut *inner, - machine_registry_inner, - owner_tag, - opt_address, - prefix, - )?; + if self.fields.ipv4.is_none() { + return Err(MachineRegistryError::NoAllocation); + } + + // See if we are requesting a specific address + let mut address_pool = self.fields.address_pool.clone(); + + let net = if let Some(address) = opt_address { + // Get the net form for this address + let net = Ipv4Net::new(address, prefix).expect("must succeed"); + address_pool.reserve_allocation_v4(net, Some(owner_tag))?; + net + } else { + // Get a random address if available + let Some(allocation) = address_pool.allocate_random_v4( + machine_registry_inner.srng(), + prefix, + owner_tag, + )? + else { + return Err(MachineRegistryError::NoAllocation); + }; + allocation + }; + + // Update fields + self.fields = Arc::new(NetworkStateFields { + address_pool, + ..(*self.fields).clone() + }); Ok(net) } pub fn can_allocate_subnet_v4(&self, opt_address: Option, prefix: u8) -> bool { - Self::can_allocate_net_v4_inner(&*inner, opt_address, prefix) + if self.fields.ipv4.is_none() { + return false; + }; + + // See if we are requesting a specific address + if let Some(address) = opt_address { + // Get the net form for this address + let net = Ipv4Net::new(address, prefix).expect("must succeed"); + self.fields.address_pool.get_overlaps_v4(net).is_empty() + } else { + // Get a random address if available + self.fields + .address_pool + .can_allocate_v4(prefix) + .unwrap_or(false) + } } pub fn release_address_v4( &mut self, addr: Ipv4Addr, ) -> MachineRegistryResult> { - Self::release_subnet_v4_inner(&mut *inner, Ipv4Net::new(addr, 32).expect("must succeed")) + self.release_subnet_v4(Ipv4Net::new(addr, 32).expect("must succeed")) } pub fn release_subnet_v4(&mut self, net: Ipv4Net) -> MachineRegistryResult> { - Self::release_subnet_v4_inner(&mut *inner, net) + let mut address_pool = self.fields.address_pool.clone(); + let opt_tag = address_pool.release_allocation_v4(net)?; + + // Update fields + self.fields = Arc::new(NetworkStateFields { + address_pool, + ..(*self.fields).clone() + }); + Ok(opt_tag) } pub fn allocate_address_v6( @@ -453,157 +571,69 @@ impl NetworkState { owner_tag: OwnerTag, opt_address: Option, ) -> MachineRegistryResult { - let net = Self::allocate_net_v6_inner( - &mut *inner, - machine_registry_inner, - owner_tag, - opt_address, - 128, - )?; + let net = self.allocate_subnet_v6(machine_registry_inner, owner_tag, opt_address, 128)?; let ip = net.addr(); + let ipv6 = self.fields.ipv6.as_ref().unwrap(); + let netmask = ipv6.params.allocation.netmask(); + let broadcast = ipv6.params.allocation.broadcast(); + let ifaddr = Ifv6Addr { ip, - netmask: inner.ipv6.as_ref().unwrap().params.allocation.netmask(), - broadcast: Some(inner.ipv6.as_ref().unwrap().params.allocation.broadcast()), + netmask, + broadcast: Some(broadcast), }; Ok(ifaddr) } pub fn can_allocate_address_v6(&self, opt_address: Option) -> bool { - Self::can_allocate_net_v6_inner(&*inner, opt_address, 128) + self.can_allocate_subnet_v6(opt_address, 128) } pub fn allocate_subnet_v6( - &self, + &mut self, machine_registry_inner: &mut MachineRegistryInner, owner_tag: OwnerTag, opt_address: Option, prefix: u8, ) -> MachineRegistryResult { - let net = Self::allocate_net_v6_inner( - &mut *inner, - machine_registry_inner, - owner_tag, - opt_address, - prefix, - )?; + if self.fields.ipv6.is_none() { + return Err(MachineRegistryError::NoAllocation); + } + + // See if we are requesting a specific address + let mut address_pool = self.fields.address_pool.clone(); + + let net = if let Some(address) = opt_address { + // Get the net form for this address + let net = Ipv6Net::new(address, prefix).expect("must succeed"); + address_pool.reserve_allocation_v6(net, Some(owner_tag))?; + net + } else { + // Get a random address if available + let Some(allocation) = address_pool.allocate_random_v6( + machine_registry_inner.srng(), + prefix, + owner_tag, + )? + else { + return Err(MachineRegistryError::NoAllocation); + }; + allocation + }; + + // Update fields + self.fields = Arc::new(NetworkStateFields { + address_pool, + ..(*self.fields).clone() + }); Ok(net) } pub fn can_allocate_subnet_v6(&self, opt_address: Option, prefix: u8) -> bool { - Self::can_allocate_net_v6_inner(&*inner, opt_address, prefix) - } - - pub fn release_address_v6(&self, addr: Ipv6Addr) -> MachineRegistryResult> { - Self::release_subnet_v6_inner(&mut *inner, Ipv6Net::new(addr, 128).expect("must succeed")) - } - - pub fn release_subnet_v6(&self, net: Ipv6Net) -> MachineRegistryResult> { - Self::release_subnet_v6_inner(&mut *inner, net) - } - - //////////////////////////////////////////////////////////////// - - fn clear_ipv6_inner( - self_id: NetworkStateId, - inner: &mut NetworkStateFields, - machine_registry_inner: &mut MachineRegistryInner, - ) -> MachineRegistryResult<()> { - let Some(ipv6) = inner.ipv6.as_mut() else { - return Ok(()); - }; - - inner.address_pool.clear_ipv6(|_n, t| match t { - OwnerTag::Machine(_) => true, - OwnerTag::Network(nsid) => *nsid != self_id, - OwnerTag::Gateway(nsid) => *nsid != self_id, - })?; - - // If we have a gateway, release its external address - // if it belongs to a different network - if let Some(gateway) = ipv6.gateway.as_ref() { - if gateway.params.external_network != self_id { - // Get the external network state - let external_network_state = machine_registry_inner - .network_states() - .get_state(gateway.params.external_network) - .expect("must succeed"); - - // Release external address - external_network_state - .release_address_v6(gateway.external_interface_address.ip) - .expect("must succeed"); - } - } - - inner.ipv6 = None; - Ok(()) - } - - fn allocate_net_v4_inner( - inner: &mut NetworkStateFields, - machine_registry_inner: &mut MachineRegistryInner, - owner_tag: OwnerTag, - opt_address: Option, - prefix: u8, - ) -> MachineRegistryResult { - let Some(_network_state_ipv4) = &mut inner.ipv4 else { - return Err(MachineRegistryError::NoAllocation); - }; - - // See if we are requesting a specific address - let net = if let Some(address) = opt_address { - // Get the net form for this address - let net = Ipv4Net::new(address, prefix).expect("must succeed"); - inner - .address_pool - .reserve_allocation_v4(net, Some(owner_tag))?; - net - } else { - // Get a random address if available - let Some(allocation) = inner.address_pool.allocate_random_v4( - machine_registry_inner.srng(), - prefix, - owner_tag, - )? - else { - return Err(MachineRegistryError::NoAllocation); - }; - allocation - }; - - Ok(net) - } - - fn can_allocate_net_v4_inner( - inner: &NetworkStateFields, - opt_address: Option, - prefix: u8, - ) -> bool { - let Some(_network_state_ipv4) = &inner.ipv4 else { - return false; - }; - - // See if we are requesting a specific address - if let Some(address) = opt_address { - // Get the net form for this address - let net = Ipv4Net::new(address, prefix).expect("must succeed"); - inner.address_pool.get_overlaps_v4(net).is_empty() - } else { - // Get a random address if available - inner.address_pool.can_allocate_v4(prefix).unwrap_or(false) - } - } - - fn can_allocate_net_v6_inner( - inner: &NetworkStateFields, - opt_address: Option, - prefix: u8, - ) -> bool { - let Some(_network_state_ipv6) = &inner.ipv6 else { + if self.fields.ipv6.is_none() { return false; }; @@ -611,97 +641,34 @@ impl NetworkState { if let Some(address) = opt_address { // Get the net form for this address let net = Ipv6Net::new(address, prefix).expect("must succeed"); - inner.address_pool.get_overlaps_v6(net).is_empty() + self.fields.address_pool.get_overlaps_v6(net).is_empty() } else { // Get a random address if available - inner.address_pool.can_allocate_v6(prefix).unwrap_or(false) - } - } - - fn allocate_net_v6_inner( - inner: &mut NetworkStateFields, - machine_registry_inner: &mut MachineRegistryInner, - owner_tag: OwnerTag, - opt_address: Option, - prefix: u8, - ) -> MachineRegistryResult { - let Some(_network_state_ipv6) = &mut inner.ipv6 else { - return Err(MachineRegistryError::NoAllocation); - }; - - // See if we are requesting a specific address - let net = if let Some(address) = opt_address { - // Get the net form for this address - let net = Ipv6Net::new(address, prefix).expect("must succeed"); - inner + self.fields .address_pool - .reserve_allocation_v6(net, Some(owner_tag))?; - net - } else { - // Get a random address if available - let Some(allocation) = inner.address_pool.allocate_random_v6( - machine_registry_inner.srng(), - prefix, - owner_tag, - )? - else { - return Err(MachineRegistryError::NoAllocation); - }; - allocation - }; - - Ok(net) - } - - fn release_subnet_v4_inner( - inner: &mut NetworkStateFields, - net: Ipv4Net, - ) -> MachineRegistryResult> { - inner.address_pool.release_allocation_v4(net) - } - - fn release_subnet_v6_inner( - inner: &mut NetworkStateFields, - net: Ipv6Net, - ) -> MachineRegistryResult> { - inner.address_pool.release_allocation_v6(net) - } - - pub fn release_all_addresses>( - &self, - addrs: I, - ) -> MachineRegistryResult<()> { - let mut ok = true; - for addr in addrs { - match addr { - IpAddr::V4(ipv4_addr) => { - if Self::release_subnet_v4_inner( - &mut *inner, - Ipv4Net::new(ipv4_addr, 32).expect("must succeed"), - ) - .is_err() - { - ok = false; - } - } - IpAddr::V6(ipv6_addr) => { - if Self::release_subnet_v6_inner( - &mut *inner, - Ipv6Net::new(ipv6_addr, 128).expect("must succeed"), - ) - .is_err() - { - ok = false; - } - } - } - } - if ok { - Ok(()) - } else { - Err(MachineRegistryError::NoAllocation) + .can_allocate_v6(prefix) + .unwrap_or(false) } } + + pub fn release_address_v6( + &mut self, + addr: Ipv6Addr, + ) -> MachineRegistryResult> { + self.release_subnet_v6(Ipv6Net::new(addr, 128).expect("must succeed")) + } + + pub fn release_subnet_v6(&mut self, net: Ipv6Net) -> MachineRegistryResult> { + let mut address_pool = self.fields.address_pool.clone(); + let opt_tag = address_pool.release_allocation_v6(net)?; + + // Update fields + self.fields = Arc::new(NetworkStateFields { + address_pool, + ..(*self.fields).clone() + }); + Ok(opt_tag) + } } impl State for NetworkState { diff --git a/veilid-tools/src/virtual_network/router_server/machine_registry/state/template_state.rs b/veilid-tools/src/virtual_network/router_server/machine_registry/state/template_state.rs index 2deff63a..b8e9c90e 100644 --- a/veilid-tools/src/virtual_network/router_server/machine_registry/state/template_state.rs +++ b/veilid-tools/src/virtual_network/router_server/machine_registry/state/template_state.rs @@ -1,15 +1,15 @@ use super::*; #[derive(Debug)] -struct TemplateStateUnlockedInner { +struct TemplateStateImmutable { id: TemplateStateId, name: String, } -#[derive(Debug)] +#[derive(Debug, Clone)] struct PerNetworkInfo { limit_machine_count: Option, - machines: HashSet, + machines: imbl::HashSet, } #[derive(Debug, Clone)] @@ -18,20 +18,20 @@ enum BlueprintAvailability { Generate(BlueprintState), } -#[derive(Debug)] -struct TemplateStateInner { +#[derive(Debug, Clone)] +struct TemplateStateFields { limit_machine_count: Option, limit_machines_per_network: Option>, locations_list: Option, - machines: HashSet, - machines_per_network: HashMap, - disable_capabilities: Vec, + machines: imbl::HashSet, + machines_per_network: imbl::HashMap, + disable_capabilities: imbl::Vector>, } #[derive(Debug, Clone)] pub struct TemplateState { - unlocked_inner: Arc, - inner: Arc>, + immutable: Arc, + fields: Arc, } pub type TemplateStateId = StateId; @@ -39,61 +39,85 @@ pub type TemplateStateId = StateId; impl TemplateState { pub fn new(id: TemplateStateId, name: String) -> Self { Self { - unlocked_inner: Arc::new(TemplateStateUnlockedInner { id, name }), - inner: Arc::new(Mutex::new(TemplateStateInner { + immutable: Arc::new(TemplateStateImmutable { id, name }), + fields: Arc::new(TemplateStateFields { limit_machine_count: None, limit_machines_per_network: None, locations_list: None, - machines: HashSet::new(), - machines_per_network: HashMap::new(), - disable_capabilities: Vec::new(), - })), + machines: imbl::HashSet::new(), + machines_per_network: imbl::HashMap::new(), + disable_capabilities: imbl::Vector::new(), + }), } } - pub fn set_disable_capabilities(&self, disable_capabilities: Vec) { - let mut inner = self.inner.lock(); - inner.disable_capabilities = disable_capabilities; + pub fn set_disable_capabilities(&mut self, disable_capabilities: Vec) { + let disable_capabilities = + imbl::Vector::from_iter(disable_capabilities.into_iter().map(Arc::new)); + // Update fields + self.fields = Arc::new(TemplateStateFields { + disable_capabilities, + ..(*self.fields).clone() + }); } - pub fn set_networks_list(&self, networks: WeightedList) { - let mut inner = self.inner.lock(); - inner.locations_list = Some(MachineLocationsList::Networks { networks }) + pub fn set_networks_list(&mut self, networks: WeightedList) { + let locations_list = Some(MachineLocationsList::Networks { networks }); + + // Update fields + self.fields = Arc::new(TemplateStateFields { + locations_list, + ..(*self.fields).clone() + }); } - pub fn set_blueprints_list(&self, blueprints: WeightedList) { - let mut inner = self.inner.lock(); - inner.locations_list = Some(MachineLocationsList::Blueprints { blueprints }) + pub fn set_blueprints_list(mut self, blueprints: WeightedList) { + let locations_list = Some(MachineLocationsList::Blueprints { blueprints }); + + // Update fields + self.fields = Arc::new(TemplateStateFields { + locations_list, + ..(*self.fields).clone() + }); } - pub fn clear_locations_list(&self) { - let mut inner = self.inner.lock(); - inner.locations_list = None; + pub fn clear_locations_list(&mut self) { + let locations_list = None; + + // Update fields + self.fields = Arc::new(TemplateStateFields { + locations_list, + ..(*self.fields).clone() + }); } - pub fn set_limit_machine_count(&self, limit_machine_count: Option) { - let mut inner = self.inner.lock(); - inner.limit_machine_count = limit_machine_count; + pub fn set_limit_machine_count(&mut self, limit_machine_count: Option) { + // Update fields + self.fields = Arc::new(TemplateStateFields { + limit_machine_count, + ..(*self.fields).clone() + }); } pub fn set_limit_machines_per_network( - &self, + &mut self, limit_machines_per_network: Option>, ) { - let mut inner = self.inner.lock(); - inner.limit_machines_per_network = limit_machines_per_network; + // Update fields + self.fields = Arc::new(TemplateStateFields { + limit_machines_per_network, + ..(*self.fields).clone() + }); } - fn is_network_available_inner( - inner: &TemplateStateInner, - network_state: NetworkState, - ) -> MachineRegistryResult { + fn is_network_available(&self, network_state: NetworkState) -> MachineRegistryResult { // If the network is not active, it is not available if !network_state.is_active()? { return Ok(false); } + // Get the per network info - let Some(pni) = inner.machines_per_network.get(&network_state.id()) else { + let Some(pni) = self.fields.machines_per_network.get(&network_state.id()) else { // If we haven't allocated anything in the network yet it is // by definition available return Ok(true); @@ -110,8 +134,8 @@ impl TemplateState { Ok(true) } - fn is_blueprint_available_inner( - inner: &TemplateStateInner, + fn is_blueprint_available( + &self, machine_registry_inner: &MachineRegistryInner, blueprint_state: BlueprintState, ) -> MachineRegistryResult> { @@ -120,7 +144,7 @@ impl TemplateState { if let Some(available_network_state) = blueprint_state.for_each_network_id(|id| { // Check the network's availability let network_state = machine_registry_inner.network_states().get_state(id)?; - if Self::is_network_available_inner(inner, network_state.clone())? { + if self.is_network_available(network_state.clone())? { // We found one return Ok(Some(network_state)); } @@ -145,16 +169,14 @@ impl TemplateState { &self, machine_registry_inner: &MachineRegistryInner, ) -> MachineRegistryResult { - let inner = self.inner.lock(); - // See if we have reached our machine limit - if let Some(limit_machine_count) = inner.limit_machine_count { - if inner.machines.len() >= limit_machine_count { + if let Some(limit_machine_count) = self.fields.limit_machine_count { + if self.fields.machines.len() >= limit_machine_count { return Ok(false); } } - let Some(locations_list) = inner.locations_list.as_ref() else { + let Some(locations_list) = self.fields.locations_list.as_ref() else { return Ok(false); }; @@ -165,7 +187,7 @@ impl TemplateState { .try_filter(|id| { let network_state = machine_registry_inner.network_states().get_state(*id)?; - Self::is_network_available_inner(&*inner, network_state) + self.is_network_available(network_state) })? .is_none() { @@ -179,12 +201,8 @@ impl TemplateState { let blueprint_state = machine_registry_inner.blueprint_states().get_state(*id)?; - Self::is_blueprint_available_inner( - &*inner, - machine_registry_inner, - blueprint_state, - ) - .map(|x| x.is_some()) + self.is_blueprint_available(machine_registry_inner, blueprint_state) + .map(|x| x.is_some()) })? .is_none() { @@ -200,17 +218,15 @@ impl TemplateState { &mut self, machine_registry_inner: &mut MachineRegistryInner, ) -> MachineRegistryResult { - let mut inner = self.inner.lock(); - // See if we have reached our machine limit - if let Some(limit_machine_count) = inner.limit_machine_count { - if inner.machines.len() < limit_machine_count.try_into().unwrap_or(usize::MAX) { + if let Some(limit_machine_count) = self.fields.limit_machine_count { + if self.fields.machines.len() < limit_machine_count.try_into().unwrap_or(usize::MAX) { return Err(MachineRegistryError::TemplateComplete); } } // If existing networks are all full, we'd have to allocate one, see if we'd be able to do that - let Some(locations_list) = inner.locations_list.as_ref() else { + let Some(locations_list) = self.fields.locations_list.as_ref() else { return Err(MachineRegistryError::TemplateComplete); }; @@ -220,7 +236,7 @@ impl TemplateState { // Filter the weighted list of networks to those that are still active and or not yet started let Some(available_networks) = networks.try_filter_map(|id| { let network_state = machine_registry_inner.network_states().get_state(*id)?; - if Self::is_network_available_inner(&*inner, network_state.clone())? { + if self.is_network_available(network_state.clone())? { Ok(Some(network_state)) } else { Ok(None) @@ -244,11 +260,7 @@ impl TemplateState { let blueprint_state = machine_registry_inner.blueprint_states().get_state(*id)?; - Self::is_blueprint_available_inner( - &*inner, - machine_registry_inner, - blueprint_state, - ) + self.is_blueprint_available(machine_registry_inner, blueprint_state) })? else { return Err(MachineRegistryError::BlueprintComplete); @@ -270,6 +282,8 @@ impl TemplateState { // Allocate a machine id let machine_state_id = machine_registry_inner.machine_states_mut().allocate_id(); +xxx continue here + // Create an anonymous machine state let machine_state = MachineState::new(machine_state_id, None); @@ -309,8 +323,12 @@ impl TemplateState { .machines_per_network .entry(network_state.id()) .or_insert_with(|| { - let limit_machine_count = limit_machines_per_network - .map(|wl| machine_registry_inner.srng().weighted_choice_ref(&wl).clone()); + let limit_machine_count = limit_machines_per_network.map(|wl| { + machine_registry_inner + .srng() + .weighted_choice_ref(&wl) + .clone() + }); PerNetworkInfo { limit_machine_count, machines: HashSet::new(),