Skip to content

Commit 7e7a3b6

Browse files
committed
improve: fdb → ledger
1 parent d99633f commit 7e7a3b6

File tree

5 files changed

+70
-19
lines changed

5 files changed

+70
-19
lines changed

config.yaml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# InferaDB Control Configuration - Development Defaults
22
# Good defaults for local development and testing
3+
#
4+
# STORAGE BEHAVIOR:
5+
# - Default is "ledger" (production-ready, cryptographically verifiable)
6+
# - In development environment with no Ledger config, auto-falls back to "memory"
7+
# - Use --dev-mode flag to force memory storage regardless of config
8+
# - Set storage: "memory" explicitly for persistent development mode
39

410
control:
511
frontend:
@@ -10,10 +16,12 @@ control:
1016
grpc: "127.0.0.1:9091"
1117
mesh: "0.0.0.0:9092"
1218

13-
# Storage backend: "memory" (default) or "ledger"
19+
# Storage backend: "ledger" (default, production) or "memory" (development)
20+
# In development mode without Ledger config, automatically uses memory.
21+
# Uncomment to explicitly use memory storage:
1422
# storage: "memory"
1523

16-
# Ledger storage configuration (requires --features ledger)
24+
# Ledger storage configuration (required in production)
1725
# Provides cryptographically verifiable storage using InferaDB Ledger
1826
# ledger:
1927
# endpoint: "http://localhost:50051"

crates/inferadb-control-config/src/lib.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ fn default_logging() -> String {
319319
}
320320

321321
fn default_storage() -> String {
322-
"memory".to_string()
322+
"ledger".to_string()
323323
}
324324

325325
fn default_email_port() -> u16 {
@@ -614,6 +614,39 @@ impl ControlConfig {
614614

615615
Ok(())
616616
}
617+
618+
/// Apply environment-aware defaults for storage backend.
619+
///
620+
/// In development environment, if Ledger is the default but no Ledger configuration
621+
/// is provided, automatically fall back to memory storage for convenience.
622+
/// This allows `cargo run` to "just work" without requiring Ledger setup.
623+
///
624+
/// In production or when Ledger configuration is explicitly provided,
625+
/// no changes are made and validation will enforce proper configuration.
626+
///
627+
/// # Arguments
628+
///
629+
/// * `environment` - The environment name (e.g., "development", "staging", "production")
630+
pub fn apply_environment_defaults(&mut self, environment: &str) {
631+
// Only apply in development environment
632+
if environment != "development" {
633+
return;
634+
}
635+
636+
// If storage is ledger (the default) and no ledger config is provided,
637+
// fall back to memory for developer convenience
638+
if self.storage == "ledger"
639+
&& self.ledger.endpoint.is_none()
640+
&& self.ledger.client_id.is_none()
641+
&& self.ledger.namespace_id.is_none()
642+
{
643+
tracing::info!(
644+
"Development mode: No Ledger configuration provided, using memory storage. \
645+
Set storage='memory' explicitly or provide ledger config to suppress this message."
646+
);
647+
self.storage = "memory".to_string();
648+
}
649+
}
617650
}
618651

619652
#[cfg(test)]
@@ -625,7 +658,7 @@ mod tests {
625658
assert_eq!(default_http(), "127.0.0.1:9090");
626659
assert_eq!(default_grpc(), "127.0.0.1:9091");
627660
assert_eq!(default_mesh(), "0.0.0.0:9092");
628-
assert_eq!(default_storage(), "memory");
661+
assert_eq!(default_storage(), "ledger"); // Ledger is now the default
629662
assert_eq!(default_webauthn_party(), "localhost");
630663
assert_eq!(default_webauthn_origin(), "http://localhost:3000");
631664
}

crates/inferadb-control-storage/src/optimization.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -223,11 +223,8 @@ impl<B: StorageBackend + Clone> BatchWriter<B> {
223223
return Vec::new();
224224
}
225225

226-
let max_bytes = if self.config.enabled {
227-
self.config.max_batch_bytes
228-
} else {
229-
TRANSACTION_SIZE_LIMIT
230-
};
226+
let max_bytes =
227+
if self.config.enabled { self.config.max_batch_bytes } else { TRANSACTION_SIZE_LIMIT };
231228

