1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
//! Defines the [`State`] trait and convenience type aliases.
use std::fmt::Debug;
use crate::LogEntry;
use crate::NodeInfo;
/// Type alias to extract a state's [`Context`][State::Context] type.
pub type ContextOf<S> = <S as State>::Context;
/// Type alias to extract a state's [`LogEntry`][State::LogEntry] type.
pub type LogEntryOf<S> = <S as State>::LogEntry;
/// Type alias to extract [`Id`][LogEntry::Id] type of a state's
/// [`LogEntry`][State::LogEntry] type.
pub type LogEntryIdOf<S> = <LogEntryOf<S> as LogEntry>::Id;
/// Type alias to extract a state's [`Node`][State::Node] type.
pub type NodeOf<S> = <S as State>::Node;
/// Type alias to extract [`Id`][NodeInfo::Id] type of a state's
/// [`Node`][State::Node] type.
pub type NodeIdOf<S> = <NodeOf<S> as NodeInfo>::Id;
/// Type alias to extract a state's [`Outcome`][State::Outcome] type.
pub type OutcomeOf<S> = <S as State>::Outcome;
/// Type alias to extract a state's [`Effect`][State::Effect] type.
pub type EffectOf<S> = <S as State>::Effect;
/// Distributed state to which log entries are applied.
pub trait State: 'static + Clone + Debug + Send + Sized + Sync {
/// Type of log entry that can be applied to this state.
type LogEntry: LogEntry;
/// An execution context.
///
/// The execution context commonly provides access to a working directory or
/// other state that is node and instance specific.
type Context: Debug + Send;
/// Result of applying a log entry to the state.
///
/// This result is what those actively appending to the log receive.
type Outcome: 'static + Clone + Debug + Send + Sync + Unpin;
/// Result of applying a log entry to the state.
///
/// This result is emitted as an [`Apply` event][Apply] event.
///
/// [Apply]: crate::event::Event::Apply
type Effect: 'static + Send + Debug;
/// Node descriptor type, see [`NodeInfo`].
type Node: NodeInfo;
/// Applies the given log entry to this state object.
///
/// Implementations do not have to account for out-of-order application. Log
/// entries are applied in a consistent order accross the cluster.
///
/// Note: The distributed log may contain duplicates of the same event, i.e.
/// entries `e1` and `e2` may be appended to the log for rounds `r1` and
/// `r2` such that `e1.id() == e2.id()` and `r1 != r2`. Implementations that
/// choose to ignore the application of the second entry must take care to
/// do so in a fashion that is consistent across the cluster.
fn apply(
&mut self,
log_entry: &Self::LogEntry,
context: &mut Self::Context,
) -> (Self::Outcome, Self::Effect);
/// Applies the given log entry to this state object.
///
/// This method may be implemented as an optimization. It is called instead
/// of [apply](State::apply) when there are no observers for the result
/// object.
///
/// *Careful*: Implementations must be equivalent to the default
/// implementation in their effects.
fn apply_unobserved(
&mut self,
log_entry: &Self::LogEntry,
context: &mut Self::Context,
) -> Self::Effect {
self.apply(log_entry, context).1
}
/// Returns the current level of concurrency, defaults to one.
fn concurrency(&self) -> std::num::NonZeroUsize {
std::num::NonZeroUsize::new(1).unwrap()
}
/// Returns the set of nodes that make up the cluster at the given round
/// offset.
///
/// The round offset is guaranteed to be less than or equal to the current
/// level of concurrency. As such there must always be a known set of nodes
/// that make up the cluster for the given round.
///
/// The order of the returned set must be determisistic, meaning it must be
/// consistent across the entire cluster.
fn cluster_at(&self, round_offset: std::num::NonZeroUsize) -> Vec<Self::Node>;
}