Commit d6099740 authored by nanamicat's avatar nanamicat

Update

parent 9d847083
......@@ -95,23 +95,18 @@ pub struct Database {
pub connections: BTreeMap<RouterID, BTreeMap<RouterID, Connection>>,
}
pub static DATABASE: std::sync::LazyLock<Database> = std::sync::LazyLock::new(|| Database::load());
pub static DATABASE: std::sync::LazyLock<Database> = std::sync::LazyLock::new(|| Database {
routers: register(load_file("import/data/Router.json"), |r| r.id.0, |r| r.name.clone(), &ROUTER_ID_REGISTRY),
gateways: load_file("import/data/Gateway.json"),
gateway_groups: load_file("import/data/GatewayGroup.json"),
regions: load_file("import/data/Region.json"),
connections: load_file("import/connections.json"),
});
static ROUTER_ID_REGISTRY: OnceLock<StringInterner<StringBackend<RouterID>>> = OnceLock::new();
impl Database {
pub fn load() -> Self {
Self {
routers: register(Self::load_file("import/data/Router.json"), |r| r.id.0, |r| r.name.clone(), &ROUTER_ID_REGISTRY),
gateways: Self::load_file("import/data/Gateway.json"),
gateway_groups: Self::load_file("import/data/GatewayGroup.json"),
regions: Self::load_file("import/data/Region.json"),
connections: Self::load_file("import/connections.json"),
}
}
fn load_file<T: serde::de::DeserializeOwned>(path: &str) -> T {
serde_json::from_str(&std::fs::read_to_string(path).unwrap()).unwrap()
}
fn load_file<T: serde::de::DeserializeOwned>(path: &str) -> T {
serde_json::from_str(&std::fs::read_to_string(path).unwrap()).unwrap()
}
pub fn register<T, I, N, S, Sym>(mut data: Vec<T>, num: N, str: S, registry: &OnceLock<StringInterner<StringBackend<Sym>>>) -> Vec<T>
......@@ -147,18 +142,22 @@ fn deserialize_router_id<'de, D>(deserializer: D) -> Result<RouterID, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
ROUTER_ID_REGISTRY.get().unwrap().get(&s).ok_or_else(|| serde::de::Error::custom(format!("Unknown router: {s}")))
ROUTER_ID_REGISTRY
.get()
.unwrap()
.get(&String::deserialize(deserializer)?)
.ok_or_else(|| serde::de::Error::custom(format!("Unknown router")))
}
fn serialize_router_id<S>(id: &RouterID, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let s = ROUTER_ID_REGISTRY
.get()
.unwrap()
.resolve(*id)
.ok_or_else(|| serde::ser::Error::custom(format!("Unknown id: {}", id.0)))?;
serializer.serialize_str(s)
serializer.serialize_str(
ROUTER_ID_REGISTRY
.get()
.unwrap()
.resolve(*id)
.ok_or_else(|| serde::ser::Error::custom(format!("Unknown id: {}", id.0)))?,
)
}
......@@ -33,7 +33,6 @@ async fn main() -> Result<()> {
tracing_subscriber::fmt::init();
let config: Settings = Config::builder().add_source(Environment::default()).build()?.try_deserialize()?;
let regions: Vec<RegionID> = DATABASE.regions.iter().enumerate().map(|(i, _)| RegionID(i as u8)).collect();
let gateways_group: BTreeMap<GatewayGroupID, Vec<&data::Gateway>> = DATABASE
.gateway_groups
.iter()
......@@ -43,7 +42,7 @@ async fn main() -> Result<()> {
})
.collect();
let routers: BTreeMap<RouterID, Router> = DATABASE.routers.iter().map(|c| (c.id, Router::new(c, &regions, &gateways_group))).collect();
let routers: BTreeMap<RouterID, Router> = DATABASE.routers.iter().map(|c| (c.id, Router::new(c, &gateways_group))).collect();
let routers = Arc::new(RwLock::new(routers));
let listener = tokio::net::TcpListener::bind(config.http_bind).await?;
......@@ -88,7 +87,7 @@ async fn main() -> Result<()> {
&& let Some(router) = routers.get(&uplink.id)
&& router.is_online()
&& router.last_update != now
&& let Some(downlink) = router.update(now, &routers, &regions, &gateways_group)
&& let Some(downlink) = router.update(now, &routers, &gateways_group)
{
updating.router_id = router.id;
updating.message = downlink;
......
......@@ -34,7 +34,7 @@ impl PartialEq<Self> for Router {
impl Eq for Router {}
impl Router {
pub fn new(data: &data::Router, regions: &Vec<RegionID>, gateway_groups: &BTreeMap<GatewayGroupID, Vec<&data::Gateway>>) -> Self {
pub fn new(data: &data::Router, gateway_groups: &BTreeMap<GatewayGroupID, Vec<&data::Gateway>>) -> Self {
Self {
id: data.id,
version: rand::random(),
......@@ -45,14 +45,16 @@ impl Router {
.map(|(&from, _)| (from, Default::default()))
.collect(),
via: DATABASE.routers.iter().filter(|r| r.id != data.id).map(|r| (r.id, r.id)).collect(),
plan: regions
plan: DATABASE
.regions
.iter()
.map(|&region| {
.enumerate()
.map(|(r, _)| {
(
region,
RegionID(r as u8),
gateway_groups
.iter()
.map(|(&gid, gws)| (gid, gws.iter().min_by_key(|gw| Self::guess_metric(data, gw, &region)).unwrap().id))
.map(|(&gid, gws)| (gid, gws.iter().min_by_key(|gw| Self::guess_metric(data, gw, r)).unwrap().id))
.collect(),
)
})
......@@ -63,10 +65,8 @@ impl Router {
}
}
fn guess_metric(data: &data::Router, gw: &data::Gateway, region: &RegionID) -> i32 {
gw.metrics[region.0 as usize]
.saturating_add(gw.cost_outbound)
.saturating_add(if gw.router == data.id { 0 } else { 100 })
fn guess_metric(data: &data::Router, gw: &data::Gateway, region: usize) -> i32 {
gw.metrics[region].saturating_add(gw.cost_outbound).saturating_add(if gw.router == data.id { 0 } else { 100 })
}
pub fn online(&mut self, addr: SocketAddr, now: Instant) {
......@@ -144,7 +144,7 @@ impl Router {
}
}
pub fn update(&self, now: Instant, routers: &BTreeMap<RouterID, Router>, regions: &Vec<RegionID>, gateway_groups: &BTreeMap<GatewayGroupID, Vec<&data::Gateway>>) -> Option<Downlink> {
pub fn update(&self, now: Instant, routers: &BTreeMap<RouterID, Router>, gateway_groups: &BTreeMap<GatewayGroupID, Vec<&data::Gateway>>) -> Option<Downlink> {
let penalty = PENALTY_MIN + (PENALTY as f32 * f32::exp2(-now.duration_since(self.last_update).div_duration_f32(HALF_LIFE))) as i32;
let mut changed_via = BTreeMap::new();
let mut changed_plan = BTreeMap::new();
......@@ -179,14 +179,15 @@ impl Router {
}
// Plan updates (Gateways)
for &region in regions {
for (r, _) in DATABASE.regions.iter().enumerate() {
let region_id = RegionID(r as u8);
for (&gid, gateways) in gateway_groups {
let current_gw = self.plan[&region][&gid];
let current_gw = self.plan[&region_id][&gid];
let current_metric = metrics[&DATABASE.gateways.iter().find(|f| f.id == current_gw).unwrap().router];
let (best_gw, best_metric) = gateways
.iter()
.map(|g| (g, metrics[&g.router].saturating_add(g.cost_outbound).saturating_add(g.metrics[region.0 as usize])))
.map(|g| (g, metrics[&g.router].saturating_add(g.cost_outbound).saturating_add(g.metrics[r])))
.min_by_key(|(_, m)| *m)
.unwrap();
......@@ -194,7 +195,7 @@ impl Router {
if best_metric.saturating_add(penalty) < current_metric {
overcome = true;
}
changed_plan.entry(region).or_insert_with(BTreeMap::new).insert(gid, best_gw.id);
changed_plan.entry(region_id).or_insert_with(BTreeMap::new).insert(gid, best_gw.id);
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment