From 7e9489a65aba3e6993d8b96f6ef09e34a50837c1 Mon Sep 17 00:00:00 2001 From: Adam Spofford <93943719+adamspofford-dfinity@users.noreply.github.com> Date: Thu, 25 Jul 2024 09:53:41 -0700 Subject: [PATCH 1/7] Release 0.37.1 (#576) --- CHANGELOG.md | 2 ++ Cargo.lock | 12 ++++++------ Cargo.toml | 8 ++++---- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f95901ec..09e8a970 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +## [0.37.1] - 2024-07-25 + * Bug fix: Add `api/v2` prefix to read_state requests for hyper transport ## [0.37.0] - 2024-07-23 diff --git a/Cargo.lock b/Cargo.lock index 7a31d329..c2e4fb46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1083,7 +1083,7 @@ dependencies = [ [[package]] name = "ic-agent" -version = "0.37.0" +version = "0.37.1" dependencies = [ "async-lock", "backoff", @@ -1148,7 +1148,7 @@ dependencies = [ [[package]] name = "ic-identity-hsm" -version = "0.37.0" +version = "0.37.1" dependencies = [ "hex", "ic-agent", @@ -1160,7 +1160,7 @@ dependencies = [ [[package]] name = "ic-transport-types" -version = "0.37.0" +version = "0.37.1" dependencies = [ "candid", "hex", @@ -1176,7 +1176,7 @@ dependencies = [ [[package]] name = "ic-utils" -version = "0.37.0" +version = "0.37.1" dependencies = [ "async-trait", "candid", @@ -1239,7 +1239,7 @@ dependencies = [ [[package]] name = "icx" -version = "0.37.0" +version = "0.37.1" dependencies = [ "anyhow", "candid", @@ -1257,7 +1257,7 @@ dependencies = [ [[package]] name = "icx-cert" -version = "0.37.0" +version = "0.37.1" dependencies = [ "anyhow", "base64", diff --git a/Cargo.toml b/Cargo.toml index a435ed5e..535c20fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,7 @@ members = [ ] [workspace.package] -version = "0.37.0" +version = "0.37.1" authors = ["DFINITY Stiftung "] edition = "2021" repository = "https://github.com/dfinity/agent-rs" @@ -22,9 +22,9 @@ rust-version = "1.75.0" license = "Apache-2.0" [workspace.dependencies] -ic-agent = { path = "ic-agent", version = "0.37.0", default-features = false } -ic-utils = { path = "ic-utils", version = "0.37.0" } -ic-transport-types = { path = "ic-transport-types", version = "0.37.0" } +ic-agent = { path = "ic-agent", version = "0.37.1", default-features = false } +ic-utils = { path = "ic-utils", version = "0.37.1" } +ic-transport-types = { path = "ic-transport-types", version = "0.37.1" } ic-certification = "2.2" candid = "0.10.1" From f6874acca2b69e43fe0f6b3b89a58e467a6af6a6 Mon Sep 17 00:00:00 2001 From: Nikolay Komarevskiy Date: Mon, 26 Aug 2024 11:46:54 +0300 Subject: [PATCH 2/7] feat: add availability penalty for latency-routing --- .../dynamic_routing/dynamic_route_provider.rs | 11 +- .../snapshot/latency_based_routing.rs | 475 ++++++++++++------ .../snapshot/round_robin_routing.rs | 16 +- .../snapshot/routing_snapshot.rs | 2 +- 4 files changed, 347 insertions(+), 157 deletions(-) diff --git a/ic-agent/src/agent/http_transport/dynamic_routing/dynamic_route_provider.rs b/ic-agent/src/agent/http_transport/dynamic_routing/dynamic_route_provider.rs index 855fe566..e05f6f4d 100644 --- a/ic-agent/src/agent/http_transport/dynamic_routing/dynamic_route_provider.rs +++ b/ic-agent/src/agent/http_transport/dynamic_routing/dynamic_route_provider.rs @@ -42,7 +42,7 @@ const MAINNET_ROOT_SUBNET_ID: &str = const FETCH_PERIOD: Duration = Duration::from_secs(5); const FETCH_RETRY_INTERVAL: Duration = Duration::from_millis(250); const TIMEOUT_AWAIT_HEALTHY_SEED: Duration = Duration::from_millis(1000); -const HEALTH_CHECK_TIMEOUT: Duration = Duration::from_secs(2); +const HEALTH_CHECK_TIMEOUT: Duration = Duration::from_secs(1); const HEALTH_CHECK_PERIOD: Duration = Duration::from_secs(1); const DYNAMIC_ROUTE_PROVIDER: &str = "DynamicRouteProvider"; @@ -178,9 +178,12 @@ where fn n_ordered_routes(&self, n: usize) -> Result, AgentError> { let snapshot = self.routing_snapshot.load(); - let nodes = snapshot.next_n_nodes(n).ok_or_else(|| { - AgentError::RouteProviderError("No healthy API nodes found.".to_string()) - })?; + let nodes = snapshot.next_n_nodes(n); + if nodes.is_empty() { + return Err(AgentError::RouteProviderError( + "No healthy API nodes found.".to_string(), + )); + }; let urls = nodes.iter().map(|n| n.to_routing_url()).collect(); Ok(urls) } diff --git a/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/latency_based_routing.rs b/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/latency_based_routing.rs index 7de1bbc6..54ad4939 100644 --- a/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/latency_based_routing.rs +++ b/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/latency_based_routing.rs @@ -1,29 +1,152 @@ -use std::{collections::HashSet, time::Duration}; +use std::{ + collections::{HashSet, VecDeque}, + time::Duration, +}; use rand::Rng; -use simple_moving_average::{SumTreeSMA, SMA}; use crate::agent::http_transport::dynamic_routing::{ health_check::HealthCheckStatus, node::Node, snapshot::routing_snapshot::RoutingSnapshot, }; -// Some big value implying that node is unhealthy, should be much bigger than node's latency. -const MAX_LATENCY: Duration = Duration::from_secs(500); - +// Determines the size of the sliding window used for store latencies and availabilities of the node. const WINDOW_SIZE: usize = 15; +// Determines the decay rate of the exponential decay function used for weights generation. +const LAMBDA_DECAY: f64 = 0.3; + +/// Generates exponentially decaying weights for the sliding window. +fn generate_exp_decaying_weights(n: usize, lambda: f64) -> Vec { + let mut weights: Vec = Vec::with_capacity(n); + for i in 0..n { + let weight = (-lambda * i as f64).exp(); + weights.push(weight); + } + weights +} -// Algorithmic complexity: add sample - O(log(N)), get average - O(1). -// Space complexity: O(N) -type LatencyMovAvg = SumTreeSMA; - -/// A node, which stores health check latencies in the form of moving average. +// Node with latencies and availability metrics used for generating routing URLs based on the node's score. #[derive(Clone, Debug)] -struct WeightedNode { +struct NodeWithMetrics { + // Node information. node: Node, - /// Moving mean of latencies measurements. - latency_mov_avg: LatencyMovAvg, - /// Weight of the node (invers of the average latency), used for stochastic weighted random sampling. - weight: f64, + // Size of the sliding window used for store latencies and availabilities of the node. + window_size: usize, + /// Reflects the status of the most recent health check. It should be the same as the last element in `availabilities`. + is_healthy: bool, + /// Sliding window with latency measurements. + latencies: VecDeque, + /// Sliding window with availability measurements. + availabilities: VecDeque, + /// Overall score of the node. Calculated based on latencies and availabilities arrays. This score is used in `next_n_nodes()` and `next_node()` methods. + score: f64, +} + +impl NodeWithMetrics { + pub fn new(node: Node, window_size: usize) -> Self { + Self { + node, + window_size, + is_healthy: false, + latencies: VecDeque::with_capacity(window_size), + availabilities: VecDeque::with_capacity(window_size), + score: 0.0, + } + } + + pub fn add_latency_measurement(&mut self, latency: Option) { + self.is_healthy = latency.is_some(); + if let Some(duration) = latency { + self.latencies.push_back(duration.as_secs_f64()); + while self.latencies.len() > self.window_size { + self.latencies.pop_front(); + } + self.availabilities.push_back(true); + } else { + self.availabilities.push_back(false); + } + while self.availabilities.len() > self.window_size { + self.availabilities.pop_front(); + } + } +} + +/// Computes the score of the node based on the latencies, availabilities and window weights. +/// `window_weights_sum`` is passed for efficiency reasons, as it is pre-calculated. +fn compute_score( + window_weights: &[f64], + window_weights_sum: f64, + availabilities: &VecDeque, + latencies_secs: &VecDeque, + use_availability_penalty: bool, +) -> f64 { + let weights_size = window_weights.len(); + let availabilities_size = availabilities.len(); + let latencies_size = latencies_secs.len(); + + if weights_size < availabilities_size { + panic!( + "Weights array of size {weights_size} is smaller than array of availabilities of size {availabilities_size}", + ); + } else if weights_size < latencies_size { + panic!( + "Weights array of size {weights_size} is smaller than array of latencies of size {latencies_size}", + ); + } + + // Compute normalized availability score [0.0, 1.0]. + let score_a = if !use_availability_penalty { + 1.0 + } else if availabilities.is_empty() { + 0.0 + } else { + let mut score = 0.0; + + // Compute weighted score. Weights are applied in reverse order. + for (idx, availability) in availabilities.iter().rev().enumerate() { + score += window_weights[idx] * (*availability as u8 as f64); + } + + // Normalize the score. + let weights_sum = if availabilities_size < weights_size { + // Use partial sum of weights, if the window is not full. + let partial_weights_sum: f64 = window_weights.iter().take(availabilities_size).sum(); + partial_weights_sum + } else { + // Use pre-calculated sum, if the window is full. + window_weights_sum + }; + + score /= weights_sum; + + score + }; + + // Compute latency score (not normalized). + let score_l = if latencies_secs.is_empty() { + 0.0 + } else { + let mut score = 0.0; + + // Compute weighted score. Weights are applied in reverse order. Latency is inverted, so that smaller latencies have higher score. + for (idx, latency) in latencies_secs.iter().rev().enumerate() { + score += window_weights[idx] / latency; + } + + let weights_sum = if latencies_size < weights_size { + let partial_weights_sum: f64 = window_weights.iter().take(latencies_secs.len()).sum(); + partial_weights_sum + } else { + // Use pre-calculated sum. + window_weights_sum + }; + + score /= weights_sum; + + score + }; + + // Combine availability and latency scores via product to emphasize the importance of both metrics. + score_l * score_a } /// Routing snapshot for latency-based routing. @@ -31,19 +154,44 @@ struct WeightedNode { /// Nodes with smaller average latencies are preferred for routing. #[derive(Default, Debug, Clone)] pub struct LatencyRoutingSnapshot { - weighted_nodes: Vec, + nodes_with_metrics: Vec, existing_nodes: HashSet, + window_weights: Vec, + window_weights_sum: f64, + use_availability_penalty: bool, } /// Implementation of the LatencyRoutingSnapshot. impl LatencyRoutingSnapshot { /// Creates a new LatencyRoutingSnapshot. pub fn new() -> Self { + // Weights are ordered from left to right, where the leftmost weight is for the most recent health check. + let window_weights = generate_exp_decaying_weights(WINDOW_SIZE, LAMBDA_DECAY); + // Pre-calculate the sum of weights for efficiency reasons. + let window_weights_sum: f64 = window_weights.iter().sum(); + Self { - weighted_nodes: vec![], + nodes_with_metrics: vec![], existing_nodes: HashSet::new(), + use_availability_penalty: true, + window_weights, + window_weights_sum, } } + + /// Sets whether to use availability penalty in the score computation. + pub fn set_availability_penalty(mut self, use_penalty: bool) -> Self { + self.use_availability_penalty = use_penalty; + self + } + + /// Sets the weights for the sliding window. + /// The weights are ordered from left to right, where the leftmost weight is for the most recent health check. + pub fn set_window_weights(mut self, weights: &[f64]) -> Self { + self.window_weights_sum = weights.iter().sum(); + self.window_weights = weights.to_vec(); + self + } } /// Helper function to sample nodes based on their weights. @@ -66,43 +214,46 @@ fn weighted_sample(weighted_nodes: &[(f64, &Node)], number: f64) -> Option bool { - !self.weighted_nodes.is_empty() + self.nodes_with_metrics.iter().any(|n| n.is_healthy) } fn next_node(&self) -> Option { - self.next_n_nodes(1).unwrap_or_default().into_iter().next() + self.next_n_nodes(1).into_iter().next() } - // Uses weighted random sampling algorithm without item replacement n times. - fn next_n_nodes(&self, n: usize) -> Option> { + // Uses weighted random sampling algorithm n times. Node can be selected at most once (sampling without replacement). + fn next_n_nodes(&self, n: usize) -> Vec { if n == 0 { - return Some(Vec::new()); + return Vec::new(); } - let n = std::cmp::min(n, self.weighted_nodes.len()); + // Preallocate array for a better efficiency. + let mut healthy_nodes = Vec::with_capacity(self.nodes_with_metrics.len()); + for n in &self.nodes_with_metrics { + if n.is_healthy { + healthy_nodes.push((n.score, &n.node)); + } + } - let mut nodes = Vec::with_capacity(n); + // Limit the number of returned nodes to the number of healthy nodes. + let n = std::cmp::min(n, healthy_nodes.len()); - let mut weighted_nodes: Vec<_> = self - .weighted_nodes - .iter() - .map(|n| (n.weight, &n.node)) - .collect(); + let mut nodes = Vec::with_capacity(n); let mut rng = rand::thread_rng(); for _ in 0..n { // Generate a random float in the range [0, 1) let rand_num = rng.gen::(); - if let Some(idx) = weighted_sample(weighted_nodes.as_slice(), rand_num) { - let node = weighted_nodes[idx].1; + if let Some(idx) = weighted_sample(healthy_nodes.as_slice(), rand_num) { + let node = healthy_nodes[idx].1; nodes.push(node.clone()); // Remove the item, so that it can't be selected anymore. - weighted_nodes.swap_remove(idx); + healthy_nodes.swap_remove(idx); } } - Some(nodes) + nodes } fn sync_nodes(&mut self, nodes: &[Node]) -> bool { @@ -125,38 +276,38 @@ impl RoutingSnapshot for LatencyRoutingSnapshot { // This happens after the first node health check round and a consequent update_node() invocation. for node in nodes_removed.into_iter() { self.existing_nodes.remove(&node); - let idx = self.weighted_nodes.iter().position(|x| x.node == node); - idx.map(|idx| self.weighted_nodes.swap_remove(idx)); + let idx = self.nodes_with_metrics.iter().position(|x| x.node == node); + idx.map(|idx| self.nodes_with_metrics.swap_remove(idx)); } has_added_nodes || has_removed_nodes } fn update_node(&mut self, node: &Node, health: HealthCheckStatus) -> bool { + // Skip the update if the node is not in the existing nodes. if !self.existing_nodes.contains(node) { return false; } - // If latency is None (meaning Node is unhealthy), we assign some big value - let latency = health.latency().unwrap_or(MAX_LATENCY); - - if let Some(idx) = self.weighted_nodes.iter().position(|x| &x.node == node) { - // Node is already in the array (it is not the first update_node() call). - self.weighted_nodes[idx].latency_mov_avg.add_sample(latency); - let latency_avg = self.weighted_nodes[idx].latency_mov_avg.get_average(); - // As nodes with smaller average latencies are preferred for routing, we use inverted values for weights. - self.weighted_nodes[idx].weight = 1.0 / latency_avg.as_secs_f64(); - } else { - // Node is not yet in array (first update_node() call). - let mut latency_mov_avg = LatencyMovAvg::from_zero(Duration::ZERO); - latency_mov_avg.add_sample(latency); - let weight = 1.0 / latency_mov_avg.get_average().as_secs_f64(); - self.weighted_nodes.push(WeightedNode { - latency_mov_avg, - node: node.clone(), - weight, - }) - } + let idx = self + .nodes_with_metrics + .iter() + .position(|x| &x.node == node) + .unwrap_or_else(|| { + let node = NodeWithMetrics::new(node.clone(), self.window_weights.len()); + self.nodes_with_metrics.push(node); + self.nodes_with_metrics.len() - 1 + }); + + self.nodes_with_metrics[idx].add_latency_measurement(health.latency()); + + self.nodes_with_metrics[idx].score = compute_score( + self.window_weights.as_slice(), + self.window_weights_sum, + &self.nodes_with_metrics[idx].availabilities, + &self.nodes_with_metrics[idx].latencies, + self.use_availability_penalty, + ); true } @@ -165,18 +316,16 @@ impl RoutingSnapshot for LatencyRoutingSnapshot { #[cfg(test)] mod tests { use std::{ - collections::{HashMap, HashSet}, + collections::{HashMap, HashSet, VecDeque}, time::Duration, }; - use simple_moving_average::SMA; - use crate::agent::http_transport::dynamic_routing::{ health_check::HealthCheckStatus, node::Node, snapshot::{ latency_based_routing::{ - weighted_sample, LatencyMovAvg, LatencyRoutingSnapshot, WeightedNode, MAX_LATENCY, + compute_score, weighted_sample, LatencyRoutingSnapshot, NodeWithMetrics, }, routing_snapshot::RoutingSnapshot, }, @@ -187,10 +336,11 @@ mod tests { // Arrange let snapshot = LatencyRoutingSnapshot::new(); // Assert - assert!(snapshot.weighted_nodes.is_empty()); + assert!(snapshot.nodes_with_metrics.is_empty()); assert!(snapshot.existing_nodes.is_empty()); assert!(!snapshot.has_nodes()); assert!(snapshot.next_node().is_none()); + assert!(snapshot.next_n_nodes(1).is_empty()); } #[test] @@ -203,7 +353,7 @@ mod tests { let is_updated = snapshot.update_node(&node, health); // Assert assert!(!is_updated); - assert!(snapshot.weighted_nodes.is_empty()); + assert!(snapshot.nodes_with_metrics.is_empty()); assert!(!snapshot.has_nodes()); assert!(snapshot.next_node().is_none()); } @@ -211,7 +361,9 @@ mod tests { #[test] fn test_update_for_existing_node_succeeds() { // Arrange - let mut snapshot = LatencyRoutingSnapshot::new(); + let mut snapshot = LatencyRoutingSnapshot::new() + .set_window_weights(&[2.0, 1.0]) + .set_availability_penalty(false); let node = Node::new("api1.com").unwrap(); let health = HealthCheckStatus::new(Some(Duration::from_secs(1))); snapshot.existing_nodes.insert(node.clone()); @@ -219,65 +371,51 @@ mod tests { let is_updated = snapshot.update_node(&node, health); assert!(is_updated); assert!(snapshot.has_nodes()); - let weighted_node = snapshot.weighted_nodes.first().unwrap(); - assert_eq!( - weighted_node.latency_mov_avg.get_average(), - Duration::from_secs(1) - ); - assert_eq!(weighted_node.weight, 1.0); + let node_with_metrics = snapshot.nodes_with_metrics.first().unwrap(); + assert_eq!(node_with_metrics.score, (2.0 / 1.0) / 2.0); assert_eq!(snapshot.next_node().unwrap(), node); // Check second update let health = HealthCheckStatus::new(Some(Duration::from_secs(2))); let is_updated = snapshot.update_node(&node, health); assert!(is_updated); - let weighted_node = snapshot.weighted_nodes.first().unwrap(); - assert_eq!( - weighted_node.latency_mov_avg.get_average(), - Duration::from_millis(1500) - ); - assert_eq!(weighted_node.weight, 1.0 / 1.5); + let node_with_metrics = snapshot.nodes_with_metrics.first().unwrap(); + assert_eq!(node_with_metrics.score, (2.0 / 2.0 + 1.0 / 1.0) / 3.0); // Check third update let health = HealthCheckStatus::new(Some(Duration::from_secs(3))); let is_updated = snapshot.update_node(&node, health); assert!(is_updated); - let weighted_node = snapshot.weighted_nodes.first().unwrap(); - assert_eq!( - weighted_node.latency_mov_avg.get_average(), - Duration::from_millis(2000) - ); - assert_eq!(weighted_node.weight, 0.5); + let node_with_metrics = snapshot.nodes_with_metrics.first().unwrap(); + assert_eq!(node_with_metrics.score, (2.0 / 3.0 + 1.0 / 2.0) / 3.0); // Check forth update with none let health = HealthCheckStatus::new(None); let is_updated = snapshot.update_node(&node, health); assert!(is_updated); - let weighted_node = snapshot.weighted_nodes.first().unwrap(); - let avg_latency = Duration::from_secs_f64((MAX_LATENCY.as_secs() as f64 + 6.0) / 4.0); - assert_eq!(weighted_node.latency_mov_avg.get_average(), avg_latency); - assert_eq!(weighted_node.weight, 1.0 / avg_latency.as_secs_f64()); - assert_eq!(snapshot.weighted_nodes.len(), 1); + let node_with_metrics = snapshot.nodes_with_metrics.first().unwrap(); + assert_eq!(node_with_metrics.score, (2.0 / 3.0 + 1.0 / 2.0) / 3.0); + assert!(!snapshot.has_nodes()); + assert_eq!(snapshot.nodes_with_metrics.len(), 1); assert_eq!(snapshot.existing_nodes.len(), 1); - assert_eq!(snapshot.next_node().unwrap(), node); + assert!(snapshot.next_node().is_none()); } #[test] fn test_sync_node_scenarios() { // Arrange + let window_size = 1; let mut snapshot = LatencyRoutingSnapshot::new(); let node_1 = Node::new("api1.com").unwrap(); // Sync with node_1 let nodes_changed = snapshot.sync_nodes(&[node_1.clone()]); assert!(nodes_changed); - assert!(snapshot.weighted_nodes.is_empty()); + assert!(snapshot.nodes_with_metrics.is_empty()); assert_eq!( snapshot.existing_nodes, HashSet::from_iter(vec![node_1.clone()]) ); // Add node_1 to weighted_nodes manually - snapshot.weighted_nodes.push(WeightedNode { - node: node_1.clone(), - latency_mov_avg: LatencyMovAvg::from_zero(Duration::ZERO), - weight: 0.0, - }); + snapshot + .nodes_with_metrics + .push(NodeWithMetrics::new(node_1.clone(), window_size)); // Sync with node_1 again let nodes_changed = snapshot.sync_nodes(&[node_1.clone()]); assert!(!nodes_changed); @@ -285,7 +423,7 @@ mod tests { snapshot.existing_nodes, HashSet::from_iter(vec![node_1.clone()]) ); - assert_eq!(snapshot.weighted_nodes[0].node, node_1); + assert_eq!(snapshot.nodes_with_metrics[0].node, node_1); // Sync with node_2 let node_2 = Node::new("api2.com").unwrap(); let nodes_changed = snapshot.sync_nodes(&[node_2.clone()]); @@ -295,13 +433,11 @@ mod tests { HashSet::from_iter(vec![node_2.clone()]) ); // Make sure node_1 was removed from weighted_nodes too - assert!(snapshot.weighted_nodes.is_empty()); + assert!(snapshot.nodes_with_metrics.is_empty()); // Add node_2 to weighted_nodes manually - snapshot.weighted_nodes.push(WeightedNode { - node: node_2.clone(), - latency_mov_avg: LatencyMovAvg::from_zero(Duration::ZERO), - weight: 0.0, - }); + snapshot + .nodes_with_metrics + .push(NodeWithMetrics::new(node_2.clone(), window_size)); // Sync with [node_2, node_3] let node_3 = Node::new("api3.com").unwrap(); let nodes_changed = snapshot.sync_nodes(&[node_3.clone(), node_2.clone()]); @@ -310,23 +446,22 @@ mod tests { snapshot.existing_nodes, HashSet::from_iter(vec![node_3.clone(), node_2.clone()]) ); - assert_eq!(snapshot.weighted_nodes[0].node, node_2); + assert_eq!(snapshot.nodes_with_metrics[0].node, node_2); // Add node_3 to weighted_nodes manually - snapshot.weighted_nodes.push(WeightedNode { - node: node_3, - latency_mov_avg: LatencyMovAvg::from_zero(Duration::ZERO), - weight: 0.0, - }); + snapshot + .nodes_with_metrics + .push(NodeWithMetrics::new(node_3, window_size)); // Sync with [] let nodes_changed = snapshot.sync_nodes(&[]); assert!(nodes_changed); assert!(snapshot.existing_nodes.is_empty()); // Make sure all nodes were removed from the healthy_nodes - assert!(snapshot.weighted_nodes.is_empty()); + assert!(snapshot.nodes_with_metrics.is_empty()); // Sync with [] again let nodes_changed = snapshot.sync_nodes(&[]); assert!(!nodes_changed); assert!(snapshot.existing_nodes.is_empty()); + assert!(!snapshot.has_nodes()); } #[test] @@ -386,56 +521,108 @@ mod tests { } #[test] - // #[ignore] + fn test_compute_score_with_penalty() { + let use_penalty = true; + + // Test empty arrays + let weights: &[f64] = &[]; + let weights_sum: f64 = weights.iter().sum(); + let availabilities = VecDeque::new(); + let latencies = VecDeque::new(); + + let score = compute_score( + weights, + weights_sum, + &availabilities, + &latencies, + use_penalty, + ); + assert_eq!(score, 0.0); + + // Test arrays with one element. + let weights: &[f64] = &[2.0, 1.0]; + let weights_sum: f64 = weights.iter().sum(); + let availabilities = vec![true].into(); + let latencies = vec![2.0].into(); + let score = compute_score( + weights, + weights_sum, + &availabilities, + &latencies, + use_penalty, + ); + let score_l = (2.0 / 2.0) / 2.0; + let score_a = 1.0; + assert_eq!(score, score_l * score_a); + + // Test arrays with two element. + let weights: &[f64] = &[2.0, 1.0]; + let weights_sum: f64 = weights.iter().sum(); + let availabilities = vec![true, false].into(); + let latencies = vec![1.0, 2.0].into(); + let score = compute_score( + weights, + weights_sum, + &availabilities, + &latencies, + use_penalty, + ); + let score_l = (2.0 / 2.0 + 1.0 / 1.0) / weights_sum; + let score_a = (2.0 * 0.0 + 1.0 * 1.0) / weights_sum; + assert_eq!(score, score_l * score_a); + + // Test arrays with arrays of different sizes. + let weights: &[f64] = &[3.0, 2.0, 1.0]; + let weights_sum: f64 = weights.iter().sum(); + let availabilities = vec![true, false, true].into(); + let latencies = vec![1.0, 2.0].into(); + let score = compute_score( + weights, + weights_sum, + &availabilities, + &latencies, + use_penalty, + ); + let score_l = (3.0 / 2.0 + 2.0 / 1.0) / 5.0; + let score_a = (3.0 * 1.0 + 2.0 * 0.0 + 1.0 * 1.0) / weights_sum; + assert_eq!(score, score_l * score_a); + } + + #[test] + #[ignore] // This test is for manual runs to see the statistics for nodes selection probability. fn test_stats_for_next_n_nodes() { // Arrange let mut snapshot = LatencyRoutingSnapshot::new(); + + let window_size = 1; + let node_1 = Node::new("api1.com").unwrap(); let node_2 = Node::new("api2.com").unwrap(); let node_3 = Node::new("api3.com").unwrap(); let node_4 = Node::new("api4.com").unwrap(); - let node_5 = Node::new("api5.com").unwrap(); - let node_6 = Node::new("api6.com").unwrap(); - let latency_mov_avg = LatencyMovAvg::from_zero(Duration::ZERO); - snapshot.weighted_nodes = vec![ - WeightedNode { - node: node_2.clone(), - latency_mov_avg: latency_mov_avg.clone(), - weight: 8.0, - }, - WeightedNode { - node: node_3.clone(), - latency_mov_avg: latency_mov_avg.clone(), - weight: 4.0, - }, - WeightedNode { - node: node_1.clone(), - latency_mov_avg: latency_mov_avg.clone(), - weight: 16.0, - }, - WeightedNode { - node: node_6.clone(), - latency_mov_avg: latency_mov_avg.clone(), - weight: 2.0, - }, - WeightedNode { - node: node_5.clone(), - latency_mov_avg: latency_mov_avg.clone(), - weight: 1.0, - }, - WeightedNode { - node: node_4.clone(), - latency_mov_avg: latency_mov_avg.clone(), - weight: 4.1, - }, - ]; + + let mut node_1 = NodeWithMetrics::new(node_1, window_size); + let mut node_2 = NodeWithMetrics::new(node_2, window_size); + let mut node_3 = NodeWithMetrics::new(node_3, window_size); + let mut node_4 = NodeWithMetrics::new(node_4, window_size); + + node_1.is_healthy = true; + node_2.is_healthy = true; + node_3.is_healthy = true; + node_4.is_healthy = false; + + node_1.score = 16.0; + node_2.score = 8.0; + node_3.score = 4.0; + + snapshot.nodes_with_metrics = vec![node_1, node_2, node_3, node_4]; let mut stats = HashMap::new(); let experiments = 30; - let select_nodes_count = 10; + let select_nodes_count = 1; for i in 0..experiments { - let nodes = snapshot.next_n_nodes(select_nodes_count).unwrap(); + let nodes = snapshot.next_n_nodes(select_nodes_count); println!("Experiment {i}: selected nodes {nodes:?}"); for item in nodes.into_iter() { *stats.entry(item).or_insert(1) += 1; diff --git a/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/round_robin_routing.rs b/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/round_robin_routing.rs index 318eb379..2f3fd421 100644 --- a/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/round_robin_routing.rs +++ b/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/round_robin_routing.rs @@ -45,16 +45,16 @@ impl RoutingSnapshot for RoundRobinRoutingSnapshot { .cloned() } - fn next_n_nodes(&self, n: usize) -> Option> { + fn next_n_nodes(&self, n: usize) -> Vec { if n == 0 { - return Some(Vec::new()); + return Vec::new(); } let healthy_nodes = Vec::from_iter(self.healthy_nodes.clone()); let healthy_count = healthy_nodes.len(); if n >= healthy_count { - return Some(healthy_nodes.clone()); + return healthy_nodes.clone(); } let idx = self.current_idx.fetch_add(n, Ordering::Relaxed) % healthy_count; @@ -67,7 +67,7 @@ impl RoutingSnapshot for RoundRobinRoutingSnapshot { nodes.extend_from_slice(&healthy_nodes[..n - nodes.len()]); } - Some(nodes) + nodes } fn sync_nodes(&mut self, nodes: &[Node]) -> bool { @@ -296,13 +296,13 @@ mod tests { ]; snapshot.healthy_nodes.extend(nodes.clone()); // First call - let mut n_nodes: Vec<_> = snapshot.next_n_nodes(3).expect("failed to get nodes"); + let mut n_nodes: Vec<_> = snapshot.next_n_nodes(3); // Second call - n_nodes.extend(snapshot.next_n_nodes(3).expect("failed to get nodes")); + n_nodes.extend(snapshot.next_n_nodes(3)); // Third call - n_nodes.extend(snapshot.next_n_nodes(4).expect("failed to get nodes")); + n_nodes.extend(snapshot.next_n_nodes(4)); // Fourth call - n_nodes.extend(snapshot.next_n_nodes(5).expect("failed to get nodes")); + n_nodes.extend(snapshot.next_n_nodes(5)); // Assert each node was returned 3 times let k = 3; let mut count_map = HashMap::new(); diff --git a/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/routing_snapshot.rs b/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/routing_snapshot.rs index 242abdfe..5357b271 100644 --- a/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/routing_snapshot.rs +++ b/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/routing_snapshot.rs @@ -9,7 +9,7 @@ pub trait RoutingSnapshot: Send + Sync + Clone + Debug { /// Get next node from the snapshot. fn next_node(&self) -> Option; /// Get up to n different nodes from the snapshot. - fn next_n_nodes(&self, n: usize) -> Option>; + fn next_n_nodes(&self, n: usize) -> Vec; /// Syncs the nodes in the snapshot with the provided list of nodes, returning `true` if the snapshot was updated. fn sync_nodes(&mut self, nodes: &[Node]) -> bool; /// Updates the health status of a specific node, returning `true` if the node was found and updated. From 298a8eeb6922fe1ab2998529b1462120f3cb0872 Mon Sep 17 00:00:00 2001 From: Nikolay Komarevskiy Date: Mon, 26 Aug 2024 12:56:29 +0300 Subject: [PATCH 3/7] chore: update cargo.toml and cargo.lock --- Cargo.lock | 702 ++++++++++++++++++++++++++++---------------- ic-agent/Cargo.toml | 1 - 2 files changed, 455 insertions(+), 248 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c2e4fb46..f49df689 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,11 +44,35 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + [[package]] name = "anstream" -version = "0.6.14" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", @@ -61,33 +85,33 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.3" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "windows-sys 0.52.0", @@ -108,6 +132,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + [[package]] name = "arrayvec" version = "0.5.2" @@ -152,7 +182,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.76", ] [[package]] @@ -293,9 +323,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.1" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cached" @@ -312,9 +342,9 @@ dependencies = [ [[package]] name = "candid" -version = "0.10.9" +version = "0.10.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7df77a80c72fcd356cf37ff59c812f37ff06dc9a81232b3aff0a308cb5996904" +checksum = "6c30ee7f886f296b6422c0ff017e89dd4f831521dfdcc76f3f71aae1ce817222" dependencies = [ "anyhow", "binread", @@ -342,7 +372,7 @@ dependencies = [ "lazy_static", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.76", ] [[package]] @@ -366,9 +396,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.5" +version = "1.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052" +checksum = "50d2eb3cd3d1bf4529e31c215ee6f93ec5a3d536d9f578f93d9d33ee19562932" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -376,11 +409,23 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "windows-targets 0.52.6", +] + [[package]] name = "clap" -version = "4.5.9" +version = "4.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462" +checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" dependencies = [ "clap_builder", "clap_derive", @@ -388,9 +433,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.9" +version = "4.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942" +checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" dependencies = [ "anstream", "anstyle", @@ -400,21 +445,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.8" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.76", ] [[package]] name = "clap_lex" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "codespan-reporting" @@ -428,9 +473,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "colored" @@ -476,11 +521,17 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" dependencies = [ "libc", ] @@ -761,7 +812,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.76", ] [[package]] @@ -836,35 +887,16 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "h2" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.1.0", + "http", "indexmap", "slab", "tokio", @@ -915,17 +947,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - [[package]] name = "http" version = "1.1.0" @@ -937,17 +958,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.1" @@ -955,7 +965,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.1.0", + "http", ] [[package]] @@ -965,7 +975,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17a08236c6f51c2ee95d840f45acf8fa9e339390e00b4ef640857b2f2a534d70" dependencies = [ "bytes", - "http-body 1.0.1", + "http-body", "http-body-util", ] @@ -977,8 +987,8 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "pin-project-lite", ] @@ -1000,29 +1010,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" -[[package]] -name = "hyper" -version = "0.14.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "tokio", - "tower-service", - "tracing", - "want", -] - [[package]] name = "hyper" version = "1.4.1" @@ -1032,10 +1019,11 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.5", - "http 1.1.0", - "http-body 1.0.1", + "h2", + "http", + "http-body", "httparse", + "httpdate", "itoa", "pin-project-lite", "smallvec", @@ -1050,8 +1038,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee4be2c948921a1a5320b629c4193916ed787a7f7f293fd3f7f5a6c9de74155" dependencies = [ "futures-util", - "http 1.1.0", - "hyper 1.4.1", + "http", + "hyper", "hyper-util", "rustls", "rustls-pki-types", @@ -1063,16 +1051,16 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.1.0", - "http-body 1.0.1", - "hyper 1.4.1", + "http", + "http-body", + "hyper", "pin-project-lite", "socket2", "tokio", @@ -1081,11 +1069,36 @@ dependencies = [ "tracing", ] +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "ic-agent" version = "0.37.1" dependencies = [ + "arc-swap", "async-lock", + "async-trait", "backoff", "cached", "candid", @@ -1093,11 +1106,11 @@ dependencies = [ "futures-util", "getrandom", "hex", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-to-bytes", "http-body-util", - "hyper 1.4.1", + "hyper", "hyper-rustls", "hyper-util", "ic-certification", @@ -1126,7 +1139,10 @@ dependencies = [ "thiserror", "time", "tokio", + "tokio-util", "tower", + "tracing", + "tracing-subscriber", "url", "wasm-bindgen", "wasm-bindgen-futures", @@ -1136,9 +1152,9 @@ dependencies = [ [[package]] name = "ic-certification" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20052ce9255fbe2de7041a4f6996fddd095ba1f31ae83b6c0ccdee5be6e7bbcf" +checksum = "e64ee3d8b6e81b51f245716d3e0badb63c283c00f3c9fb5d5219afc30b5bf821" dependencies = [ "hex", "serde", @@ -1285,9 +1301,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", "hashbrown", @@ -1313,9 +1329,9 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "is_terminal_polyfill" -version = "1.70.0" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -1334,9 +1350,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -1383,7 +1399,7 @@ version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" dependencies = [ - "regex-automata", + "regex-automata 0.4.7", ] [[package]] @@ -1400,9 +1416,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libloading" @@ -1460,7 +1476,7 @@ dependencies = [ "proc-macro2", "quote", "regex-syntax 0.6.29", - "syn 2.0.71", + "syn 2.0.76", ] [[package]] @@ -1472,6 +1488,15 @@ dependencies = [ "logos-codegen", ] +[[package]] +name = "matchers" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f099785f7595cc4b4553a174ce30dd7589ef93391ff414dbb67f62392b9e0ce1" +dependencies = [ + "regex-automata 0.1.10", +] + [[package]] name = "memchr" version = "2.7.4" @@ -1484,6 +1509,16 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +[[package]] +name = "minicov" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c71e683cd655513b99affab7d317deb690528255a0d5f717f1024093c12b169" +dependencies = [ + "cc", + "walkdir", +] + [[package]] name = "miniz_oxide" version = "0.7.4" @@ -1495,25 +1530,31 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.11" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ + "hermit-abi", "libc", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "mockito" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f6e023aa5bdf392aa06c78e4a4e6d498baab5138d0c993503350ebbc37bf1e" +checksum = "09b34bd91b9e5c5b06338d392463e1318d683cf82ec3d3af4014609be6e2108d" dependencies = [ "assert-json-diff", + "bytes", "colored", - "futures-core", - "hyper 0.14.30", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", "log", "rand", "regex", @@ -1575,21 +1616,11 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "object" -version = "0.36.1" +version = "0.36.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" dependencies = [ "memchr", ] @@ -1729,7 +1760,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.76", ] [[package]] @@ -1772,9 +1803,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "precomputed-hash" @@ -1822,9 +1856,9 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" +checksum = "b22d8e7369034b9a7132bc2008cac12f2013c8132b45e0554e6e20e2617f2156" dependencies = [ "bytes", "pin-project-lite", @@ -1832,6 +1866,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", + "socket2", "thiserror", "tokio", "tracing", @@ -1839,9 +1874,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.3" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddf517c03a109db8100448a4be38d498df8a210a99fe0e1b9eaf39e78c640efe" +checksum = "ba92fb39ec7ad06ca2582c0ca834dfeadcaf06ddfc8e635c80aa7e1c05315fdd" dependencies = [ "bytes", "rand", @@ -1856,9 +1891,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9096629c45860fc7fb143e125eb826b5e721e10be3263160c7d60ca832cf8c46" +checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" dependencies = [ "libc", "once_cell", @@ -1869,9 +1904,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -1923,9 +1958,9 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", @@ -1950,16 +1985,25 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.5" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", - "regex-automata", + "regex-automata 0.4.7", "regex-syntax 0.8.4", ] +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + [[package]] name = "regex-automata" version = "0.4.7" @@ -1985,19 +2029,19 @@ checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "reqwest" -version = "0.12.5" +version = "0.12.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" dependencies = [ "base64", "bytes", "futures-channel", "futures-core", "futures-util", - "http 1.1.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", - "hyper 1.4.1", + "hyper", "hyper-rustls", "hyper-util", "ipnet", @@ -2025,7 +2069,7 @@ dependencies = [ "wasm-streams", "web-sys", "webpki-roots", - "winreg", + "windows-registry", ] [[package]] @@ -2061,15 +2105,15 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" -version = "1.1.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" [[package]] name = "rustls" -version = "0.23.11" +version = "0.23.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4828ea528154ae444e5a642dbb7d5623354030dc9822b83fd9bb79683c7399d0" +checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" dependencies = [ "once_cell", "ring", @@ -2081,9 +2125,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" dependencies = [ "base64", "rustls-pki-types", @@ -2091,15 +2135,15 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" [[package]] name = "rustls-webpki" -version = "0.102.5" +version = "0.102.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a6fccd794a42c2c105b513a2f62bc3fd8f3ba57a4593677ceb0bd035164d78" +checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" dependencies = [ "ring", "rustls-pki-types", @@ -2161,9 +2205,9 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" dependencies = [ "serde_derive", ] @@ -2189,22 +2233,23 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.76", ] [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -2217,7 +2262,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.76", ] [[package]] @@ -2256,6 +2301,21 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -2277,9 +2337,9 @@ dependencies = [ [[package]] name = "similar" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42c91313f1d05da9b26f267f931cf178d4aba455b4c4622dd7355eb80c6640" +checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" [[package]] name = "simple_asn1" @@ -2342,15 +2402,15 @@ dependencies = [ [[package]] name = "stacker" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce" +checksum = "95a5daa25ea337c85ed954c0496e3bdd2c7308cc3b24cf7b50d04876654c579f" dependencies = [ "cc", "cfg-if", "libc", "psm", - "winapi", + "windows-sys 0.36.1", ] [[package]] @@ -2388,7 +2448,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.71", + "syn 2.0.76", ] [[package]] @@ -2416,9 +2476,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.71" +version = "2.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" +checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" dependencies = [ "proc-macro2", "quote", @@ -2430,6 +2490,9 @@ name = "sync_wrapper" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] [[package]] name = "term" @@ -2468,7 +2531,17 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.76", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", ] [[package]] @@ -2529,32 +2602,31 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.38.1" +version = "1.39.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb2caba9f80616f438e09748d5acda951967e1ea58508ef53d9c6402485a46df" +checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" dependencies = [ "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "tokio-macros" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.76", ] [[package]] @@ -2577,6 +2649,8 @@ dependencies = [ "bytes", "futures-core", "futures-sink", + "futures-util", + "hashbrown", "pin-project-lite", "tokio", ] @@ -2599,15 +2673,15 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -2629,7 +2703,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.76", ] [[package]] @@ -2639,6 +2713,50 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f751112709b4e791d8ce53e32c4ed2d353565a795ce84da2285393f41557bdf2" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "ansi_term", + "chrono", + "lazy_static", + "matchers", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", ] [[package]] @@ -2694,9 +2812,9 @@ checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" [[package]] name = "untrusted" @@ -2721,11 +2839,17 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "walkdir" @@ -2754,34 +2878,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.76", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", @@ -2791,9 +2916,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2801,31 +2926,32 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.76", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-bindgen-test" -version = "0.3.42" +version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bf62a58e0780af3e852044583deee40983e5886da43a271dd772379987667b" +checksum = "68497a05fb21143a08a7d24fc81763384a3072ee43c44e86aad1744d6adef9d9" dependencies = [ "console_error_panic_hook", "js-sys", + "minicov", "scoped-tls", "wasm-bindgen", "wasm-bindgen-futures", @@ -2834,13 +2960,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.42" +version = "0.3.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0" +checksum = "4b8220be1fa9e4c889b30fd207d4906657e7e90b12e0e6b0c8b8d8709f5de021" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.76", ] [[package]] @@ -2858,9 +2984,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -2893,11 +3019,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2906,6 +3032,58 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -2924,6 +3102,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -2967,6 +3154,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -2979,6 +3172,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -2997,6 +3196,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -3009,6 +3214,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -3033,6 +3244,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -3045,22 +3262,13 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] @@ -3072,7 +3280,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.76", ] [[package]] diff --git a/ic-agent/Cargo.toml b/ic-agent/Cargo.toml index 6be9470f..f455a94d 100644 --- a/ic-agent/Cargo.toml +++ b/ic-agent/Cargo.toml @@ -79,7 +79,6 @@ tower = { version = "0.4.13", optional = true } async-trait = "^0.1.0" tracing = "^0.1.0" arc-swap = "^1.0.0" -simple_moving_average = "^1.0.0" tracing-subscriber = "^0.2.0" tokio-util = { version = "^0.7.0", features = ["rt"] } rustls-webpki = "0.102" From e11334a315afc04e659c5c281302f20765aa33df Mon Sep 17 00:00:00 2001 From: Nikolay Komarevskiy Date: Mon, 26 Aug 2024 13:00:31 +0300 Subject: [PATCH 4/7] fix: typo --- .../dynamic_routing/snapshot/latency_based_routing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/latency_based_routing.rs b/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/latency_based_routing.rs index 54ad4939..fededa02 100644 --- a/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/latency_based_routing.rs +++ b/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/latency_based_routing.rs @@ -571,7 +571,7 @@ mod tests { let score_a = (2.0 * 0.0 + 1.0 * 1.0) / weights_sum; assert_eq!(score, score_l * score_a); - // Test arrays with arrays of different sizes. + // Test with arrays of different sizes. let weights: &[f64] = &[3.0, 2.0, 1.0]; let weights_sum: f64 = weights.iter().sum(); let availabilities = vec![true, false, true].into(); From 818ae53d22525fdd6ecd89e72d038e2505874f20 Mon Sep 17 00:00:00 2001 From: Nikolay Komarevskiy Date: Mon, 26 Aug 2024 13:04:53 +0300 Subject: [PATCH 5/7] docs: add a comment --- .../dynamic_routing/snapshot/latency_based_routing.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/latency_based_routing.rs b/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/latency_based_routing.rs index fededa02..b509731f 100644 --- a/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/latency_based_routing.rs +++ b/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/latency_based_routing.rs @@ -615,6 +615,8 @@ mod tests { node_1.score = 16.0; node_2.score = 8.0; node_3.score = 4.0; + // even though the score is high, this node should never be selected as it is unhealthy + node_4.score = 30.0; snapshot.nodes_with_metrics = vec![node_1, node_2, node_3, node_4]; From 84f876cc130ec22a3f432c2331c8255382b7c833 Mon Sep 17 00:00:00 2001 From: Nikolay Komarevskiy Date: Mon, 26 Aug 2024 19:20:08 +0300 Subject: [PATCH 6/7] chore: pre-allocate with surplus --- .../dynamic_routing/snapshot/latency_based_routing.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/latency_based_routing.rs b/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/latency_based_routing.rs index b509731f..295b24fa 100644 --- a/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/latency_based_routing.rs +++ b/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/latency_based_routing.rs @@ -47,8 +47,8 @@ impl NodeWithMetrics { node, window_size, is_healthy: false, - latencies: VecDeque::with_capacity(window_size), - availabilities: VecDeque::with_capacity(window_size), + latencies: VecDeque::with_capacity(window_size + 1), + availabilities: VecDeque::with_capacity(window_size + 1), score: 0.0, } } From 9a1ef2f7013a90ac3f276172a555479b7d89aeb6 Mon Sep 17 00:00:00 2001 From: Nikolay Komarevskiy Date: Tue, 27 Aug 2024 10:28:18 +0200 Subject: [PATCH 7/7] refactor: minor --- .../snapshot/latency_based_routing.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/latency_based_routing.rs b/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/latency_based_routing.rs index 295b24fa..6b1ee0b0 100644 --- a/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/latency_based_routing.rs +++ b/ic-agent/src/agent/http_transport/dynamic_routing/snapshot/latency_based_routing.rs @@ -9,9 +9,9 @@ use crate::agent::http_transport::dynamic_routing::{ health_check::HealthCheckStatus, node::Node, snapshot::routing_snapshot::RoutingSnapshot, }; -// Determines the size of the sliding window used for store latencies and availabilities of the node. +// Determines the size of the sliding window used for storing latencies and availabilities of nodes. const WINDOW_SIZE: usize = 15; -// Determines the decay rate of the exponential decay function used for weights generation. +// Determines the decay rate of the exponential decay function, which is used for generating weights over the sliding window. const LAMBDA_DECAY: f64 = 0.3; /// Generates exponentially decaying weights for the sliding window. @@ -24,7 +24,8 @@ fn generate_exp_decaying_weights(n: usize, lambda: f64) -> Vec { weights } -// Node with latencies and availability metrics used for generating routing URLs based on the node's score. +// Node with meta information and metrics (latencies, availabilities). +// Routing URLs a generated based on the score field. #[derive(Clone, Debug)] struct NodeWithMetrics { // Node information. @@ -76,12 +77,12 @@ fn compute_score( window_weights: &[f64], window_weights_sum: f64, availabilities: &VecDeque, - latencies_secs: &VecDeque, + latencies: &VecDeque, use_availability_penalty: bool, ) -> f64 { let weights_size = window_weights.len(); let availabilities_size = availabilities.len(); - let latencies_size = latencies_secs.len(); + let latencies_size = latencies.len(); if weights_size < availabilities_size { panic!( @@ -122,18 +123,18 @@ fn compute_score( }; // Compute latency score (not normalized). - let score_l = if latencies_secs.is_empty() { + let score_l = if latencies.is_empty() { 0.0 } else { let mut score = 0.0; // Compute weighted score. Weights are applied in reverse order. Latency is inverted, so that smaller latencies have higher score. - for (idx, latency) in latencies_secs.iter().rev().enumerate() { + for (idx, latency) in latencies.iter().rev().enumerate() { score += window_weights[idx] / latency; } let weights_sum = if latencies_size < weights_size { - let partial_weights_sum: f64 = window_weights.iter().take(latencies_secs.len()).sum(); + let partial_weights_sum: f64 = window_weights.iter().take(latencies.len()).sum(); partial_weights_sum } else { // Use pre-calculated sum. @@ -571,7 +572,7 @@ mod tests { let score_a = (2.0 * 0.0 + 1.0 * 1.0) / weights_sum; assert_eq!(score, score_l * score_a); - // Test with arrays of different sizes. + // Test arrays of different sizes. let weights: &[f64] = &[3.0, 2.0, 1.0]; let weights_sum: f64 = weights.iter().sum(); let availabilities = vec![true, false, true].into();