strata-store
Global reactive state management, struct-level atomic store derives, fine-grained slice selectors, bounded undo/redo time-travel, and Bitcask WAL persistence for Project Strata applications.
Architecture: Pure-Rust State Containers
The [strata-store](file:///home/usr/Projects/larvance/strata/crates/runtime/strata_store/src/lib.rs) crate delivers a zero-runtime-overhead state management solution tailored for cloud-native telemetry consoles, microservice orchestration dashboards, and distributed systems monitoring.
+-------------------------------------------------------+
| Strata Application View Layer |
+---------------------------+---------------------------+
|
+------------------+------------------+
| |
Store.select(|s| s.metric) ReactiveStore Field Signal
| |
v v
+------------------------+ +------------------------+
| Fine-Grained Slices | | Field-Level Signals |
| (Signal<MetricVal>) | | (Signal<Cpu>, Mem...) |
+------------+-----------+ +-----------+------------+
| |
+------------------+------------------+
|
v
+-------------------------------------------------------+
| Core Store Dispatch & History |
| - Store<T>::update() |
| - HistoryStore<T> (Bounded Past/Future Undo Rings) |
+---------------------------+---------------------------+
|
State Mutation Callback
v
+-------------------------------------------------------+
| Bitcask WAL Persistence Engine |
| (create_persistent_store / LocalStorage WAL) |
+---------------------------+---------------------------+
|
Disk / SSD SyncKey Differences from Redux & Zustand
| Feature | Legacy Redux / Zustand | Strata Store (strata-store) |
|---|---|---|
| Re-render Granularity | Component-level virtual DOM diffing | Exact node pointer mutation via fine-grained Signals |
| Selector Overhead | Shallow comparison on every action dispatch | Memoized dirty-flag checking; no notification if unchanged |
| Macro Generation | Manual boilerplate or runtime proxy traps | Zero-cost #[derive(ReactiveStore)] companion generation |
| Transaction Batching | Action middleware or queue batching | Native reactive DAG batching with rollback support |
| State Persistence | Unreliable LocalStorage / IndexedDB serialization | Bitcask append-only write-ahead log (WAL) with CRC verification |
Struct-Level Reactive Store Derive: #[derive(ReactiveStore)]
The #[derive(ReactiveStore)] procedural macro generates a companion <StructName>Store struct where every struct field is transformed into an independent atomic Signal<FieldType>.
Macro Expansion Mechanics
Consider a high-frequency cloud compute node state:
use strata_store::prelude::*;
#[derive(ReactiveStore, Clone, Debug, Default, PartialEq)]
pub struct ClusterNodeState {
pub node_id: String,
pub cpu_utilization: f32,
pub memory_allocated_mb: u64,
pub active_containers: u32,
}The macro expands this struct into a generated companion store:
// Generated by #[derive(ReactiveStore)]
pub struct ClusterNodeStateStore {
pub node_id: strata_dom::Signal<String>,
pub cpu_utilization: strata_dom::Signal<f32>,
pub memory_allocated_mb: strata_dom::Signal<u64>,
pub active_containers: strata_dom::Signal<u32>,
}
impl ClusterNodeStateStore {
pub fn new(initial: ClusterNodeState) -> Self { /* ... */ }
pub fn get(&self) -> ClusterNodeState { /* ... */ }
pub fn set(&self, next: ClusterNodeState) { /* ... */ }
pub fn batch<R>(&self, f: impl FnOnce(&Self) -> R) -> R { /* ... */ }
pub fn snapshot(&self) -> ClusterNodeState { /* ... */ }
pub fn restore(&self, snapshot: &ClusterNodeState) { /* ... */ }
}
impl ClusterNodeState {
pub fn into_store(self) -> ClusterNodeStateStore {
ClusterNodeStateStore::new(self)
}
}Field-Level Independence and Micro-Updates
In a traditional state architecture, updating cpu_utilization triggers re-rendering of all components consuming ClusterNodeState. With #[derive(ReactiveStore)]:
let node = ClusterNodeState {
node_id: "worker-us-east-1a-04".to_string(),
cpu_utilization: 42.5,
memory_allocated_mb: 8192,
active_containers: 16,
}.into_store();
// Mutating a single field notifies ONLY the UI elements bound to that signal:
node.cpu_utilization.set(89.2);
// Sibling fields remain completely unperturbed in memory
assert_eq!(node.memory_allocated_mb.get(), 8192);Atomic Batch Transactions & Snapshots
When multiple related metrics mutate simultaneously, call .batch() to suppress intermediate rendering states:
node.batch(|s| {
s.cpu_utilization.set(94.1);
s.active_containers.set(24);
s.memory_allocated_mb.set(12288);
});
// Subscribers are notified exactly once after all three signals are updated.To take a detached, non-reactive snapshot or perform state rollback:
// Take a snapshot without subscribing to updates
let checkpoint = node.snapshot();
// Perform modifications
node.cpu_utilization.set(99.9);
// Restore checkpoint atomically
node.restore(&checkpoint);
assert_eq!(node.cpu_utilization.get(), 94.1);Global Reactive Container: Store<T>
The [Store<T>](file:///home/usr/Projects/larvance/strata/crates/runtime/strata_store/src/store.rs) container manages arbitrary global states, supporting action dispatchers, mutation closures, and fine-grained selector slices.
API Surface
use strata_store::prelude::*;
#[derive(Clone, PartialEq, Debug)]
pub struct GatewayTelemetry {
pub ingress_bytes_sec: u64,
pub egress_bytes_sec: u64,
pub dropped_packets: u32,
pub active_routes: Vec<String>,
}
let store = create_store(GatewayTelemetry {
ingress_bytes_sec: 104_857_600,
egress_bytes_sec: 52_428_800,
dropped_packets: 0,
active_routes: vec!["/api/v1/auth".into(), "/api/v1/telemetry".into()],
});Mutating State: set and update
// Direct replacement (only triggers listeners if state changed according to PartialEq)
store.set(GatewayTelemetry {
ingress_bytes_sec: 120_000_000,
egress_bytes_sec: 60_000_000,
dropped_packets: 1,
active_routes: store.get().active_routes,
});
// In-place closure mutation
store.update(|telemetry| {
telemetry.dropped_packets += 5;
telemetry.ingress_bytes_sec = 135_000_000;
});Selector Slices (store.select)
Selector slices prevent superfluous UI updates by deriving a dedicated downstream Signal<R> that re-emits only when the projected output value changes:
// Derives a Signal<u32> for dropped packets
let dropped_signal = store.select(|s| s.dropped_packets);
// Derives a Signal<usize> for route count
let route_count_signal = store.select(|s| s.active_routes.len());
// Updating ingress traffic will NOT fire dropped_signal or route_count_signal listeners:
store.update(|s| s.ingress_bytes_sec += 5000);Bounded History Stack: HistoryStore<T>
The [HistoryStore<T>](file:///home/usr/Projects/larvance/strata/crates/runtime/strata_store/src/history.rs) wraps a Store<T> with a dual-vector ring buffer managing bounded undo/redo state histories.
[Undo Step] [Redo Step]
Past Vector <---------------+ Present State +---------------> Future Vector
[S0, S1, S2, ...] (store.state) [..., F2, F1, F0]
(Bounded max_depth) (Cleared on mutation)Configuration & State Rollback
use strata_store::prelude::*;
#[derive(Clone, PartialEq, Debug)]
pub struct AutoScalingPolicy {
pub min_replicas: u32,
pub max_replicas: u32,
pub target_cpu_percent: u32,
}
let history = HistoryStore::new(
AutoScalingPolicy {
min_replicas: 2,
max_replicas: 10,
target_cpu_percent: 75,
},
20, // Bounded buffer depth of 20 historical snapshots
);
assert_eq!(history.get().max_replicas, 10);
assert!(!history.can_undo());
// Scale up policy in response to traffic surge
history.update(|policy| {
policy.max_replicas = 50;
policy.target_cpu_percent = 80;
});
assert_eq!(history.get().max_replicas, 50);
assert!(history.can_undo());
// Operator rolls back deployment configuration change
assert!(history.undo());
assert_eq!(history.get().max_replicas, 10);
assert!(history.can_redo());
// Redo re-applies configuration
assert!(history.redo());
assert_eq!(history.get().max_replicas, 50);
// New mutations truncate any existing forward redo history
history.update(|policy| {
policy.min_replicas = 5;
});
assert!(!history.can_redo());Bitcask WAL Storage Middleware: create_persistent_store
For mission-critical desktop tools and long-running telemetry edge daemons, state must survive process restarts. The [create_persistent_store](file:///home/usr/Projects/larvance/strata/crates/runtime/strata_store/src/persist.rs) function integrates with the [strata_storage::LocalStorage](file:///home/usr/Projects/larvance/strata/crates/runtime/strata_storage/src/lib.rs) Bitcask log-structured storage engine.
Persistence Lifecycle
- Rehydration: On boot, the store synchronously reads the designated key from the Bitcask WAL. If existing valid JSON is located, state is deserialized and initialized; otherwise, the supplied fallback defaults are applied.
- Synchronous/Asynchronous Flushing: On every subsequent state modification, the persistence listener serializes the new state to JSON and records an append-only entry into the WAL.
use serde::{Deserialize, Serialize};
use strata_store::prelude::*;
use strata_storage::LocalStorage;
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
pub struct DashboardPreferences {
pub refresh_interval_ms: u64,
pub active_cluster_filter: String,
pub dark_theme: bool,
}
let storage = LocalStorage::open("/var/log/strata/telemetry_prefs.wal")
.expect("Failed to initialize Bitcask WAL storage");
let options = PersistOptions::new("cloud_console_preferences")
.with_storage(storage);
let initial_fallback = DashboardPreferences {
refresh_interval_ms: 1000,
active_cluster_filter: "all".to_string(),
dark_theme: true,
};
// Rehydrates existing preferences from disk or initializes with fallback
let store = create_persistent_store(options, initial_fallback);
// Updates are automatically committed to the append-only Bitcask WAL
store.update(|prefs| {
prefs.refresh_interval_ms = 250;
prefs.active_cluster_filter = "prod-emea-central".to_string();
});Enterprise Cloud Infrastructure Case Study
The following complete module orchestrates a cluster node autoscaler, combining derive stores, fine-grained slice selectors, history tracking, and atomic batch updates:
use serde::{Deserialize, Serialize};
use strata_dom::prelude::*;
use strata_macro::{component, rsx};
use strata_store::prelude::*;
#[derive(ReactiveStore, Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
pub struct OrchestrationState {
pub desired_instances: u32,
pub running_instances: u32,
pub cluster_load_score: f32,
pub active_datacenter: String,
}
#[component]
pub fn ClusterAutoscalerControl() -> View {
let history = HistoryStore::new(
OrchestrationState {
desired_instances: 8,
running_instances: 8,
cluster_load_score: 0.42,
active_datacenter: "us-east-zone-1".into(),
},
50,
);
// Derive selectors for targeted rendering
let desired_signal = history.store.select(|s| s.desired_instances);
let running_signal = history.store.select(|s| s.running_instances);
let load_signal = history.store.select(|s| s.cluster_load_score);
rsx! {
<div class="p-6 bg-neutral-950 border border-neutral-800 rounded-2xl flex flex-col gap-6">
<div class="flex items-center justify-between border-b border-neutral-800 pb-4">
<div>
<h2 class="text-lg font-bold text-neutral-100">{"Cluster Autoscaler"}</h2>
<p class="text-xs text-neutral-400">{"Autonomous workload scaling engine"}</p>
</div>
<div class="flex items-center gap-2">
<button
class="px-3 py-1.5 text-xs font-mono bg-neutral-800 hover:bg-neutral-700 text-neutral-300 rounded disabled:opacity-40"
disabled={!history.can_undo()}
on_click={move |_| { history.undo(); }}
>
{"Undo"}
</button>
<button
class="px-3 py-1.5 text-xs font-mono bg-neutral-800 hover:bg-neutral-700 text-neutral-300 rounded disabled:opacity-40"
disabled={!history.can_redo()}
on_click={move |_| { history.redo(); }}
>
{"Redo"}
</button>
</div>
</div>
<div class="grid grid-cols-3 gap-4 font-mono text-sm">
<div class="p-3 bg-neutral-900 border border-neutral-800 rounded-lg">
<span class="text-neutral-500 text-xs block">{"RUNNING"}</span>
<span class="text-xl font-bold text-cyan-400">{running_signal.get().to_string()}</span>
</div>
<div class="p-3 bg-neutral-900 border border-neutral-800 rounded-lg">
<span class="text-neutral-500 text-xs block">{"DESIRED"}</span>
<span class="text-xl font-bold text-neutral-200">{desired_signal.get().to_string()}</span>
</div>
<div class="p-3 bg-neutral-900 border border-neutral-800 rounded-lg">
<span class="text-neutral-500 text-xs block">{"LOAD SCORE"}</span>
<span class="text-xl font-bold text-amber-400">{format!("{:.2}", load_signal.get())}</span>
</div>
</div>
<div class="flex gap-3">
<button
class="px-4 py-2 bg-blue-600 hover:bg-blue-500 text-white text-xs font-bold rounded-lg transition"
on_click={move |_| {
history.update(|s| {
s.desired_instances += 4;
s.cluster_load_score += 0.15;
});
}}
>
{"Scale Up (+4)"}
</button>
<button
class="px-4 py-2 bg-neutral-800 hover:bg-neutral-700 text-neutral-200 text-xs font-bold rounded-lg transition"
on_click={move |_| {
history.update(|s| {
if s.desired_instances > 1 {
s.desired_instances -= 1;
}
});
}}
>
{"Scale Down (-1)"}
</button>
</div>
</div>
}
}