[][src]Trait async_raft::storage::RaftStorage

pub trait RaftStorage<D, R>: Send + Sync + 'static where
    D: AppData,
    R: AppDataResponse
{ type Snapshot: AsyncRead + AsyncWrite + AsyncSeek + Send + Unpin + 'static; #[must_use] fn get_membership_config<'life0, 'async_trait>(
        &'life0 self
    ) -> Pin<Box<dyn Future<Output = Result<MembershipConfig>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
;
#[must_use] fn get_initial_state<'life0, 'async_trait>(
        &'life0 self
    ) -> Pin<Box<dyn Future<Output = Result<InitialState>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
;
#[must_use] fn save_hard_state<'life0, 'life1, 'async_trait>(
        &'life0 self,
        hs: &'life1 HardState
    ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        'life1: 'async_trait,
        Self: 'async_trait
;
#[must_use] fn get_log_entries<'life0, 'async_trait>(
        &'life0 self,
        start: u64,
        stop: u64
    ) -> Pin<Box<dyn Future<Output = Result<Vec<Entry<D>>>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
;
#[must_use] fn delete_logs_from<'life0, 'async_trait>(
        &'life0 self,
        start: u64,
        stop: Option<u64>
    ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
;
#[must_use] fn append_entry_to_log<'life0, 'life1, 'async_trait>(
        &'life0 self,
        entry: &'life1 Entry<D>
    ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        'life1: 'async_trait,
        Self: 'async_trait
;
#[must_use] fn replicate_to_log<'life0, 'life1, 'async_trait>(
        &'life0 self,
        entries: &'life1 [Entry<D>]
    ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        'life1: 'async_trait,
        Self: 'async_trait
;
#[must_use] fn apply_entry_to_state_machine<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        index: &'life1 u64,
        data: &'life2 D
    ) -> Pin<Box<dyn Future<Output = Result<R>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        'life1: 'async_trait,
        'life2: 'async_trait,
        Self: 'async_trait
;
#[must_use] fn replicate_to_state_machine<'life0, 'life1, 'life2, 'life3, 'async_trait>(
        &'life0 self,
        entries: &'life1 [(&'life2 u64, &'life3 D)]
    ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        'life1: 'async_trait,
        'life2: 'async_trait,
        'life3: 'async_trait,
        Self: 'async_trait
;
#[must_use] fn do_log_compaction<'life0, 'async_trait>(
        &'life0 self,
        through: u64
    ) -> Pin<Box<dyn Future<Output = Result<CurrentSnapshotData<Self::Snapshot>>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
;
#[must_use] fn create_snapshot<'life0, 'async_trait>(
        &'life0 self
    ) -> Pin<Box<dyn Future<Output = Result<(String, Box<Self::Snapshot>)>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
;
#[must_use] fn finalize_snapshot_installation<'life0, 'async_trait>(
        &'life0 self,
        index: u64,
        term: u64,
        delete_through: Option<u64>,
        id: String,
        snapshot: Box<Self::Snapshot>
    ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
;
#[must_use] fn get_current_snapshot<'life0, 'async_trait>(
        &'life0 self
    ) -> Pin<Box<dyn Future<Output = Result<Option<CurrentSnapshotData<Self::Snapshot>>>> + Send + 'async_trait>>
    where
        'life0: 'async_trait,
        Self: 'async_trait
; }

A trait defining the interface for a Raft storage system.

See the storage chapter of the guide for details and discussion on this trait and how to implement it.

Associated Types

type Snapshot: AsyncRead + AsyncWrite + AsyncSeek + Send + Unpin + 'static

The storage engine's associated type used for exposing a snapshot for reading & writing.

Loading content...

Required methods

#[must_use]fn get_membership_config<'life0, 'async_trait>(
    &'life0 self
) -> Pin<Box<dyn Future<Output = Result<MembershipConfig>> + Send + 'async_trait>> where
    'life0: 'async_trait,
    Self: 'async_trait, 

Get the latest membership config found in the log.

This must always be implemented as a reverse search through the log to find the most recent membership config to be appended to the log.

If a snapshot pointer is encountered, then the membership config embedded in that snapshot pointer should be used.

If the system is pristine, then it should return the value of calling MembershipConfig::new_initial(node_id). It is required that the storage engine persist the node's ID so that it is consistent across restarts.

#[must_use]fn get_initial_state<'life0, 'async_trait>(
    &'life0 self
) -> Pin<Box<dyn Future<Output = Result<InitialState>> + Send + 'async_trait>> where
    'life0: 'async_trait,
    Self: 'async_trait, 

Get Raft's state information from storage.

When the Raft node is first started, it will call this interface on the storage system to fetch the last known state from stable storage. If no such entry exists due to being the first time the node has come online, then InitialState::new_initial should be used.

pro tip

The storage impl may need to look in a few different places to accurately respond to this request: the last entry in the log for last_log_index & last_log_term; the node's hard state record; and the index of the last log applied to the state machine.

#[must_use]fn save_hard_state<'life0, 'life1, 'async_trait>(
    &'life0 self,
    hs: &'life1 HardState
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where
    'life0: 'async_trait,
    'life1: 'async_trait,
    Self: 'async_trait, 

Save Raft's hard-state.

#[must_use]fn get_log_entries<'life0, 'async_trait>(
    &'life0 self,
    start: u64,
    stop: u64
) -> Pin<Box<dyn Future<Output = Result<Vec<Entry<D>>>> + Send + 'async_trait>> where
    'life0: 'async_trait,
    Self: 'async_trait, 

Get a series of log entries from storage.

