2024-07-04 06:04:17 +00:00
|
|
|
use super::{batcher::Batcher, sync_store::SyncStore};
|
2024-08-19 01:54:52 +00:00
|
|
|
use crate::{
|
2024-09-05 02:09:29 +00:00
|
|
|
auto_sync::{batcher::SyncResult, metrics, sync_store::Queue},
|
2024-08-19 01:54:52 +00:00
|
|
|
Config, SyncSender,
|
|
|
|
};
|
2024-07-04 06:04:17 +00:00
|
|
|
use anyhow::Result;
|
2024-08-05 09:30:26 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
2024-07-12 09:45:20 +00:00
|
|
|
use std::sync::{
|
|
|
|
atomic::{AtomicBool, Ordering},
|
|
|
|
Arc,
|
|
|
|
};
|
2024-07-04 06:04:17 +00:00
|
|
|
use storage_async::Store;
|
|
|
|
use tokio::time::sleep;
|
|
|
|
|
2024-08-05 09:30:26 +00:00
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
|
|
#[serde(rename_all = "camelCase")]
|
|
|
|
pub struct RandomBatcherState {
|
2024-11-15 02:00:58 +00:00
|
|
|
pub name: String,
|
2024-08-05 09:30:26 +00:00
|
|
|
pub tasks: Vec<u64>,
|
|
|
|
pub pending_txs: usize,
|
|
|
|
pub ready_txs: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
2024-07-04 06:04:17 +00:00
|
|
|
pub struct RandomBatcher {
|
2024-11-15 02:00:58 +00:00
|
|
|
name: String,
|
2024-08-22 02:42:15 +00:00
|
|
|
config: Config,
|
2024-07-04 06:04:17 +00:00
|
|
|
batcher: Batcher,
|
2024-07-08 03:47:59 +00:00
|
|
|
sync_store: Arc<SyncStore>,
|
2024-07-04 06:04:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl RandomBatcher {
|
2024-07-08 03:47:59 +00:00
|
|
|
pub fn new(
|
2024-11-15 02:00:58 +00:00
|
|
|
name: String,
|
2024-07-08 03:47:59 +00:00
|
|
|
config: Config,
|
|
|
|
store: Store,
|
|
|
|
sync_send: SyncSender,
|
|
|
|
sync_store: Arc<SyncStore>,
|
|
|
|
) -> Self {
|
2024-07-04 06:04:17 +00:00
|
|
|
Self {
|
2024-11-15 02:00:58 +00:00
|
|
|
name,
|
2024-08-22 02:42:15 +00:00
|
|
|
config,
|
|
|
|
batcher: Batcher::new(
|
|
|
|
config.max_random_workers,
|
|
|
|
config.random_find_peer_timeout,
|
|
|
|
store,
|
|
|
|
sync_send,
|
|
|
|
),
|
2024-07-04 06:04:17 +00:00
|
|
|
sync_store,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-05 09:30:26 +00:00
|
|
|
pub async fn get_state(&self) -> Result<RandomBatcherState> {
|
|
|
|
let (pending_txs, ready_txs) = self.sync_store.stat().await?;
|
|
|
|
|
|
|
|
Ok(RandomBatcherState {
|
2024-11-15 02:00:58 +00:00
|
|
|
name: self.name.clone(),
|
2024-08-05 09:30:26 +00:00
|
|
|
tasks: self.batcher.tasks().await,
|
|
|
|
pending_txs,
|
|
|
|
ready_txs,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-07-12 09:45:20 +00:00
|
|
|
pub async fn start(mut self, catched_up: Arc<AtomicBool>) {
|
2024-11-15 02:00:58 +00:00
|
|
|
info!("Start to sync files, state = {:?}", self.get_state().await);
|
2024-07-04 06:04:17 +00:00
|
|
|
|
2024-10-28 06:56:08 +00:00
|
|
|
// wait for log entry sync catched up
|
|
|
|
while !catched_up.load(Ordering::Relaxed) {
|
|
|
|
trace!("Cannot sync file in catch-up phase");
|
|
|
|
sleep(self.config.auto_sync_idle_interval).await;
|
|
|
|
}
|
2024-07-12 09:45:20 +00:00
|
|
|
|
2024-10-28 06:56:08 +00:00
|
|
|
loop {
|
2024-11-15 02:00:58 +00:00
|
|
|
// if let Ok(state) = self.get_state().await {
|
|
|
|
// metrics::RANDOM_STATE_TXS_SYNCING.update(state.tasks.len() as u64);
|
|
|
|
// metrics::RANDOM_STATE_TXS_READY.update(state.ready_txs as u64);
|
|
|
|
// metrics::RANDOM_STATE_TXS_PENDING.update(state.pending_txs as u64);
|
|
|
|
// }
|
2024-08-19 01:54:52 +00:00
|
|
|
|
2024-07-04 06:04:17 +00:00
|
|
|
match self.sync_once().await {
|
|
|
|
Ok(true) => {}
|
|
|
|
Ok(false) => {
|
2024-07-08 03:47:59 +00:00
|
|
|
trace!(
|
2024-08-05 09:30:26 +00:00
|
|
|
"File sync still in progress or idle, state = {:?}",
|
|
|
|
self.get_state().await
|
2024-07-08 03:47:59 +00:00
|
|
|
);
|
2024-08-22 02:42:15 +00:00
|
|
|
sleep(self.config.auto_sync_idle_interval).await;
|
2024-07-04 06:04:17 +00:00
|
|
|
}
|
|
|
|
Err(err) => {
|
2024-08-05 09:30:26 +00:00
|
|
|
warn!(%err, "Failed to sync file once, state = {:?}", self.get_state().await);
|
2024-08-22 02:42:15 +00:00
|
|
|
sleep(self.config.auto_sync_error_interval).await;
|
2024-07-04 06:04:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn sync_once(&mut self) -> Result<bool> {
|
|
|
|
if self.schedule().await? {
|
|
|
|
return Ok(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// poll any completed file sync
|
|
|
|
let (tx_seq, sync_result) = match self.batcher.poll().await? {
|
|
|
|
Some(v) => v,
|
|
|
|
None => return Ok(false),
|
|
|
|
};
|
|
|
|
|
2024-08-05 09:30:26 +00:00
|
|
|
debug!(%tx_seq, ?sync_result, "Completed to sync file, state = {:?}", self.get_state().await);
|
2024-08-19 01:54:52 +00:00
|
|
|
match sync_result {
|
2024-08-22 02:42:15 +00:00
|
|
|
SyncResult::Completed => metrics::RANDOM_SYNC_RESULT_COMPLETED.mark(1),
|
2024-08-19 01:54:52 +00:00
|
|
|
SyncResult::Failed => metrics::RANDOM_SYNC_RESULT_FAILED.inc(1),
|
|
|
|
SyncResult::Timeout => metrics::RANDOM_SYNC_RESULT_TIMEOUT.inc(1),
|
|
|
|
}
|
2024-07-04 06:04:17 +00:00
|
|
|
|
2024-09-05 02:09:29 +00:00
|
|
|
if matches!(sync_result, SyncResult::Completed) {
|
|
|
|
self.sync_store.remove(tx_seq).await?;
|
|
|
|
} else {
|
|
|
|
self.sync_store.insert(tx_seq, Queue::Pending).await?;
|
|
|
|
}
|
2024-07-04 06:04:17 +00:00
|
|
|
|
|
|
|
Ok(true)
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn schedule(&mut self) -> Result<bool> {
|
2024-09-05 02:09:29 +00:00
|
|
|
let tx_seq = match self.sync_store.random().await? {
|
2024-07-04 06:04:17 +00:00
|
|
|
Some(v) => v,
|
|
|
|
None => return Ok(false),
|
|
|
|
};
|
|
|
|
|
|
|
|
if !self.batcher.add(tx_seq).await? {
|
|
|
|
return Ok(false);
|
|
|
|
}
|
|
|
|
|
2024-08-05 09:30:26 +00:00
|
|
|
debug!("Pick a file to sync, state = {:?}", self.get_state().await);
|
2024-07-04 06:04:17 +00:00
|
|
|
|
|
|
|
Ok(true)
|
|
|
|
}
|
|
|
|
}
|