pub use self::core::{
CheckpointManagerState, CheckpointProgress, CheckpointState, DirtyBlockTracker,
V2WALCheckpointManager,
};
pub use self::coordinator::CheckpointExecutor;
pub use self::io::BlockFlusher;
pub use self::io::multi_file::{
CheckpointManifest, CheckpointSegment, CheckpointSegmentMeta, MultiFileCheckpointConfig,
MultiFileRecovery, MultiSegmentIterator, RecoveredCheckpoint, SegmentReader, SegmentWriter,
};
pub use self::record::V2GraphIntegrator;
pub use self::strategies::{
CheckpointStrategy, CheckpointTrigger, StrategyEvaluator, StrategyMetrics, StrategyValidator,
};
pub use self::validation::{
CheckpointCleanup,
CheckpointMetrics as V2CheckpointMetrics,
CheckpointValidationReport,
CheckpointValidator,
CheckpointValidatorFactory,
ConsistencyResult,
ConsistencySeverity,
ConsistencyViolation,
PerformanceMetrics,
V2InvariantResult,
V2InvariantViolation,
ValidationComponents,
ValidationConfig,
ValidationRule,
ValidationRuleEngine,
ValidationSeverity,
ValidationStatus,
};
pub mod coordinator;
pub mod core;
pub mod io;
pub mod operations;
pub mod record;
pub mod strategies;
pub mod validation;
pub mod constants;
pub mod errors;
use crate::backend::native::v2::wal::V2WALConfig;
use std::path::Path;
pub use self::errors::{
CheckpointError, CheckpointErrorKind, CheckpointResult, ErrorSeverity, RecoverySuggestion,
};
pub struct CheckpointFactory;
impl CheckpointFactory {
pub fn create_manager(
config: V2WALConfig,
strategy: CheckpointStrategy,
) -> CheckpointResult<V2WALCheckpointManager> {
V2WALCheckpointManager::create(config, strategy).map_err(Into::into)
}
pub fn create_adaptive_manager(
config: V2WALConfig,
min_interval: std::time::Duration,
max_wal_size: u64,
max_transactions: u64,
) -> CheckpointResult<V2WALCheckpointManager> {
let strategy = CheckpointStrategy::Adaptive {
min_interval,
max_wal_size,
max_transactions,
};
Self::create_manager(config, strategy)
}
pub fn create_v2_optimized_manager(
config: V2WALConfig,
) -> CheckpointResult<V2WALCheckpointManager> {
let strategy = CheckpointStrategy::SizeThreshold(config.max_wal_size / 4);
Self::create_manager(config, strategy)
}
pub fn validate_config(config: &V2WALConfig) -> CheckpointResult<()> {
config.validate().map_err(Into::into)
}
pub fn ensure_checkpoint_directory(config: &V2WALConfig) -> CheckpointResult<()> {
if let Some(parent) = config.checkpoint_path.parent() {
std::fs::create_dir_all(parent).map_err(|e| {
CheckpointError::io(format!("Failed to create checkpoint directory: {}", e))
})?;
}
Ok(())
}
}
pub mod utils {
use super::*;
pub fn calculate_optimal_checkpoint_size(wal_size: u64) -> u64 {
std::cmp::max(wal_size / 4, 1024 * 1024) }
pub fn estimate_checkpoint_duration(
wal_size: u64,
strategy: &CheckpointStrategy,
) -> std::time::Duration {
let base_duration = std::time::Duration::from_millis(
((wal_size / (1024 * 1024)) as u64) * 100, );
match strategy {
CheckpointStrategy::SizeThreshold(_) => base_duration,
CheckpointStrategy::TransactionCount(_) => base_duration * 2, CheckpointStrategy::TimeInterval(_) => base_duration / 2, CheckpointStrategy::Adaptive { .. } => base_duration * 3, }
}
pub fn validate_checkpoint_file(path: &Path) -> CheckpointResult<bool> {
if !path.exists() {
return Ok(false);
}
let metadata = std::fs::metadata(path).map_err(|e| {
CheckpointError::io(format!("Failed to read checkpoint metadata: {}", e))
})?;
if metadata.len() == 0 {
return Err(CheckpointError::validation(
"Checkpoint file is empty".to_string(),
));
}
let min_size = 1024; let max_size = 1024 * 1024 * 1024;
if metadata.len() < min_size {
return Err(CheckpointError::validation(
"Checkpoint file too small".to_string(),
));
}
if metadata.len() > max_size {
return Err(CheckpointError::validation(
"Checkpoint file too large".to_string(),
));
}
Ok(true)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::backend::native::GraphFile;
use crate::backend::native::NativeBackendError;
use std::time::Duration;
use tempfile::tempdir;
#[test]
fn test_checkpoint_factory_create_manager() -> CheckpointResult<()> {
let temp_dir = tempdir().unwrap();
let v2_graph_path = temp_dir.path().join("test.v2");
let _graph_file = GraphFile::create(&v2_graph_path).map_err(|e| {
CheckpointError::v2_integration(format!("Failed to create test graph file: {}", e))
})?;
let config = V2WALConfig {
wal_path: temp_dir.path().join("test.wal"),
checkpoint_path: temp_dir.path().join("test.checkpoint"),
..Default::default()
};
let strategy = CheckpointStrategy::TimeInterval(Duration::from_secs(60));
let manager = CheckpointFactory::create_manager(config, strategy)?;
assert!(true, "Checkpoint manager created successfully");
Ok(())
}
#[test]
fn test_checkpoint_factory_adaptive_manager() -> CheckpointResult<()> {
let temp_dir = tempdir().unwrap();
let v2_graph_path = temp_dir.path().join("test.v2");
let _graph_file = GraphFile::create(&v2_graph_path).map_err(|e| {
CheckpointError::v2_integration(format!("Failed to create test graph file: {}", e))
})?;
let config = V2WALConfig {
wal_path: temp_dir.path().join("test.wal"),
checkpoint_path: temp_dir.path().join("test.checkpoint"),
..Default::default()
};
let manager = CheckpointFactory::create_adaptive_manager(
config,
Duration::from_secs(30),
100 * 1024 * 1024, 1000,
)?;
assert!(true, "Adaptive checkpoint manager created successfully");
Ok(())
}
#[test]
fn test_checkpoint_utils_calculate_optimal_size() {
let test_sizes = vec![
(16 * 1024 * 1024, 4 * 1024 * 1024), (64 * 1024 * 1024, 16 * 1024 * 1024), (256 * 1024 * 1024, 64 * 1024 * 1024), (512, 1024 * 1024), ];
for (wal_size, expected) in test_sizes {
let result = utils::calculate_optimal_checkpoint_size(wal_size);
assert_eq!(
result, expected,
"Incorrect optimal checkpoint size for WAL size {}",
wal_size
);
}
}
#[test]
fn test_checkpoint_error_display() {
let error = CheckpointError::configuration("Invalid configuration");
let display = format!("{}", error);
assert!(display.contains("Configuration"));
assert!(display.contains("Invalid configuration"));
}
#[test]
fn test_checkpoint_error_from_native() {
let native_error =
NativeBackendError::Io(std::io::Error::new(std::io::ErrorKind::NotFound, "test"));
let checkpoint_error: CheckpointError = native_error.into();
assert_eq!(checkpoint_error.kind, CheckpointErrorKind::Io);
assert!(checkpoint_error.message.contains("I/O error"));
}
}