Fence installation transaction durability (T-613)
This commit is contained in:
+36
-18
@@ -3,7 +3,6 @@ package installer
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
var ErrRecoveryInconsistent = errors.New("install recovery state is inconsistent")
|
||||
@@ -24,6 +23,11 @@ type RecoveryResult struct {
|
||||
|
||||
// Recover resolves an interrupted transaction from journal and directory state.
|
||||
func Recover(root string) (RecoveryResult, error) {
|
||||
return recoverWithFence(root, defaultDurability())
|
||||
}
|
||||
|
||||
func recoverWithFence(root string, fence durabilityFence) (RecoveryResult, error) {
|
||||
fence = effectiveDurability(fence)
|
||||
layout, err := inspectAppLayout(root)
|
||||
if err != nil {
|
||||
return RecoveryResult{}, err
|
||||
@@ -57,18 +61,18 @@ func Recover(root string) (RecoveryResult, error) {
|
||||
state.staging,
|
||||
)
|
||||
}
|
||||
if err := removeManagedDirectory(layout, layout.backup); err != nil {
|
||||
if err := removeManagedDirectoryWithFence(layout, layout.backup, fence); err != nil {
|
||||
return RecoveryResult{}, err
|
||||
}
|
||||
if err := removeTransaction(layout); err != nil {
|
||||
if err := removeTransactionWithFence(layout, fence); err != nil {
|
||||
return RecoveryResult{}, err
|
||||
}
|
||||
result.Action = RecoveryCommitted
|
||||
return result, nil
|
||||
case phaseRollbackRequired:
|
||||
return recoverRollbackRequired(layout, record, state, result)
|
||||
return recoverRollbackRequired(layout, record, state, result, fence)
|
||||
case phasePrepared, phaseCurrentBackedUp, phaseStagingActivated:
|
||||
return recoverUncommitted(layout, record, state, result)
|
||||
return recoverUncommitted(layout, record, state, result, fence)
|
||||
default:
|
||||
return RecoveryResult{}, fmt.Errorf("%w: phase=%q", ErrTransactionCorrupt, record.Phase)
|
||||
}
|
||||
@@ -79,6 +83,7 @@ func recoverUncommitted(
|
||||
record transactionRecord,
|
||||
state directoryState,
|
||||
result RecoveryResult,
|
||||
fence durabilityFence,
|
||||
) (RecoveryResult, error) {
|
||||
if record.HadCurrent {
|
||||
if state.backup {
|
||||
@@ -89,27 +94,39 @@ func recoverUncommitted(
|
||||
)
|
||||
}
|
||||
if state.current {
|
||||
if err := os.Rename(layout.current, layout.staging); err != nil {
|
||||
if err := renameManagedDirectory(
|
||||
layout,
|
||||
layout.current,
|
||||
layout.staging,
|
||||
fence,
|
||||
"app root after recovery staging rename",
|
||||
); err != nil {
|
||||
return RecoveryResult{}, fmt.Errorf("move unverified current aside: %w", err)
|
||||
}
|
||||
}
|
||||
if err := os.Rename(layout.backup, layout.current); err != nil {
|
||||
if err := renameManagedDirectory(
|
||||
layout,
|
||||
layout.backup,
|
||||
layout.current,
|
||||
fence,
|
||||
"app root after recovery current restore",
|
||||
); err != nil {
|
||||
return RecoveryResult{}, fmt.Errorf("restore backup during recovery: %w", err)
|
||||
}
|
||||
if err := removeManagedDirectory(layout, layout.staging); err != nil {
|
||||
if err := removeManagedDirectoryWithFence(layout, layout.staging, fence); err != nil {
|
||||
return RecoveryResult{}, err
|
||||
}
|
||||
if err := removeTransaction(layout); err != nil {
|
||||
if err := removeTransactionWithFence(layout, fence); err != nil {
|
||||
return RecoveryResult{}, err
|
||||
}
|
||||
result.Action = RecoveryRolledBack
|
||||
return result, nil
|
||||
}
|
||||
if record.Phase == phasePrepared && state.current && state.staging {
|
||||
if err := removeManagedDirectory(layout, layout.staging); err != nil {
|
||||
if err := removeManagedDirectoryWithFence(layout, layout.staging, fence); err != nil {
|
||||
return RecoveryResult{}, err
|
||||
}
|
||||
if err := removeTransaction(layout); err != nil {
|
||||
if err := removeTransactionWithFence(layout, fence); err != nil {
|
||||
return RecoveryResult{}, err
|
||||
}
|
||||
result.Action = RecoveryAborted
|
||||
@@ -127,13 +144,13 @@ func recoverUncommitted(
|
||||
ErrRecoveryInconsistent,
|
||||
)
|
||||
}
|
||||
if err := removeManagedDirectory(layout, layout.current); err != nil {
|
||||
if err := removeManagedDirectoryWithFence(layout, layout.current, fence); err != nil {
|
||||
return RecoveryResult{}, err
|
||||
}
|
||||
if err := removeManagedDirectory(layout, layout.staging); err != nil {
|
||||
if err := removeManagedDirectoryWithFence(layout, layout.staging, fence); err != nil {
|
||||
return RecoveryResult{}, err
|
||||
}
|
||||
if err := removeTransaction(layout); err != nil {
|
||||
if err := removeTransactionWithFence(layout, fence); err != nil {
|
||||
return RecoveryResult{}, err
|
||||
}
|
||||
result.Action = RecoveryAborted
|
||||
@@ -145,6 +162,7 @@ func recoverRollbackRequired(
|
||||
record transactionRecord,
|
||||
state directoryState,
|
||||
result RecoveryResult,
|
||||
fence durabilityFence,
|
||||
) (RecoveryResult, error) {
|
||||
if record.HadCurrent && !state.backup {
|
||||
if !state.current {
|
||||
@@ -153,19 +171,19 @@ func recoverRollbackRequired(
|
||||
ErrRecoveryInconsistent,
|
||||
)
|
||||
}
|
||||
if err := removeManagedDirectory(layout, layout.staging); err != nil {
|
||||
if err := removeManagedDirectoryWithFence(layout, layout.staging, fence); err != nil {
|
||||
return RecoveryResult{}, err
|
||||
}
|
||||
if err := removeTransaction(layout); err != nil {
|
||||
if err := removeTransactionWithFence(layout, fence); err != nil {
|
||||
return RecoveryResult{}, err
|
||||
}
|
||||
result.Action = RecoveryRolledBack
|
||||
return result, nil
|
||||
}
|
||||
if err := rollbackActivated(layout, record.HadCurrent); err != nil {
|
||||
if err := rollbackActivated(layout, record.HadCurrent, fence); err != nil {
|
||||
return RecoveryResult{}, err
|
||||
}
|
||||
if err := removeTransaction(layout); err != nil {
|
||||
if err := removeTransactionWithFence(layout, fence); err != nil {
|
||||
return RecoveryResult{}, err
|
||||
}
|
||||
result.Action = RecoveryRolledBack
|
||||
|
||||
Reference in New Issue
Block a user