use amaters_core::{CipherBlob, Key};
use amaters_sdk_rust::AmateRSClient;
use std::time::Duration;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt::init();
println!("=== AmateRS SDK Persistence Example ===\n");
println!("Phase 1: Writing persistent data");
println!("Connecting to server...");
let client = AmateRSClient::connect("http://localhost:50051").await?;
println!("Connected!\n");
let collection = "persistent_store";
println!(" Writing test data...");
let test_data: Vec<(&str, &[u8])> = vec![
("config:app_version", b"1.0.0".as_slice()),
(
"config:feature_flags",
b"feature1,feature2,feature3".as_slice(),
),
(
"user:alice:profile",
b"Alice Anderson, alice@example.com".as_slice(),
),
(
"user:bob:profile",
b"Bob Builder, bob@example.com".as_slice(),
),
("metrics:request_count", b"12345".as_slice()),
("metrics:error_rate", b"0.001".as_slice()),
];
for (key_str, data) in &test_data {
let key = Key::from_str(key_str);
let value = CipherBlob::new(data.to_vec());
client.set(collection, &key, &value).await?;
println!(" ✓ Wrote key: {}", key_str);
}
println!(" {} keys written", test_data.len());
println!();
println!(" Verifying immediate reads...");
for (key_str, expected_data) in &test_data {
let key = Key::from_str(key_str);
match client.get(collection, &key).await? {
Some(value) => {
if value.as_bytes() == *expected_data {
println!(" ✓ Verified: {}", key_str);
} else {
println!(" ✗ Mismatch: {}", key_str);
}
}
None => {
println!(" ✗ Not found: {}", key_str);
}
}
}
println!();
println!(" Waiting for data to flush to disk...");
tokio::time::sleep(Duration::from_secs(2)).await;
println!(" ✓ Data should now be persisted\n");
client.close();
println!("Phase 2: Simulating server restart");
println!(" In production, you would:");
println!(" 1. Stop the server (Ctrl+C)");
println!(" 2. Restart the server");
println!(" 3. Reconnect the client");
println!();
println!(" For this example, we'll reconnect after a delay...");
tokio::time::sleep(Duration::from_secs(1)).await;
println!();
println!("Phase 3: Reading persisted data after 'restart'");
println!("Reconnecting to server...");
let client = AmateRSClient::connect("http://localhost:50051").await?;
println!("Connected!\n");
println!(" Reading back data...");
let mut success_count = 0;
let mut failure_count = 0;
for (key_str, expected_data) in &test_data {
let key = Key::from_str(key_str);
match client.get(collection, &key).await? {
Some(value) => {
if value.as_bytes() == *expected_data {
println!(
" ✓ Persisted: {} = {:?}",
key_str,
String::from_utf8_lossy(expected_data)
);
success_count += 1;
} else {
println!(" ✗ Data mismatch: {}", key_str);
failure_count += 1;
}
}
None => {
println!(" ✗ Lost: {} (not found after restart)", key_str);
failure_count += 1;
}
}
}
println!();
println!("Persistence Summary:");
println!(" Total keys written: {}", test_data.len());
println!(" Successfully persisted: {}", success_count);
println!(" Failed/Lost: {}", failure_count);
if failure_count == 0 {
println!("\n ✓ All data persisted successfully!");
println!(" LSM-Tree is working correctly.");
} else {
println!("\n ✗ Some data was lost.");
println!(" This might indicate:");
println!(" - Server is using in-memory mode");
println!(" - Data directory not configured");
println!(" - Write-ahead log disabled");
}
println!();
println!("Phase 4: Range query on persisted data");
println!(" Querying range: user:a to user:z");
let start_key = Key::from_str("user:a");
let end_key = Key::from_str("user:z");
let results = client.range(collection, &start_key, &end_key).await?;
println!(" ✓ Found {} user entries:", results.len());
for (key, value) in results {
println!(" {}: {}", key, String::from_utf8_lossy(value.as_bytes()));
}
println!();
println!("Closing client...");
client.close();
println!("Done!");
println!();
println!("Note: To verify true persistence, stop and restart the server,");
println!(" then run this example again to see if data is still there.");
Ok(())
}