232229
let max_ops = if self.config.enabled { self.config.max_batch_size } else { usize::MAX };
233230

crates/inferadb-control-storage/tests/ledger_integration_tests.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@
33
//! These tests require a running Ledger server. They are skipped unless the
44
//! `RUN_LEDGER_INTEGRATION_TESTS` environment variable is set.
55
//!
6-
//! Run with: cargo test --test ledger_integration_tests --features ledger
6+
//! Run with: cargo test --test ledger_integration_tests
77
//!
88
//! Or using Docker Compose:
99
//! ```bash
1010
//! cd docker/ledger-integration-tests && ./run-tests.sh
1111
//! ```
1212
13-
#![cfg(feature = "ledger")]
1413
#![allow(clippy::unwrap_used, clippy::expect_used)]
1514

1615
use std::{
@@ -51,7 +50,7 @@ async fn create_ledger_backend() -> LedgerBackend {
5150
let vault_id = unique_vault_id();
5251
let config = LedgerBackendConfig::builder()
5352
.with_endpoint(ledger_endpoint())
54-
.with_client_id(&format!("control-test-{}", vault_id))
53+
.with_client_id(format!("control-test-{}", vault_id))
5554
.with_namespace_id(ledger_namespace_id())
5655
.with_vault_id(vault_id)
5756
.build()
@@ -240,15 +239,13 @@ async fn test_ledger_concurrent_writes() {
240239
return;
241240
}
242241

243-
let backend = create_ledger_backend().await;
244-
245-
// Spawn concurrent writers
242+
// Spawn concurrent writers (each gets its own backend with unique vault)
246243
let mut handles = Vec::new();
247244
for i in 0..10 {
248245
let vault_id = unique_vault_id();
249246
let config = LedgerBackendConfig::builder()
250247
.with_endpoint(ledger_endpoint())
251-
.with_client_id(&format!("concurrent-test-{}", vault_id))
248+
.with_client_id(format!("concurrent-test-{}", vault_id))
252249
.with_namespace_id(ledger_namespace_id())
253250
.with_vault_id(vault_id)
254251
.build()
@@ -284,15 +281,15 @@ async fn test_ledger_vault_isolation() {
284281

285282
let config_a = LedgerBackendConfig::builder()
286283
.with_endpoint(ledger_endpoint())
287-
.with_client_id(&format!("vault-a-{}", vault_a))
284+
.with_client_id(format!("vault-a-{}", vault_a))
288285
.with_namespace_id(ledger_namespace_id())
289286
.with_vault_id(vault_a)
290287
.build()
291288
.unwrap();
292289

293290
let config_b = LedgerBackendConfig::builder()
294291
.with_endpoint(ledger_endpoint())
295-
.with_client_id(&format!("vault-b-{}", vault_b))
292+
.with_client_id(format!("vault-b-{}", vault_b))
296293
.with_namespace_id(ledger_namespace_id())
297294
.with_vault_id(vault_b)
298295
.build()

crates/inferadb-control/src/main.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ struct Args {
2727
/// Environment (development, staging, production)
2828
#[arg(short, long, env = "ENVIRONMENT", default_value = "development")]
2929
environment: String,
30+
31+
/// Force development mode with in-memory storage.
32+
/// Use this flag for local development and testing without Ledger.
33+
/// In production, Ledger storage is the default and required.
34+
#[arg(long)]
35+
dev_mode: bool,
3036
}
3137

3238
#[tokio::main]
@@ -46,7 +52,17 @@ async fn main() -> Result<()> {
4652
}
4753

4854
// Load configuration
49-
let config = ControlConfig::load(&args.config)?;
55+
let mut config = ControlConfig::load(&args.config)?;
56+
57+
// Apply environment-aware defaults (in development, auto-fallback to memory if no Ledger config)
58+
config.apply_environment_defaults(&args.environment);
59+
60+
// Handle --dev-mode flag: force memory storage for development/testing
61+
if args.dev_mode {
62+
tracing::info!("Development mode enabled via --dev-mode flag: using memory storage");
63+
config.storage = "memory".to_string();
64+
}
65+
5066
config.validate()?;
5167

5268
// Initialize structured logging with environment-appropriate format

0 commit comments

Comments
 (0)