//! Cluster mode: multi-region tidalDB behind an HTTP surface. //! //! Two cluster modes share this module: //! //! * **Single-process** ([`ClusterState`], the m8p8 dev/demo default): every //! region runs inside ONE process, wrapping [`SimulatedCluster`] with region //! name ↔ [`RegionId`] mapping. Replication between regions still traverses a //! real [`GrpcTransport`] on loopback (not in-process channels), but a crash //! takes the whole "cluster" down — there is no process isolation. //! * **Multi-process** ([`RegionClusterState`], the m8p10 mode, selected by //! `--region`): this process owns exactly ONE region — one [`TidalDb`], one //! [`GrpcTransport`] whose server binds this region's `grpc_addr` and whose //! peers are every sibling region's real `grpc_addr` — and peers with sibling //! processes over real gRPC. Process isolation is real; quorum-ack writes and //! automatic failure detection are still future work. //! //! Both modes are gated behind the same explicit operator opt-in //! ([`ensure_experimental_enabled`]). //! //! # Module layout (M0–M10 review Maintainability-S follow-up) //! //! The original single 1379-line `cluster.rs` carried four loosely-coupled //! concerns; it was split (behavior-neutral) into: //! //! * [`topology`] — `TopologySpec` / `RegionSpec` / `load_topology` / validation //! * [`transport`] — single-process self-loop gRPC transport wiring //! * [`state`] — [`ClusterState`] (single-process) + the experimental gate //! * [`routes`] — the single-process router + handlers //! * [`node`] — [`RegionClusterState`] (multi-process) + its router/handlers //! //! [`GrpcTransport`]: tidal_net::GrpcTransport //! [`RegionId`]: tidaldb::replication::shard::RegionId //! [`SimulatedCluster`]: tidaldb::testing::SimulatedCluster //! [`TidalDb`]: tidaldb::TidalDb pub(crate) mod forward; pub(crate) mod node; pub(crate) mod routes; mod state; mod topology; mod transport; // ── Public API (preserved across the split) ───────────────────────────────── pub use node::{RegionClusterState, build_region_router}; pub use routes::build_cluster_router; pub use state::{ClusterMode, ClusterState, EXPERIMENTAL_CLUSTER_ENV, ensure_experimental_enabled}; pub use topology::{ GrpcTlsSpec, RegionSpec, ReplicationSpec, TimeoutsSpec, TopologySpec, WalSpec, load_topology, validate_multiproc, }; // The OpenAPI documents (`crate::openapi`) reach the handlers/DTOs through // `cluster::routes::…` / `cluster::node::…` directly, so the // `#[utoipa::path]`-generated `__path_*` types resolve in the module that // defines them. `node` reaches `ClusterAppError` via `super::routes`.