use super::NormalReplica;
use crate::{Commit, Prefix, PrepareOk, ReplicationError};
use ozzy_proto::NodeId;
impl NormalReplica {
pub fn acknowledgment(&self) -> Result<PrepareOk, ReplicationError> {
self.require_normal()?;
if self.is_primary() {
return Err(ReplicationError::WrongRole);
}
Ok(PrepareOk {
scope: self.configuration.scope(),
durable: self.prefix_at(self.journal.snapshot().durable)?,
})
}
pub fn receive_ack(&mut self, from: NodeId, ack: PrepareOk) -> Result<(), ReplicationError> {
let (scope, prefix) = (ack.scope, ack.durable);
self.require_scope(scope)?;
let voter = self.configuration.voter_index(from)?;
if !self.is_primary() || voter == self.local {
return Err(ReplicationError::WrongRole);
}
if prefix.op < self.applied.op {
return Ok(());
}
if self.prefix_at(prefix.op)? != prefix {
return Err(self.conflict());
}
self.acknowledged[voter] = self.acknowledged[voter].max(prefix.op);
self.advance_commit()
}
pub fn announcement(&self) -> Result<Commit, ReplicationError> {
self.require_normal()?;
if !self.is_primary() {
return Err(ReplicationError::WrongRole);
}
Ok(Commit {
scope: self.configuration.scope(),
committed: self.committed,
})
}
pub fn start_view(&self) -> Result<Option<crate::StartView>, ReplicationError> {
self.require_normal()?;
if !self.is_primary() {
return Err(ReplicationError::WrongRole);
}
Ok(self.installed_view)
}
pub(crate) fn activation_prefix(&self) -> Result<Prefix, ReplicationError> {
self.require_normal()?;
let snapshot = self.snapshot();
if self
.installed_view
.is_none_or(|installed| installed.accepted != snapshot.accepted)
|| snapshot.committed != snapshot.accepted
|| snapshot.journal.durable < snapshot.accepted.op
|| (self.is_primary() && self.backup_acknowledged() < snapshot.accepted.op)
{
return Err(ReplicationError::ActivationPending);
}
Ok(snapshot.accepted)
}
pub(crate) fn observe_installed_start(
&mut self,
from: NodeId,
start: crate::StartView,
) -> Result<(), ReplicationError> {
self.require_scope(start.scope)?;
self.require_primary(from)?;
if self.is_primary() {
return Err(ReplicationError::WrongRole);
}
if self.installed_view != Some(start) {
return Err(self.conflict());
}
Ok(())
}
pub fn receive_commit(&mut self, from: NodeId, commit: Commit) -> Result<(), ReplicationError> {
self.require_scope(commit.scope)?;
self.require_primary(from)?;
if self.is_primary() {
return Err(ReplicationError::WrongRole);
}
if commit.committed.op < self.applied.op {
return Ok(());
}
if commit.committed.op > self.accepted.op
&& self.journal_tail.is_none()
&& self.accepted.op > self.known_commit
{
self.known_commit = self.accepted.op;
self.advance_commit()?;
}
if self.prefix_at(commit.committed.op)? != commit.committed {
return Err(self.conflict());
}
self.known_commit = self.known_commit.max(commit.committed.op);
self.advance_commit()
}
}