use serde::{Deserialize, Serialize};
use std::{collections::HashMap, sync::Arc};
use tokio::sync::Mutex;
use walr::{ReplayHandlerResult, WAL};
type Cache = HashMap<String, String>;
#[derive(Serialize, Deserialize)]
enum CacheLog {
Remove(String),
Insert { key: String, value: String },
}
impl CacheLog {
fn inner(self) -> (String, Option<String>) {
match self {
Self::Remove(key) => (key, None),
Self::Insert { key, value } => (key, Some(value)),
}
}
}
type ReplayContext = ();
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
fn replay_handler(
logs: Vec<CacheLog>,
checkpoint: Arc<Mutex<Cache>>,
context: Option<ReplayContext>,
) -> ReplayHandlerResult {
Box::pin(async move {
let mut checkpoint = checkpoint.lock().await;
for log in logs {
match log {
CacheLog::Insert { key, value } => checkpoint.insert(key, value),
CacheLog::Remove(key) => checkpoint.remove(&key),
};
}
Ok(())
})
}
let mut wal: WAL<CacheLog, Cache, ReplayContext> =
WAL::open("./cache_wal", Box::new(replay_handler), None).await?;
let mut cache = wal.replay(None).await?;
let log = CacheLog::Insert {
key: "some id".to_string(),
value: "some data".to_string(),
};
wal.log(&log).await?;
let (key, value) = log.inner();
cache.insert(key, value.unwrap());
let mut logs = vec![];
for string in vec!["1".to_string(), "2".to_string()] {
logs.push(CacheLog::Insert {
key: string.clone(),
value: string,
});
}
wal.log_many(&logs).await?;
for log in logs {
let (key, value) = log.inner();
cache.insert(key, value.unwrap());
}
wal.checkpoint(&cache).await?;
Ok(())
}