diff --git a/pkg/model/backup_state.go b/pkg/model/backup_state.go index c713085d..ccaf4641 100644 --- a/pkg/model/backup_state.go +++ b/pkg/model/backup_state.go @@ -7,7 +7,7 @@ import ( // BackupState represents the state of a backup. type BackupState struct { - LastRun time.Time `yaml:"last-run,omitempty" json:"last-run,omitempty"` + LastFullRun time.Time `yaml:"last-run,omitempty" json:"last-run,omitempty"` LastIncrRun time.Time `yaml:"last-incr-run,omitempty" json:"last-incr-run,omitempty"` Performed int `yaml:"performed,omitempty" json:"performed,omitempty"` } diff --git a/pkg/service/backup_backend_local.go b/pkg/service/backup_backend_local.go index e9a5cae9..1ee50794 100644 --- a/pkg/service/backup_backend_local.go +++ b/pkg/service/backup_backend_local.go @@ -91,7 +91,7 @@ func (local *BackupBackendLocal) FullBackupList(from, to int64) ([]model.BackupD return nil, err } - lastRun := local.readState().LastRun + lastRun := local.readState().LastFullRun if local.backupPolicy.RemoveFiles != nil && *local.backupPolicy.RemoveFiles { // when use RemoveFiles = true, backup data is located in backupFolder folder itself if len(entries) == 0 { diff --git a/pkg/service/backup_backend_s3.go b/pkg/service/backup_backend_s3.go index 8f3c1e57..44725f0c 100644 --- a/pkg/service/backup_backend_s3.go +++ b/pkg/service/backup_backend_s3.go @@ -56,7 +56,7 @@ func (s *BackupBackendS3) writeState(state *model.BackupState) error { func (s *BackupBackendS3) FullBackupList(from, to int64) ([]model.BackupDetails, error) { backupFolder := s.Path + "/" + model.FullBackupDirectory + "/" s3prefix := "s3://" + s.bucket - lastRun := s.readState().LastRun + lastRun := s.readState().LastFullRun if s.backupPolicy.RemoveFiles != nil && *s.backupPolicy.RemoveFiles { // when use RemoveFiles = true, backup data is located in backupFolder folder itself files, _ := s.listFiles(backupFolder) diff --git a/pkg/service/backup_scheduler.go b/pkg/service/backup_scheduler.go index 77554840..73b63f29 100644 --- a/pkg/service/backup_scheduler.go +++ b/pkg/service/backup_scheduler.go @@ -160,12 +160,11 @@ func (h *BackupHandler) runFullBackup(now time.Time) { backupSkippedCounter.Inc() return } - if !h.isFullEligible(now, h.state.LastRun) { + if !h.isFullEligible(now, h.state.LastFullRun) { slog.Log(context.Background(), util.LevelTrace, "The full backup is not due to run yet", "name", h.routineName) return } - if !h.fullBackupInProgress.CompareAndSwap(false, true) { slog.Log(context.Background(), util.LevelTrace, "Full backup is currently in progress, skipping full backup", @@ -216,13 +215,13 @@ func (h *BackupHandler) runIncrementalBackup(now time.Time) { } // read the state first and check state := h.backend.readState() - if state.LastRun == (time.Time{}) { + if state.LastFullRun == (time.Time{}) { slog.Log(context.Background(), util.LevelTrace, "Skip incremental backup until initial full backup is done", "name", h.routineName) return } - if !h.isIncrementalEligible(now, state.LastIncrRun) { + if !h.isIncrementalEligible(now, state.LastIncrRun, state.LastFullRun) { slog.Log(context.Background(), util.LevelTrace, "The incremental backup is not due to run yet", "name", h.routineName) return @@ -236,8 +235,8 @@ func (h *BackupHandler) runIncrementalBackup(now time.Time) { var stats *shared.BackupStat backupRunFunc := func() { opts := shared.BackupOptions{} - lastIncrRunEpoch := state.LastIncrRun.UnixNano() - opts.ModAfter = &lastIncrRunEpoch + lastRunEpoch := max(state.LastIncrRun.UnixNano(), state.LastFullRun.UnixNano()) + opts.ModAfter = &lastRunEpoch started := time.Now() slog.Debug("Starting incremental backup", "name", h.routineName) stats = backupService.BackupRun(h.backupRoutine, h.backupIncrPolicy, h.cluster, @@ -277,16 +276,20 @@ func (h *BackupHandler) deleteEmptyBackup(stats *shared.BackupStat, routineName } } -func (h *BackupHandler) isFullEligible(n time.Time, t time.Time) bool { - return n.UnixMilli()-t.UnixMilli() >= *h.backupRoutine.IntervalMillis +func (h *BackupHandler) isFullEligible(now time.Time, lastFullRun time.Time) bool { + return now.UnixMilli()-lastFullRun.UnixMilli() >= *h.backupRoutine.IntervalMillis } -func (h *BackupHandler) isIncrementalEligible(n time.Time, t time.Time) bool { - return n.UnixMilli()-t.UnixMilli() >= *h.backupRoutine.IncrIntervalMillis +func (h *BackupHandler) isIncrementalEligible(now time.Time, lastIncrRun time.Time, lastFullRun time.Time) bool { + if now.UnixMilli()-lastFullRun.UnixMilli() < *h.backupRoutine.IncrIntervalMillis { + return false // Full backup happened recently + } + + return now.UnixMilli()-lastIncrRun.UnixMilli() >= *h.backupRoutine.IncrIntervalMillis } func (h *BackupHandler) updateBackupState() { - h.state.LastRun = time.Now() + h.state.LastFullRun = time.Now() h.state.Performed++ h.writeState() }