pub struct RootCutover { /* private fields */ }Expand description
The cutover of one app root. Build it with RootCutover::new, register participants, run it.
Implementations§
Source§impl RootCutover
impl RootCutover
Sourcepub fn new(app: AppRoot, old_root: impl Into<PathBuf>) -> Self
pub fn new(app: AppRoot, old_root: impl Into<PathBuf>) -> Self
A cutover of app’s root (the new root) from old_root. old_root must be an absolute
path to a real directory that does not contain, and is not inside, the new root.
Sourcepub fn fs_move(self, fs_move: FsMove) -> Self
pub fn fs_move(self, fs_move: FsMove) -> Self
How the files travel (default FsMove::None).
Sourcepub fn tree_roots(
self,
resolver: impl Fn(&CutoverContext) -> Result<Vec<PathBuf>, ParticipantError> + Send + 'static,
) -> Self
pub fn tree_roots( self, resolver: impl Fn(&CutoverContext) -> Result<Vec<PathBuf>, ParticipantError> + Send + 'static, ) -> Self
Resolve a bounded tree-root descriptor after every writer has quiesced.
Legal only for FsMove::Tree without static include_roots.
Sourcepub fn participant(self, participant: impl CutoverParticipant + 'static) -> Self
pub fn participant(self, participant: impl CutoverParticipant + 'static) -> Self
Register a participant. Order matters: hooks run in registration order.
Sourcepub fn status(app: &AppRoot) -> Result<Option<RootStatus>, CutoverError>
pub fn status(app: &AppRoot) -> Result<Option<RootStatus>, CutoverError>
The persisted selection of app’s root, or None when no cutover ever started there (the
old root is the only root). Takes no lock and changes nothing. An unreadable record is an
error, never a guess.
Sourcepub fn selected_root(
app: &AppRoot,
legacy: &Path,
) -> Result<PathBuf, CutoverError>
pub fn selected_root( app: &AppRoot, legacy: &Path, ) -> Result<PathBuf, CutoverError>
The root to open: the new root once the switch is durable, otherwise legacy (the old
root the app used before any cutover).
Sourcepub fn run(&mut self) -> Result<CutoverReport, CutoverError>
pub fn run(&mut self) -> Result<CutoverReport, CutoverError>
Run the cutover. Idempotent: a completed cutover returns
already_completed; a switched one is finished (the
roll-forward of recover); an aborted or interrupted one is attempted
again with the next generation.
On Err before the switch the old root is the authority and every prepared participant
was settled as aborted. CutoverError::ReopenPending and CutoverError::Undecided
mean the opposite or unknown: call recover.
CutoverError::SettlementPending preserves new-root authority & retries cleanup only.
Sourcepub fn recover(&mut self) -> Result<RecoverOutcome, CutoverError>
pub fn recover(&mut self) -> Result<RecoverOutcome, CutoverError>
Finish a switched cutover after a restart or a failed reopen, without starting a new one.
Run it at startup, before opening any root: it takes the cutover lock, resolves pending
file transactions, and, when the record says switched, reopens every participant at the
new root and completes. completed with pending settlement invokes only
CutoverParticipant::recover_completed, never reopen or old-root resumption.
A cutover that never reached the switch is left alone
(RecoverOutcome::Nothing: the old root is still the authority).
Sourcepub fn retire_old_root(
app: &AppRoot,
mode: RetireMode,
) -> Result<Retired, CutoverError>
pub fn retire_old_root( app: &AppRoot, mode: RetireMode, ) -> Result<Retired, CutoverError>
Retire the old root of a completed cutover: a separate, identity-checked step that never
runs as part of run. Refuses unless the record is completed and the
directory at the recorded old path still has the file identity recorded when the cutover
started (a path that was replaced is CutoverError::PathSubstituted, never touched), and
the new root still has its recorded identity. Takes the cutover lock.
It never deletes: RetireMode::RenameAside renames the old root beside itself,
RetireMode::Trash uses the platform trash. A crash between the rename and the record
is repaired by calling it again (the aside directory is found by name and identity).