|
|
|
|
| use anyhow::Result;
|
| use std::collections::VecDeque;
|
| use serde::{Deserialize, Serialize};
|
|
|
|
|
| #[derive(Debug, Clone, Serialize, Deserialize)]
|
| pub struct WormCheckpoint {
|
| pub id: String,
|
| pub ip: usize,
|
| pub step_count: u64,
|
| pub mutation_log_len: usize,
|
| pub timestamp: u64,
|
| pub memory_snapshot: Vec<i64>,
|
| }
|
|
|
|
|
| pub struct RollbackManager {
|
| checkpoints: VecDeque<WormCheckpoint>,
|
| max_checkpoints: usize,
|
| }
|
|
|
| impl RollbackManager {
|
| pub fn new(max_checkpoints: usize) -> Self {
|
| Self {
|
| checkpoints: VecDeque::new(),
|
| max_checkpoints,
|
| }
|
| }
|
|
|
|
|
| pub fn add_checkpoint(&mut self, checkpoint: WormCheckpoint) {
|
| self.checkpoints.push_back(checkpoint);
|
|
|
|
|
| while self.checkpoints.len() > self.max_checkpoints {
|
| self.checkpoints.pop_front();
|
| }
|
| }
|
|
|
|
|
| pub fn last_valid_checkpoint(&self) -> Option<WormCheckpoint> {
|
| self.checkpoints.back().cloned()
|
| }
|
|
|
|
|
| pub fn all_checkpoints(&self) -> Vec<WormCheckpoint> {
|
| self.checkpoints.iter().cloned().collect()
|
| }
|
|
|
|
|
| pub fn rollback(&self, _checkpoint: &WormCheckpoint) -> Result<()> {
|
|
|
|
|
| Ok(())
|
| }
|
|
|
| pub fn checkpoint_count(&self) -> usize {
|
| self.checkpoints.len()
|
| }
|
| }
|
|
|
| impl Default for RollbackManager {
|
| fn default() -> Self {
|
| Self::new(100)
|
| }
|
| }
|
|
|
| #[cfg(test)]
|
| mod tests {
|
| use super::*;
|
|
|
| #[test]
|
| fn test_rollback_manager_creation() {
|
| let mgr = RollbackManager::new(10);
|
| assert_eq!(mgr.checkpoint_count(), 0);
|
| }
|
|
|
| #[test]
|
| fn test_add_checkpoint() {
|
| let mut mgr = RollbackManager::new(10);
|
| let cp = WormCheckpoint {
|
| id: "cp1".into(),
|
| ip: 0,
|
| step_count: 0,
|
| mutation_log_len: 0,
|
| timestamp: 0,
|
| memory_snapshot: vec![],
|
| };
|
| mgr.add_checkpoint(cp);
|
| assert_eq!(mgr.checkpoint_count(), 1);
|
| }
|
|
|
| #[test]
|
| fn test_last_checkpoint() {
|
| let mut mgr = RollbackManager::new(10);
|
| let cp = WormCheckpoint {
|
| id: "cp1".into(),
|
| ip: 0,
|
| step_count: 0,
|
| mutation_log_len: 0,
|
| timestamp: 0,
|
| memory_snapshot: vec![],
|
| };
|
| mgr.add_checkpoint(cp.clone());
|
| let last = mgr.last_valid_checkpoint();
|
| assert_eq!(last.unwrap().id, "cp1");
|
| }
|
|
|
| #[test]
|
| fn test_max_checkpoints_limit() {
|
| let mut mgr = RollbackManager::new(3);
|
| for i in 0..5 {
|
| let cp = WormCheckpoint {
|
| id: format!("cp{}", i),
|
| ip: 0,
|
| step_count: 0,
|
| mutation_log_len: 0,
|
| timestamp: 0,
|
| memory_snapshot: vec![],
|
| };
|
| mgr.add_checkpoint(cp);
|
| }
|
| assert_eq!(mgr.checkpoint_count(), 3);
|
| }
|
| }
|
|
|