rabia-kvstore-example 0.4.1

Key-value store state machine implementation example using the Rabia SMR protocol
Documentation
# Key-Value Store SMR Example

This example demonstrates how to build a production-grade distributed key-value store using State Machine Replication (SMR) with the Rabia consensus protocol.

## What This Example Shows

The KV Store SMR demonstrates advanced SMR concepts:

1. **Complex State Management**: Managing a dictionary of key-value pairs across replicas
2. **Change Notifications**: Event-driven architecture with publish-subscribe patterns
3. **Efficient Serialization**: Optimized state serialization for large datasets
4. **Production Features**: Comprehensive error handling, monitoring, and observability

## State Machine Implementation

The KV store implements these operations:

- `Set { key, value }` - Store a key-value pair
- `Get { key }` - Retrieve value for a key
- `Delete { key }` - Remove a key-value pair
- `Exists { key }` - Check if a key exists
- `ListKeys` - Get all keys (for debugging/monitoring)
- `Clear` - Remove all key-value pairs
- `Size` - Get current number of stored keys

## Key SMR Features Demonstrated

### Complex State Management
```rust
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KVStoreState {
    pub data: HashMap<String, String>,
    pub operation_count: u64,
    pub created_at: SystemTime,
    pub last_modified: SystemTime,
}
```

### Change Notifications (Event-Driven SMR)
```rust
// The KV store publishes change notifications
pub enum ChangeNotification {
    KeySet { key: String, value: String, old_value: Option<String> },
    KeyDeleted { key: String, old_value: String },
    StoreCleared { key_count: usize },
}

// Clients can subscribe to changes
let subscription_id = store.subscribe_to_changes(|notification| {
    println!("Key changed: {:?}", notification);
}).await;
```

### Efficient State Snapshots
```rust
// Implements efficient serialization for large state
fn serialize_state(&self) -> Vec<u8> {
    // Uses bincode for compact binary serialization
    bincode::serialize(&self.state).unwrap_or_default()
}

// Supports incremental state updates
async fn apply_command(&mut self, command: Self::Command) -> Self::Response {
    let old_value = self.state.data.get(&key).cloned();
    // ... apply operation ...
    
    // Emit change notification for subscribers
    if let Some(notification) = self.create_notification(&command, &old_value) {
        self.notification_bus.publish(notification).await;
    }
    
    KVResult::success(response_data)
}
```

## Architecture Components

### Store Layer (`store.rs`)
High-level interface for KV operations with:
- Connection pooling and load balancing
- Caching and performance optimization
- Metrics collection and monitoring
- Configuration management

### Operations Layer (`operations.rs`)
Defines KV operations and results:
- Operation types and serialization
- Error handling and validation
- Result types and status codes

### SMR Implementation (`smr_impl.rs`)
Core StateMachine trait implementation:
- Deterministic operation application
- State serialization/deserialization
- Change notification generation

### Notifications (`notifications.rs`)
Event-driven change notifications:
- Publication/subscription patterns
- Change event types and routing
- Asynchronous notification delivery

## Running the Example

```bash
# Run the KV store SMR example
cargo run --bin kvstore_smr_example

# Run with multiple replicas
cargo run --bin kvstore_smr_cluster

# Run tests to see SMR behavior
cargo test -p kvstore_smr

# Run benchmarks
cargo bench --bench kvstore_performance
```

## Use Cases

This pattern is ideal for:

- **Configuration Stores**: Application configuration management
- **Session Storage**: User session data across web servers
- **Caching**: Distributed caching with strong consistency
- **Service Discovery**: Registry of available services and endpoints
- **Feature Flags**: Centralized feature flag management
- **Metadata Storage**: Database metadata, schema information

## Advanced Features

### Change Notifications
```rust
use kvstore_smr::{KVStoreSMR, NotificationBus};

let mut kvstore = KVStoreSMR::new_with_notifications().await?;

// Subscribe to all changes
let subscription = kvstore.subscribe_to_changes().await;

// Subscribe to specific key patterns
let user_subscription = kvstore.subscribe_to_prefix("user:").await;

// Apply operations and receive notifications
kvstore.set("user:123", "john_doe").await?;
// Notification: KeySet { key: "user:123", value: "john_doe", old_value: None }
```

### Batch Operations
```rust
use kvstore_smr::KVOperation;

let batch_ops = vec![
    KVOperation::Set { key: "key1".to_string(), value: "value1".to_string() },
    KVOperation::Set { key: "key2".to_string(), value: "value2".to_string() },
    KVOperation::Delete { key: "old_key".to_string() },
];

let results = kvstore.apply_commands(batch_ops).await;
// All operations applied atomically across replicas
```

### State Snapshots and Recovery
```rust
// Create snapshot
let snapshot = kvstore.serialize_state();

// Restore from snapshot
let mut new_kvstore = KVStoreSMR::new().await?;
new_kvstore.deserialize_state(&snapshot)?;

// Verify restored state
assert_eq!(new_kvstore.size().await, original_size);
```

## Performance Characteristics

### Memory Usage
- Efficient HashMap storage with string interning
- Configurable memory limits and eviction policies
- Compressed snapshots for large datasets

### Throughput
- Optimized for high-frequency SET/GET operations
- Batch operation support for bulk updates
- Asynchronous notification delivery

### Consistency
- Strong consistency across all replicas
- Linearizable read operations
- Atomic batch operations

## Configuration Options

```rust
use kvstore_smr::KVStoreConfig;

let config = KVStoreConfig {
    max_entries: 1_000_000,           // Maximum number of keys
    max_memory_bytes: 1_024_000_000,  // 1GB memory limit
    enable_notifications: true,        // Enable change notifications
    notification_buffer_size: 1000,   // Notification queue size
    snapshot_compression: true,        // Compress snapshots
    key_expiration_enabled: false,    // TTL support (optional)
    metrics_enabled: true,            // Performance metrics
};

let kvstore = KVStoreSMR::new(config).await?;
```

## Implementation Notes

### Why This Works Well for SMR

1. **Deterministic Operations**: Hash map operations are deterministic and reproducible
2. **Efficient Serialization**: Binary serialization minimizes snapshot overhead
3. **Event-Driven Architecture**: Change notifications enable reactive applications
4. **Scalable State**: Can handle large numbers of keys with efficient memory usage

### SMR Considerations

1. **Memory Usage**: Large key-value stores require careful memory management
2. **Snapshot Frequency**: Balance between recovery time and performance overhead
3. **Notification Ordering**: Events are delivered in operation order for consistency
4. **Error Handling**: Robust error handling prevents state machine corruption

## Next Steps

After understanding the KV store example, explore:
- [Banking SMR]../banking_smr/ - Business logic with complex validation
- [Custom State Machine]../custom_state_machine.rs - Template for your own SMR applications
- [Performance Benchmarks]../../benchmarks/ - SMR performance optimization techniques