fix(walrestore): use timeline-aware barman-cloud end-of-WAL markers

Update `wal-restore` to use the new `barman-cloud` restorer APIs,
resolving a bug that can cause replicas to enter a broken state that
CNPG cant recover from. Local marker naming, WAL timeline parsing, and
restore-result filtering policy lives in
`github.com/cloudnative-pg/barman-cloud/pkg/restorer`. depends on
https://github.com/cloudnative-pg/barman-cloud/pull/277

Signed-off-by: Jeremy Schneider <schneider@ardentperf.com>
This commit is contained in:
Jeremy Schneider 2026-07-06 09:10:06 -07:00
parent 3cc6a882c8
commit f25415eeb4

View File

@ -21,7 +21,6 @@ package common
import (
"context"
"errors"
"fmt"
"os"
"path"
@ -331,9 +330,14 @@ func (w WALServiceImplementation) restoreFromBarmanObjectStore(
return nil
}
// Step 2: return error if the end-of-wal-stream flag is set.
// PostgreSQL treats a restore_command failure as "WAL not available from
// archive" and can then try streaming via primary_conninfo. When prefetch has
// already observed archive exhaustion for this timeline, return one failure to
// let PostgreSQL switch sources instead of repeatedly probing the archive.
// We skip this step if streaming connection is not available
if isStreamingAvailable(cluster, w.InstanceName) {
if err := checkEndOfWALStreamFlag(walRestorer); err != nil {
if err := checkEndOfWALStreamFlag(walRestorer, walName); err != nil {
return err
}
}
@ -366,15 +370,15 @@ func (w WALServiceImplementation) restoreFromBarmanObjectStore(
}
// We skip this step if streaming connection is not available
endOfWALStream := isEndOfWALStream(walStatus)
if isStreamingAvailable(cluster, w.InstanceName) && endOfWALStream {
contextLogger.Info(
"Set end-of-wal-stream flag as one of the WAL files to be prefetched was not found")
err = walRestorer.SetEndOfWALStream()
if isStreamingAvailable(cluster, w.InstanceName) {
endOfWALStream, err := walRestorer.SetEndOfWALStreamFromResults(walStatus)
if err != nil {
return err
}
if endOfWALStream {
contextLogger.Info(
"Set end-of-wal-stream flag as one of the WAL files to be prefetched was not found")
}
}
successfulWalRestore := 0
@ -473,32 +477,14 @@ func gatherWALFilesToRestore(walName string, parallel int) (walList []string, er
return walList, err
}
// checkEndOfWALStreamFlag returns ErrEndOfWALStreamReached if the flag is set in the restorer.
func checkEndOfWALStreamFlag(walRestorer *barmanRestorer.WALRestorer) error {
contain, err := walRestorer.IsEndOfWALStream()
// checkEndOfWALStreamFlag returns ErrEndOfWALStreamReached if the flag is set for the requested WAL timeline.
func checkEndOfWALStreamFlag(walRestorer *barmanRestorer.WALRestorer, walName string) error {
contains, err := walRestorer.ConsumeEndOfWALStreamForWAL(walName)
if err != nil {
return err
}
if contain {
err := walRestorer.ResetEndOfWalStream()
if err != nil {
return err
}
if contains {
return ErrEndOfWALStreamReached
}
return nil
}
// isEndOfWALStream returns true if one of the downloads has returned
// a file-not-found error.
func isEndOfWALStream(results []barmanRestorer.Result) bool {
for _, result := range results {
if errors.Is(result.Err, barmanRestorer.ErrWALNotFound) {
return true
}
}
return false
}