use std::collections::VecDeque;
use std::sync::{Arc, Mutex, RwLock};
use super::{NetworkConfig, NetworkStats};
use std::time::{Duration, Instant};
#[derive(Debug, Clone)]
pub struct BatchConfig {
pub max_batch_size: usize,
pub batch_timeout_ms: u64,
pub max_pending_batches: usize,
pub enable_parallel_processing: bool,
}
impl Default for BatchConfig {
fn default() -> Self {
Self {
max_batch_size: 100,
batch_timeout_ms: 10,
max_pending_batches: 1000,
enable_parallel_processing: true,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum BatchPriority {
Low,
Normal,
High,
Critical,
}
#[derive(Debug, Clone)]
pub struct BatchOperation {
pub id: u64,
pub priority: BatchPriority,
pub created_at: Instant,
pub data: Vec<u8>,
pub target: String, }
#[derive(Debug, Clone)]
pub struct BatchStats {
pub total_batches_processed: u64,
pub total_operations_batched: u64,
pub average_batch_size: f64,
pub batch_processing_time_ns: u64,
pub throughput_mbps: f64,
}
pub struct BatchIoEngine {
config: NetworkConfig,
batch_config: BatchConfig,
stats: Arc<RwLock<BatchStats>>,
pending_operations: Arc<RwLock<VecDeque<BatchOperation>>>,
operation_counter: Arc<RwLock<u64>>,
processor_handle: Option<tokio::task::JoinHandle<()>>,
}
impl BatchIoEngine {
pub fn new(config: NetworkConfig) -> Self {
let batch_config: _ = BatchConfig::default();
Self {
processor_handle: None,
batch_config,
stats: Arc::new(Mutex::new(BatchStats {
total_batches_processed: 0,
total_operations_batched: 0,
average_batch_size: 0.0,
batch_processing_time_ns: 0,
throughput_mbps: 0.0,
})),
pending_operations: Arc::new(Mutex::new(VecDeque::new())),
operation_counter: Arc::new(Mutex::new(0)),
config,
}
}
pub async fn start(&mut self) -> Result<(), Box<dyn std::error::Error>> {
let pending_operations: _ = Arc::clone(&self.pending_operations);
let stats: _ = Arc::clone(&self.stats);
let batch_timeout_ms: _ = self.batch_config.batch_timeout_ms;
let handle: _ = tokio::spawn(async move {
let mut interval = tokio::time::interval(
Duration::from_millis(batch_timeout_ms)
);
loop {
interval.tick().await;
Self::process_batch(&pending_operations, &stats).await;
}
});
self.processor_handle = Some(handle);
Ok(())
}
pub async fn stop(&mut self) -> Result<(), Box<dyn std::error::Error>> {
if let Some(handle) = self.processor_handle.take() {
handle.abort();
}
Ok(())
}
pub async fn submit_operation(&self, operation: BatchOperation) -> Result<(), Box<dyn std::error::Error>> {
let mut pending = self.pending_operations.write().await;
if pending.len() >= self.batch_config.max_pending_batches {
return Err("批处理器满".into());
}
pending.push_back(operation);
Ok(())
}
async fn process_batch(
pending_operations: &Arc<RwLock<VecDeque<BatchOperation>>>,
stats: &Arc<RwLock<BatchStats>>,
) {
let start: _ = Instant::now();
let max_batch_size: _ = BatchConfig::default().max_batch_size;
let mut batch = Vec::new();
{
let mut pending = pending_operations.write().await;
while batch.len() < max_batch_size {
if let Some(op) = pending.pop_front() {
batch.push(op);
} else {
break;
}
}
}
if batch.is_empty() {
return;
}
Self::simulate_batch_processing(&batch).await;
let elapsed: _ = start.elapsed();
let mut stats_guard = stats.write().await;
stats_guard.total_batches_processed += 1;
stats_guard.total_operations_batched += batch.len() as u64;
stats_guard.batch_processing_time_ns += elapsed.as_nanos() as u64;
stats_guard.average_batch_size = stats_guard.total_operations_batched as f64
/ stats_guard.total_batches_processed as f64;
}
async fn simulate_batch_processing(batch: &[BatchOperation]) {
tokio::time::sleep(Duration::from_micros(10)).await;
}
pub async fn get_stats(&self) -> BatchStats {
self.stats.read().await.clone()
}
}
impl Drop for BatchIoEngine {
fn drop(&mut self) {
if let Some(handle) = &self.processor_handle {
handle.abort();
}
}
}