use super::Service;
use crate::{
engine_sync::CatchUp, recorded::RecordedError, recorded::record, retrieval::RecordSource,
};
use std::{sync::atomic::Ordering, time::Duration};
impl Service {
pub const CATCH_UP_BLOCKS: u64 = 256;
pub const CATCH_UP_TIME: Duration = Duration::from_secs(5);
const PAUSE_STEPS: u32 = 20;
const PAUSE_STEP: Duration = Duration::from_millis(100);
fn stopped(&self) -> bool {
self.stop.load(Ordering::Acquire)
}
fn pause(&self) {
for _ in 0..Self::PAUSE_STEPS {
if self.stopped() {
return;
}
std::thread::sleep(Self::PAUSE_STEP);
}
}
pub(super) fn sync_loop(&self) {
while !self.stopped() {
if !self.sync_round() {
self.pause();
}
}
}
pub(super) fn maintenance_loop(&self) {
while !self.stopped() {
self.maintenance_round();
self.pause();
}
}
fn sync_round(&self) -> bool {
let catch_up = match self.engine.synchronize_headers_until(&self.stop) {
Ok(_) => {
self.engine
.scan_catch_up(&self.stop, Self::CATCH_UP_BLOCKS, Self::CATCH_UP_TIME)
}
Err(error) => CatchUp {
scanned: 0,
outcome: Err(error),
},
};
let result = catch_up.outcome.and_then(|status| {
if !self.stopped() {
self.engine.resolve_cached_dependency()?;
}
Ok(status)
});
record(&self.sync_error, &result);
catch_up.scanned > 0
}
fn maintenance_round(&self) {
self.probe_commit_sources();
self.discover_peers();
self.sync_next_inventory();
self.acquire_next_dependency();
if !self.stopped() {
let result = self.engine.maintain_next_names(&self.stop);
record(&self.names_error, &result);
}
if !self.stopped() {
self.retain_next_object();
}
if !self.stopped() {
let result = self.engine.maintain_cache(self.cache_bytes, &self.stop);
if let Ok(mut status) = self.cache_status.lock() {
match result {
Ok(receipt) => {
status.receipt = Some(receipt);
status.error = None;
}
Err(cause) => {
status.error = Some(RecordedError::now(cause));
}
}
}
}
}
fn retain_next_object(&self) {
let Some((scratch, slice)) = &self.retention else {
return;
};
let owned = self.record_sources();
let sources: Vec<&dyn RecordSource> = owned
.iter()
.map(|source| -> &dyn RecordSource { source.as_ref() })
.collect();
let result = self
.engine
.retain_next_object(&sources, *slice, scratch, &self.stop);
record(&self.retention_error, &result);
}
fn probe_commit_sources(&self) {
let Some(sources) = &self.commit_sources else {
return;
};
if self.stopped() {
return;
}
if let Err(error) = sources.probe() {
record(&self.dependency_error, &Err::<(), _>(error));
}
}
fn acquire_next_dependency(&self) {
let Some(sources) = &self.commit_sources else {
return;
};
if self.stopped() {
return;
}
let result = self.engine.resolve_next_dependency(sources, &self.stop);
if self.stopped() {
return;
}
record(&self.dependency_error, &result);
}
}