diff --git a/src/commons/api/ca.rs b/src/commons/api/ca.rs index 89fd9fa38..cc4d79241 100644 --- a/src/commons/api/ca.rs +++ b/src/commons/api/ca.rs @@ -1262,6 +1262,59 @@ impl ParentStatuses { self.0.iter() } + /// Get the first synchronization candidates based on the following: + /// - take the given ca_parents for which no current status exists first + /// - then sort by last exchange, minute grade granularity - oldest first + /// - where failures come before success within the same minute + /// - then take the first N parents for this batch + pub fn sync_candidates(&self, ca_parents: Vec<&ParentHandle>, batch: usize) -> Vec { + let mut parents = vec![]; + + // Add any parent for which no current status is known to the candidate list first. + for parent in ca_parents { + if !self.0.contains_key(parent) { + parents.push(parent.clone()); + } + } + + // Then add the ones for which we do have a status, sorted by their + // last exchange. + let mut parents_by_last_exchange = self.sorted_by_last_exchange(); + parents.append(&mut parents_by_last_exchange); + + // But truncate to the specified batch size + parents.truncate(batch); + + parents + } + + // Return the parents sorted by last exchange, i.e. let the parents + // without an exchange be first, and then from longest ago to most recent. + // Uses minute grade granularity and in cases where the exchanges happened in + // the same minute failures take precedence (come before) successful exchanges. + pub fn sorted_by_last_exchange(&self) -> Vec { + let mut sorted_parents: Vec<(&ParentHandle, &ParentStatus)> = self.iter().collect(); + sorted_parents.sort_by(|a, b| { + // we can map the 'no last exchange' case to 1970.. + let a_last_exchange = a.1.last_exchange.as_ref(); + let b_last_exchange = b.1.last_exchange.as_ref(); + + let a_last_exchange_time = a_last_exchange.map(|e| i64::from(e.timestamp)).unwrap_or(0) / 60; + let b_last_exchange_time = b_last_exchange.map(|e| i64::from(e.timestamp)).unwrap_or(0) / 60; + + if a_last_exchange_time == b_last_exchange_time { + // compare success / failure + let a_last_exchange_res = a_last_exchange.map(|e| e.result().was_success()).unwrap_or(false); + let b_last_exchange_res = b_last_exchange.map(|e| e.result().was_success()).unwrap_or(false); + a_last_exchange_res.cmp(&b_last_exchange_res) + } else { + a_last_exchange_time.cmp(&b_last_exchange_time) + } + }); + + sorted_parents.into_iter().map(|(handle, _)| handle).cloned().collect() + } + pub fn set_failure(&mut self, parent: &ParentHandle, uri: &ServiceUri, error: ErrorResponse, next_seconds: i64) { self.get_mut_status(parent) .set_failure(uri.clone(), error, next_seconds); @@ -1923,6 +1976,12 @@ impl From