The start value is inclusive in the search and the stop value is non-inclusive: [start, stop).

#[must_use]fn delete_logs_from<'life0, 'async_trait>(
    &'life0 self,
    start: u64,
    stop: Option<u64>
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where
    'life0: 'async_trait,
    Self: 'async_trait, 

Delete all logs starting from start and stopping at stop, else continuing to the end of the log if stop is None.

#[must_use]fn append_entry_to_log<'life0, 'life1, 'async_trait>(
    &'life0 self,
    entry: &'life1 Entry<D>
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where
    'life0: 'async_trait,
    'life1: 'async_trait,
    Self: 'async_trait, 

Append a new entry to the log.

#[must_use]fn replicate_to_log<'life0, 'life1, 'async_trait>(
    &'life0 self,
    entries: &'life1 [Entry<D>]
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where
    'life0: 'async_trait,
    'life1: 'async_trait,
    Self: 'async_trait, 

Replicate a payload of entries to the log.

Though the entries will always be presented in order, each entry's index should be used to determine its location to be written in the log.

#[must_use]fn apply_entry_to_state_machine<'life0, 'life1, 'life2, 'async_trait>(
    &'life0 self,
    index: &'life1 u64,
    data: &'life2 D
) -> Pin<Box<dyn Future<Output = Result<R>> + Send + 'async_trait>> where
    'life0: 'async_trait,
    'life1: 'async_trait,
    'life2: 'async_trait,
    Self: 'async_trait, 

Apply the given log entry to the state machine.

The Raft protocol guarantees that only logs which have been committed, that is, logs which have been replicated to a majority of the cluster, will be applied to the state machine.

This is where the business logic of interacting with your application's state machine should live. This is 100% application specific. Perhaps this is where an application specific transaction is being started, or perhaps committed. This may be where a key/value is being stored. This may be where an entry is being appended to an immutable log.

The behavior here is application specific, but errors should never be returned unless the error represents an actual failure to apply the entry. An error returned here will cause the Raft node to shutdown in order to preserve the safety of the data and avoid corruption. If instead some application specific error needs to be returned to the client, those variants must be encapsulated in the type R, which may have application specific success and error variants encoded in the type, perhaps using an inner Result type.

#[must_use]fn replicate_to_state_machine<'life0, 'life1, 'life2, 'life3, 'async_trait>(
    &'life0 self,
    entries: &'life1 [(&'life2 u64, &'life3 D)]
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where
    'life0: 'async_trait,
    'life1: 'async_trait,
    'life2: 'async_trait,
    'life3: 'async_trait,
    Self: 'async_trait, 

Apply the given payload of entries to the state machine, as part of replication.

The Raft protocol guarantees that only logs which have been committed, that is, logs which have been replicated to a majority of the cluster, will be applied to the state machine.

#[must_use]fn do_log_compaction<'life0, 'async_trait>(
    &'life0 self,
    through: u64
) -> Pin<Box<dyn Future<Output = Result<CurrentSnapshotData<Self::Snapshot>>> + Send + 'async_trait>> where
    'life0: 'async_trait,
    Self: 'async_trait, 

Perform log compaction, returning a handle to the generated snapshot.

through

The log should be compacted starting from entry 0 and should cover all entries through the index specified by through, inclusively. This will always be the commit_index of the Raft log at the time of the request.

implementation guide

See the storage chapter of the guide for details on how to implement this handler.

#[must_use]fn create_snapshot<'life0, 'async_trait>(
    &'life0 self
) -> Pin<Box<dyn Future<Output = Result<(String, Box<Self::Snapshot>)>> + Send + 'async_trait>> where
    'life0: 'async_trait,
    Self: 'async_trait, 

Create a new blank snapshot, returning a writable handle to the snapshot object along with the ID of the snapshot.

implementation guide

See the storage chapter of the guide for details on how to implement this handler.

#[must_use]fn finalize_snapshot_installation<'life0, 'async_trait>(
    &'life0 self,
    index: u64,
    term: u64,
    delete_through: Option<u64>,
    id: String,
    snapshot: Box<Self::Snapshot>
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>> where
    'life0: 'async_trait,
    Self: 'async_trait, 

Finalize the installation of a snapshot which has finished streaming from the cluster leader.

Delete all entries in the log through delete_through, unless None, in which case all entries of the log are to be deleted.

Write a new snapshot pointer to the log at the given index. The snapshot pointer should be constructed via the Entry::new_snapshot_pointer constructor and the other parameters provided to this method.

All other snapshots should be deleted at this point.

snapshot

A snapshot created from an earlier call to created_snapshot which provided the snapshot. By the time ownership of the snapshot object is returned here, its AsyncWriteExt.shutdown() method will have been called, so no additional writes should be made to the snapshot.

#[must_use]fn get_current_snapshot<'life0, 'async_trait>(
    &'life0 self
) -> Pin<Box<dyn Future<Output = Result<Option<CurrentSnapshotData<Self::Snapshot>>>> + Send + 'async_trait>> where
    'life0: 'async_trait,
    Self: 'async_trait, 

Get a readable handle to the current snapshot, along with its metadata.

implementation algorithm

Implementing this method should be straightforward. Check the configured snapshot directory for any snapshot files. A proper implementation will only ever have one active snapshot, though another may exist while it is being created. As such, it is recommended to use a file naming pattern which will allow for easily distinguishing between the current live snapshot, and any new snapshot which is being created.

A proper snapshot implementation will store the term, index and membership config as part of the snapshot, which should be decoded for creating this method's response data.

Loading content...

Implementors

Loading content...