Milestone 8 (phases 1-4): - Shard-aware WAL segment naming, BatchHeader v2, ShardRouter - Transport trait, InProcessTransport, WalShipper, FollowerDb - HLC, PNCounter, LWWRegister, CrdtSignalState, ReconciliationEngine - Session replication bridge with SeqNo/HWM, idempotency store Forage application: - Multi-source discovery engine with MAB exploration - Embedding-based label system, server handlers, UI refresh Other: - QUICKSTART.md, README.md, milestone-8 planning docs - Hard negative union semantics, RLHF export enhancements - Recovery benchmark and visibility test expansions - Split 8 oversized source files per CODING_GUIDELINES §9 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
124 lines
3.5 KiB
Markdown
124 lines
3.5 KiB
Markdown
# Task 05: NodeConfig
|
|
|
|
## Delivers
|
|
|
|
Add `NodeConfig` struct to `tidal/src/db/config.rs` extending `Config` with cluster fields (`role`, `shard_id`, `region_id`, `peer_shards`). Defaults produce a single-node config with zero changes to existing embedders.
|
|
|
|
## Complexity: S
|
|
|
|
## Dependencies
|
|
|
|
- Task 01 (ShardId, RegionId, NodeRole types)
|
|
- Task 02 (ShardRouter)
|
|
|
|
## Technical Design
|
|
|
|
```rust
|
|
// tidal/src/db/config.rs
|
|
|
|
/// Cluster configuration for distributed tidalDB deployments.
|
|
///
|
|
/// Defaults produce a single-node configuration identical to M0-M7 behavior.
|
|
/// Embedded deployments that do not set any cluster fields get single-node.
|
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
|
pub struct NodeConfig {
|
|
/// The role of this node.
|
|
///
|
|
/// Default: `NodeRole::Single` (standalone, accepts reads and writes).
|
|
pub role: NodeRole,
|
|
|
|
/// This node's shard identity.
|
|
///
|
|
/// Default: `ShardId(0)` (single-node shard).
|
|
pub shard_id: ShardId,
|
|
|
|
/// This node's region identity.
|
|
///
|
|
/// Default: `RegionId(0)` (single-node region).
|
|
pub region_id: RegionId,
|
|
|
|
/// Shards this node is aware of (including itself).
|
|
///
|
|
/// Empty for single-node deployments.
|
|
pub peer_shards: Vec<ShardId>,
|
|
|
|
/// Routing strategy for entity-to-shard assignment.
|
|
///
|
|
/// Default: `ShardRouter::single()` (all entities -> ShardId(0)).
|
|
#[serde(skip)]
|
|
pub router: ShardRouter,
|
|
}
|
|
|
|
impl Default for NodeConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
role: NodeRole::Single,
|
|
shard_id: ShardId::SINGLE,
|
|
region_id: RegionId::SINGLE,
|
|
peer_shards: vec![],
|
|
router: ShardRouter::single(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl NodeConfig {
|
|
/// Returns true if this is a standalone single-node deployment.
|
|
pub fn is_single_node(&self) -> bool {
|
|
self.role == NodeRole::Single
|
|
}
|
|
|
|
/// Returns true if this node accepts writes.
|
|
pub fn accepts_writes(&self) -> bool {
|
|
matches!(self.role, NodeRole::Single | NodeRole::Leader)
|
|
}
|
|
}
|
|
```
|
|
|
|
### Integration into Config
|
|
|
|
```rust
|
|
// tidal/src/db/config.rs -- extend existing Config struct
|
|
|
|
pub struct Config {
|
|
// ... existing fields ...
|
|
|
|
/// Cluster configuration. Default: single-node.
|
|
pub cluster: NodeConfig,
|
|
}
|
|
|
|
impl Default for Config {
|
|
fn default() -> Self {
|
|
Self {
|
|
// ... existing defaults ...
|
|
cluster: NodeConfig::default(),
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Builder integration
|
|
|
|
```rust
|
|
// TidalDb::builder() -- add optional cluster config method
|
|
|
|
impl TidalDbBuilder {
|
|
/// Configure this instance for distributed deployment.
|
|
///
|
|
/// Not required for single-node embedded use.
|
|
pub fn with_cluster(mut self, config: NodeConfig) -> Self {
|
|
self.config.cluster = config;
|
|
self
|
|
}
|
|
}
|
|
```
|
|
|
|
## Acceptance Criteria
|
|
|
|
- [ ] `NodeConfig::default()` produces `role=Single`, `shard_id=ShardId(0)`, `region_id=RegionId(0)`, `peer_shards=[]`, `router=ShardRouter::single()`
|
|
- [ ] `NodeConfig::is_single_node()` returns true for `Single`, false for `Leader`/`Follower`
|
|
- [ ] `NodeConfig::accepts_writes()` returns true for `Single` and `Leader`, false for `Follower`
|
|
- [ ] `Config` gains a `cluster: NodeConfig` field with default `NodeConfig::default()`
|
|
- [ ] All existing tests that construct `Config` or use `TidalDb::builder()` pass unchanged (cluster field defaults to single-node)
|
|
- [ ] `TidalDbBuilder::with_cluster(config)` sets the cluster config
|
|
- [ ] `cargo clippy -D warnings` and `cargo fmt` pass
|