rollblock 0.4.1

A super-fast, block-oriented and rollbackable key-value store.
Documentation
//! Observability example demonstrating metrics and tracing
//!
//! Run with: cargo run --example observability
//! For JSON logs: RUST_LOG=rollblock=info cargo run --example observability

use rollblock::metrics::HealthState;
use rollblock::types::{Operation, StoreKey as Key, Value};
use rollblock::{SimpleStoreFacade, StoreConfig, StoreFacade};

fn key_from_u8(i: u8) -> Key {
    Key::from_prefix([i, 0, 0, 0, 0, 0, 0, 0])
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize tracing subscriber for structured logging
    tracing_subscriber::fmt()
        .with_env_filter(
            tracing_subscriber::EnvFilter::try_from_default_env()
                .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info")),
        )
        .with_target(false)
        .with_thread_ids(true)
        .with_file(true)
        .with_line_number(true)
        .init();

    println!("🔍 Rollblock Observability Example\n");
    println!("This example demonstrates metrics collection and tracing.");
    println!("Set RUST_LOG=debug for detailed traces.\n");

    // Create store configuration
    let config = StoreConfig::new(
        "./data/observability_example",
        4,     // 4 shards
        1000,  // initial capacity
        1,     // single thread
        false, // disable compression for metrics demo
    )?
    .without_remote_server();

    let store = SimpleStoreFacade::new(config)?;

    // Check initial health
    println!("📊 Initial Health Check");
    if let Some(health) = store.health() {
        print_health(&health);
    }
    println!();

    // Perform some operations
    println!("✏ïļ  Performing operations...");

    // Block 1: Set operations (new keys)
    let mut operations = Vec::new();
    for i in 0..10 {
        operations.push(Operation {
            key: key_from_u8(i),
            value: (i as u64 * 100).into(),
        });
    }
    store.set(1, operations)?;
    println!("✓ Block 1: Set 10 keys");

    // Block 2: Set operations (existing keys)
    let mut operations = Vec::new();
    for i in 0..5 {
        operations.push(Operation {
            key: key_from_u8(i),
            value: (i as u64 * 200).into(),
        });
    }
    store.set(2, operations)?;
    println!("✓ Block 2: Updated 5 keys");

    // Block 3: Delete operations
    let mut operations = Vec::new();
    for i in 0..3 {
        operations.push(Operation {
            key: key_from_u8(i),
            value: Value::empty(),
        });
    }
    store.set(3, operations)?;
    println!("✓ Block 3: Deleted 3 keys");

    // Perform some lookups
    println!("\n🔎 Performing lookups...");
    for i in 0..10 {
        let key = key_from_u8(i);
        let _ = store.get(key)?;
    }
    println!("✓ Performed 10 lookups");

    // Rollback to block 1
    println!("\n⏊ Rolling back to block 1...");
    store.rollback(1)?;
    println!("✓ Rollback complete");

    // Display metrics
    println!("\n📈 Metrics Report");
    println!("═══════════════════════════════════════════════════");

    if let Some(metrics) = store.metrics() {
        let snapshot = metrics.snapshot();

        println!("Operations:");
        println!(
            "  â€Ē Total operations applied: {}",
            snapshot.operations_applied
        );
        println!(
            "  â€Ē Sets: {} ({} empty-value deletes)",
            snapshot.set_operations_applied, snapshot.zero_value_deletes_applied
        );
        println!("  â€Ē Blocks committed: {}", snapshot.blocks_committed);
        println!("  â€Ē Rollbacks executed: {}", snapshot.rollbacks_executed);
        println!("  â€Ē Lookups performed: {}", snapshot.lookups_performed);

        println!("\nPerformance (Averages):");
        println!("  â€Ē Apply time: {} Ξs", snapshot.avg_apply_time_us);
        println!("  â€Ē Rollback time: {} Ξs", snapshot.avg_rollback_time_us);
        println!("  â€Ē Lookup time: {} Ξs", snapshot.avg_lookup_time_us);

        println!("\nPerformance (Percentiles):");
        println!("  â€Ē Apply P50: {} Ξs", snapshot.apply_p50_us);
        println!("  â€Ē Apply P95: {} Ξs", snapshot.apply_p95_us);
        println!("  â€Ē Apply P99: {} Ξs", snapshot.apply_p99_us);
        println!("  â€Ē Rollback P50: {} Ξs", snapshot.rollback_p50_us);
        println!("  â€Ē Rollback P95: {} Ξs", snapshot.rollback_p95_us);
        println!("  â€Ē Rollback P99: {} Ξs", snapshot.rollback_p99_us);

        println!("\nState:");
        println!("  â€Ē Current block: {}", snapshot.current_block_height);
        println!("  â€Ē Total keys stored: {}", snapshot.total_keys_stored);

        println!("\nErrors:");
        println!("  â€Ē Failed operations: {}", snapshot.failed_operations);
        println!("  â€Ē Checksum errors: {}", snapshot.checksum_errors);

        if let Some(secs) = snapshot.last_operation_secs {
            println!("\nActivity:");
            println!("  â€Ē Last operation: {} seconds ago", secs);
        }
    }

    // Final health check
    println!("\nðŸĨ Final Health Check");
    println!("═══════════════════════════════════════════════════");
    if let Some(health) = store.health() {
        print_health(&health);
    }

    // Export metrics as JSON (demonstration)
    if let Some(metrics) = store.metrics() {
        let snapshot = metrics.snapshot();
        let json = serde_json::to_string_pretty(&snapshot)?;
        println!("\n📄 Metrics JSON:");
        println!("{}", json);
    }

    println!("\n✅ Example completed successfully!");
    println!("\nTip: Run with RUST_LOG=debug to see detailed tracing information.");

    Ok(())
}

fn print_health(health: &rollblock::metrics::HealthStatus) {
    let status_emoji = match health.state {
        HealthState::Healthy => "✅",
        HealthState::Idle => "ðŸ’Ī",
        HealthState::Degraded => "⚠ïļ",
        HealthState::Unhealthy => "❌",
    };

    println!("  {} Status: {}", status_emoji, health.state);
    println!("  â€Ē Applied block: {}", health.current_block);
    println!("  â€Ē Durable block: {}", health.durable_block);
    println!("  â€Ē Total operations: {}", health.total_operations);
    println!("  â€Ē Failed operations: {}", health.failed_operations);
    println!("  â€Ē Checksum errors: {}", health.checksum_errors);

    if let Some(secs) = health.last_operation_secs {
        println!("  â€Ē Last operation: {} seconds ago", secs);
    } else {
        println!("  â€Ē Last operation: never");
    }
}