pub struct ReplicatedEnvironment { /* private fields */ }Expand description
A replicated database environment.
This is the entry point for replication. It wraps a standard Environment and adds replication capabilities including master election, replica streaming, and commit acknowledgments.
High Availability (HA) provides a replicated, embedded database
management system which provides fast, reliable, and scalable data
management. HA enables replication of an environment across a Replication
Group. A ReplicatedEnvironment is a single node in the replication group.
ReplicatedEnvironment wraps a standard Environment. All database
operations are executed in the same fashion in both replicated and
non-replicated applications. A ReplicatedEnvironment must be
transactional. All replicated databases created in the replicated
environment must be transactional as well.
A ReplicatedEnvironment joins its replication group when it is created.
When new() returns, the node will have established contact with the other
members of the group and will be ready to service operations.
Replicated environments can be created with node type Electable or Secondary. Electable nodes can be masters or replicas, and participate in both master elections and commit durability decisions. Secondary nodes can only be replicas, not masters, and do not participate in either elections or durability decisions.
§Example
use noxu_rep::{ReplicatedEnvironment, RepConfig};
let config = RepConfig::builder("my_group", "node1", "localhost")
.node_port(5001)
.build();
let rep_env = ReplicatedEnvironment::new(config).unwrap();Implementations§
Source§impl ReplicatedEnvironment
impl ReplicatedEnvironment
Sourcepub fn new(config: RepConfig) -> Result<Self>
pub fn new(config: RepConfig) -> Result<Self>
Create a new replicated environment.
Creates a replicated environment handle and starts participating in the replication group. The node’s state is determined when it joins the group, and mastership is not preconfigured. If the group has no current master, creation will trigger an election to determine whether this node will participate as a Master or a Replica.
A brand new node will always join an existing group as a Replica, unless it is the very first electable node that is creating the group. In that case it joins as the Master of the newly formed singleton group.
Sourcepub fn open(config: RepConfig) -> Result<Arc<Self>>
pub fn open(config: RepConfig) -> Result<Arc<Self>>
Open a replicated environment with the standard production lifecycle.
This is the entry point recommended by the mdBook chapters:
it allocates the ReplicatedEnvironment, registers all
services on the TCP dispatcher, and spawns the election
driver background thread that runs Paxos rounds against
known peers until the node has resolved into either Master or
Replica state.
Closes finding F6 of docs/src/internal/api-audit-2026-05-rep.md.
Use ReplicatedEnvironment::new directly only when the
caller plans to drive state transitions explicitly (test
harnesses, scripted bootstrap, recovery tooling).
Sourcepub fn init_self_weak(self: &Arc<Self>)
pub fn init_self_weak(self: &Arc<Self>)
Populate the env’s self-referential Weak so background
threads can obtain a back-reference for auto-orchestrated
follow-up actions (e.g. replica auto-bootstrap on
NeedsRestore). Idempotent: subsequent calls are silent
no-ops because the inner OnceLock only accepts one set.
Callers that wrap the env in Arc and want auto-bootstrap
behaviour should call this immediately after construction.
Self::open already does so. Test harnesses that drive
transitions manually (RepTestBase) also call this so the
auto-bootstrap path is exercised in tests.
Sourcepub fn register_admin_service(self: &Arc<Self>)
pub fn register_admin_service(self: &Arc<Self>)
Register the ADMIN service handler on the TCP dispatcher.
Closes findings F7 / F8. Holds a Weak<Self> so the handler
does not extend the env’s lifetime. Idempotent: re-registering
is harmless because TcpServiceDispatcher::register overwrites
the existing handler.
Sourcepub fn start_vlsn_persistence_daemon(self: &Arc<Self>)
pub fn start_vlsn_persistence_daemon(self: &Arc<Self>)
Spawn the VLSN-index persistence daemon (F11).
Periodically (every 2 seconds) snapshots the in-memory
VlsnIndex to <env_home>/vlsn.idx so a clean restart can
resume from where the replica left off without a full network
restore. No-op when config.env_home is None.
Idempotent: only one daemon is ever spawned per env.
Sourcepub fn start_election_driver(self: &Arc<Self>)
pub fn start_election_driver(self: &Arc<Self>)
Spawn the election driver background thread.
While the env is in Detached or Unknown state and no master
is known, the driver periodically attempts a Paxos election
against peers in GroupService (whose ELECTION services were
registered at open() time). On success the driver calls
become_master (if this node is the winner) or become_replica
(otherwise). On failure (no quorum), the driver waits
config.election_timeout and tries again.
The driver respects io_shutdown; on env close the loop exits
promptly.
Idempotent: a second call is a no-op (only one driver thread is ever spawned per env).
Sourcepub fn bound_addr(&self) -> Option<SocketAddr>
pub fn bound_addr(&self) -> Option<SocketAddr>
Return the socket address the TCP service dispatcher is bound to.
This may differ from the configured node_port when port 0 is used
(the OS assigns an ephemeral port). Returns None if the dispatcher
could not be started (e.g. the address is not resolvable).
Sourcepub fn with_environment(&self, env: Arc<EnvironmentImpl>)
pub fn with_environment(&self, env: Arc<EnvironmentImpl>)
Wire a live EnvironmentImpl into this replicated environment.
After this call, state transitions (become_master, become_replica)
will spawn real feeder/receiver I/O threads backed by the live log.
If the RESTORE service was not registered at construction time (because
config.env_home was None), it is registered here using the
environment’s actual home path. This mirrorsRepNode.envSetup()
which registers the restore handler during environment wiring.
Environment reference wiring.
EnvironmentImpl via RepImpl.repNode.envImpl in HA.
Sourcepub fn get_state(&self) -> NodeState
pub fn get_state(&self) -> NodeState
Get the current node state.
Returns the current state of the node associated with this replication
environment. If the caller’s intent is to track the state of the node,
StateChangeListener may be a more convenient and efficient approach.
Sourcepub fn is_master(&self) -> bool
pub fn is_master(&self) -> bool
Check if this node is the master.
Returns true if the node’s current state is Master.
Sourcepub fn is_replica(&self) -> bool
pub fn is_replica(&self) -> bool
Check if this node is a replica.
Returns true if the node’s current state is Replica.
Sourcepub fn is_active(&self) -> bool
pub fn is_active(&self) -> bool
Returns true if the node is currently participating in the group as a Replica or a Master.
Sourcepub fn get_node_name(&self) -> &str
pub fn get_node_name(&self) -> &str
Get the node name.
Returns the unique name used to identify this replicated environment.
Sourcepub fn get_group_name(&self) -> &str
pub fn get_group_name(&self) -> &str
Get the group name.
Returns the name of the replication group this node belongs to.
Sourcepub fn get_master_name(&self) -> Option<String>
pub fn get_master_name(&self) -> Option<String>
Get the current master (if known).
Returns the name of the node that is currently the master, or None if the master is not known (e.g. the node is in the Unknown or Detached state).
Sourcepub fn get_group(&self) -> &GroupService
pub fn get_group(&self) -> &GroupService
Get the replication group info.
Returns a description of the replication group as known by this node. The replicated group metadata is stored in a replicated database and updates are propagated by the current master node to all replicas. If this node is not the master, it is possible for its description of the group to be out of date.
Sourcepub fn add_peer(&self, node: RepNode) -> Result<()>
pub fn add_peer(&self, node: RepNode) -> Result<()>
Add a peer node to the replication group at runtime.
The node is registered in the GroupService so elections and quorum
calculations immediately reflect the new membership.
Sourcepub fn remove_peer(&self, name: &str) -> Result<()>
pub fn remove_peer(&self, name: &str) -> Result<()>
Remove a peer node from the replication group by name.
The node is deregistered from the GroupService. Elections initiated
after this call will not include the removed node in quorum calculations.
Sourcepub fn update_peer_metadata(&self, name: &str, node: RepNode) -> Result<()>
pub fn update_peer_metadata(&self, name: &str, node: RepNode) -> Result<()>
Update the capacity and latency metadata of an existing peer.
Only the following fields are updated from node:
read_capacity_pctwrite_capacity_pctlatency_hint_ms
The node’s identity (name, address, port, node_type) is preserved. Safe to call while replication is active.
If the quorum policy is Flexible or Expression, the quorum system
is rebuilt to reflect the new capacity/latency weights.
§Note
update_peer_metadata does not currently re-run
QuorumPolicy::validate(electable_count) after the metadata
change. An LP-optimal Expression quorum that was safe before
the update may no longer satisfy the intersection property
afterwards. Until automatic revalidation lands, deployments
using QuorumPolicy::Expression should call
quorum_policy().validate(get_rep_group().electable_count())
on the returned RepGroup after every metadata change and
fail the operator-facing operation if validation reports
unsafety.
Sourcepub fn get_rep_group(&self) -> RepGroup
pub fn get_rep_group(&self) -> RepGroup
Returns a snapshot of the current replication group as a RepGroup.
The snapshot reflects the state at the time of the call; subsequent
add_peer / remove_peer calls are not reflected in it.
Sourcepub fn get_config(&self) -> &RepConfig
pub fn get_config(&self) -> &RepConfig
Get the replication configuration.
Returns the replication configuration that has been used to create this environment.
Sourcepub fn get_vlsn_range(&self) -> VlsnRange
pub fn get_vlsn_range(&self) -> VlsnRange
Get the current VLSN range on this node.
Returns the range of VLSNs currently available on this node.
Sourcepub fn get_current_vlsn(&self) -> u64
pub fn get_current_vlsn(&self) -> u64
Get the latest VLSN.
Returns the most recent VLSN registered on this node.
Sourcepub fn feeder_replica_names(&self) -> Vec<String>
pub fn feeder_replica_names(&self) -> Vec<String>
Return the list of replica names that currently have a Feeder
tracker on this (master) node.
Used by tests and operator tooling. The returned list reflects
the master’s view at the time of the call; subsequent
add_peer/remove_peer calls may change it.
Sourcepub fn bootstrap_via_dispatcher(&self, peer_name: &str) -> Result<()>
pub fn bootstrap_via_dispatcher(&self, peer_name: &str) -> Result<()>
Bootstrap this node’s environment by network-restoring all .ndb
files from peer_name via the dispatcher’s RESTORE service.
Closes findings F2 / F4 of docs/src/internal/api-audit-2026-05-rep.md.
The standalone NetworkRestore::execute() opens raw TCP and
expects to drive the legacy NetworkRestoreServer::start listener.
Production replicated environments host the RESTORE handler on the
dispatcher, so this method routes through execute_via_dispatcher.
peer_name must be a known peer in GroupService; on success the
peer’s .ndb files are written into config.env_home. Returns
Err if env_home is None, the peer is unknown, or the restore
fails for any reason.
Sourcepub fn get_stats(&self) -> &RepStats
pub fn get_stats(&self) -> &RepStats
Get replication statistics.
Returns statistics associated with this environment.
Sourcepub fn get_ack_tracker(&self) -> &AckTracker
pub fn get_ack_tracker(&self) -> &AckTracker
Get the ack tracker.
Sourcepub fn ensure_unknown_state(&self) -> Result<()>
pub fn ensure_unknown_state(&self) -> Result<()>
Ensure the node state machine is in Unknown state, transitioning from Detached if necessary. This is needed because the state machine only allows Detached -> Unknown -> Master/Replica.
Sourcepub fn become_master(&self, term: u64) -> Result<()>
pub fn become_master(&self, term: u64) -> Result<()>
Transition to master state.
Transitions this node to Master state for the given election term. As master, the node can accept write operations and feed log entries to replicas.
If a live EnvironmentImpl has been wired in via with_environment,
a FeederRunner + EnvironmentLogScanner background thread is spawned
for each currently-registered replica (feeder entries in feeders).
In HA.
Sourcepub fn become_replica(&self, master_name: &str) -> Result<()>
pub fn become_replica(&self, master_name: &str) -> Result<()>
Transition to replica state with the given master.
Transitions this node to Replica state. The node will receive log entries from the specified master.
If a live EnvironmentImpl has been wired in via with_environment,
the method prepares an EnvironmentLogWriter so that replicated
entries can be written to the local log. The actual network connection
is established by the TcpServiceDispatcher; this method logs intent.
In HA.
Sourcepub fn transfer_master(&self, config: MasterTransferConfig) -> Result<()>
pub fn transfer_master(&self, config: MasterTransferConfig) -> Result<()>
Initiate a master transfer to the target node.
Transfers the current master state from this node to one of the electable replicas. The replica that is actually chosen to be the new master is the one with which the Master Transfer can be completed most rapidly. The transfer operation ensures that all changes at this node are available at the new master upon conclusion of the operation.
Sourcepub fn register_vlsn(&self, vlsn: u64, file_number: u32, file_offset: u32)
pub fn register_vlsn(&self, vlsn: u64, file_number: u32, file_offset: u32)
Register a VLSN (as master, after writing a log entry).
Maps the given VLSN to the specified log file position. This is called by the master after it writes a replicated log entry.
Sourcepub fn replicate_entry(
&self,
vlsn: u64,
file_number: u32,
file_offset: u32,
entry_type: u8,
data: Vec<u8>,
)
pub fn replicate_entry( &self, vlsn: u64, file_number: u32, file_offset: u32, entry_type: u8, data: Vec<u8>, )
Replicate a freshly committed log entry from the master.
Closes finding F9 of docs/src/internal/api-audit-2026-05-rep.md.
Combines register_vlsn with a push into the in-memory
peer_scanner so that downstream replicas pulling from this
node’s PEER_FEEDER service (via catch_up_from_peer) can
stream the entry without round-tripping through the on-disk
log. The local log is still the source of truth; the peer
scanner is a fast-path cache that bounds itself via
PeerLogScanner::with_capacity so old entries are evicted.
Should be called by the master after the local commit has fsynced. Calling on a non-master is harmless (the peer scanner cache is also used by replicas) but is logged at trace level for diagnostics.
Sourcepub fn apply_entry(
&self,
vlsn: u64,
entry_type: u8,
data: Vec<u8>,
) -> Result<()>
pub fn apply_entry( &self, vlsn: u64, entry_type: u8, data: Vec<u8>, ) -> Result<()>
Apply a replicated entry (as replica).
Applies a log entry received from the master. This is called by the replica stream handler after receiving an entry from the feeder.
data is the wire-encoded log-record payload. When the
replicated environment has not been wired to a local
noxu_db::Environment (i.e., before with_environment is
called) the payload is forwarded into the in-memory peer
scanner so that downstream replicas attached to the
PEER_FEEDER service can re-stream it; the local log is not
updated. This is documented behaviour rather than a stub — see
api-audit-2026-05-rep.md finding #26 (medium) for the
with_environment-required local-apply path.
cleanup (rep info F35: _data placeholder) renames the leading
underscore so reviewers don’t read it as a TODO.
Sourcepub fn record_ack(&self, vlsn: u64, replica_name: &str)
pub fn record_ack(&self, vlsn: u64, replica_name: &str)
Record an ack from a replica (as master).
Records that the specified replica has acknowledged processing up to the given VLSN. This is used by the master to track durability guarantees.
Sourcepub fn set_state_change_listener(&self, listener: Arc<dyn StateChangeListener>)
pub fn set_state_change_listener(&self, listener: Arc<dyn StateChangeListener>)
Set the state change listener.
Sets the listener used to receive asynchronous replication node state change events. Note that there is one listener per replication node, not one per handle. Invoking this method adds to the set of listeners.
Invoking this method typically results in an immediate callback to the
application via the on_state_change method, so that the application
is made aware of the existing state of the node at the time the listener
is first established.
Sourcepub fn close(&self) -> Result<()>
pub fn close(&self) -> Result<()>
Close the replicated environment.
Closes this handle and releases any resources. When closed, daemon threads are stopped, even if they are performing work. The node ceases participation in the replication group. If the node was currently the master, the rest of the group will hold an election.
The ReplicatedEnvironment should not be closed while any other type of handle that refers to it is not yet closed.
Sourcepub fn shutdown_group(&self, replica_shutdown_timeout_ms: u64) -> Result<()>
pub fn shutdown_group(&self, replica_shutdown_timeout_ms: u64) -> Result<()>
Close this handle and shut down the Replication Group by forcing all active Replicas to exit.
This method must be invoked on the node that’s currently the Master after all other outstanding handles have been closed. The Master waits for all active Replicas to catch up so that they have a current set of logs, and then shuts them down.
Sourcepub fn is_shutdown(&self) -> bool
pub fn is_shutdown(&self) -> bool
Check if shutdown is in progress.
Trait Implementations§
Source§impl ReplicaAckCoordinator for ReplicatedEnvironment
impl ReplicaAckCoordinator for ReplicatedEnvironment
Source§fn alloc_vlsn_for_recovered_commit(&self, lsn: Lsn) -> u64
fn alloc_vlsn_for_recovered_commit(&self, lsn: Lsn) -> u64
X-3: allocate the next VLSN for a recovered XA commit and register
lsn in the VLSN index so feeders can stream the commit.
Increments off the current latest VLSN so the new VLSN is strictly monotonically increasing. In a single-node or master-less environment (not master) returns 0 (NULL_VLSN — harmless, the default).
Source§fn await_replica_acks(
&self,
policy: ReplicaAckPolicyKind,
timeout: Duration,
) -> Result<u32, AckWaitError>
fn await_replica_acks( &self, policy: ReplicaAckPolicyKind, timeout: Duration, ) -> Result<u32, AckWaitError>
policy.required_acks(electable_count)
replicas have acknowledged the most-recent local commit, or
until timeout elapses, whichever comes first. Read moreAuto Trait Implementations§
impl !Freeze for ReplicatedEnvironment
impl !RefUnwindSafe for ReplicatedEnvironment
impl Send for ReplicatedEnvironment
impl Sync for ReplicatedEnvironment
impl Unpin for ReplicatedEnvironment
impl UnsafeUnpin for ReplicatedEnvironment
impl !UnwindSafe for ReplicatedEnvironment
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more