Keep a clean look below a share for an hour, so the backup check does not walk the library every 30 s
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
@@ -101,6 +102,9 @@ type Machine struct {
|
||||
// WalkLimit bounds the look for a backup repository below a share.
|
||||
WalkLimit int
|
||||
owners map[string]Owner
|
||||
// clean is when a look below each real path last found no backup repository (LookKept).
|
||||
clean map[string]time.Time
|
||||
cleanMu sync.Mutex
|
||||
}
|
||||
|
||||
// Here is the machine this process runs on.
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// The review of 2026-10-08 (mesh-catalog #136): each finding, reproduced.
|
||||
@@ -311,3 +312,30 @@ func TestWantsFromTheMountsStateKeepOnlyWhatIsAskedOfThisMachine(t *testing.T) {
|
||||
t.Errorf("the tools may write the wants file: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// The look below a share for a backup repository walks up to WalkLimit folders; on a library of tens of
|
||||
// thousands of folders that must not run on every 30 s pass. A clean result is kept for LookKept, and a
|
||||
// repository put there later is found once that has passed.
|
||||
func TestTheLookBelowIsKeptForAWhileAndThenTakenAgain(t *testing.T) {
|
||||
f := newFake(t)
|
||||
f.mountinfo("/")
|
||||
f.dir("/srv/clean/films/one")
|
||||
f.file(ConfigFile, grantsConfig("clean=/srv/clean", "clean=ws:rw"))
|
||||
f.roster("ws 10.0.0.3")
|
||||
f.wants(map[string][]Want{"ws": {{Share: "clean", Access: "rw"}}})
|
||||
m := f.machine()
|
||||
now := time.Date(2026, 10, 8, 19, 0, 0, 0, time.UTC)
|
||||
m.Now = func() time.Time { return now }
|
||||
if s := m.Pass(context.Background(), nil); refusedWhy(s, "clean") != "" {
|
||||
t.Fatalf("a clean folder is refused: %+v", s.Refused)
|
||||
}
|
||||
f.restic("/srv/clean/films/one/backup")
|
||||
now = now.Add(time.Minute)
|
||||
if s := m.Pass(context.Background(), nil); refusedWhy(s, "clean") != "" {
|
||||
t.Errorf("the look was taken again within a minute: %+v", s.Refused)
|
||||
}
|
||||
now = now.Add(LookKept)
|
||||
if s := m.Pass(context.Background(), nil); !strings.Contains(refusedWhy(s, "clean"), "/srv/clean/films/one/backup") {
|
||||
t.Errorf("a repository put there later was not found once the kept look expired: %+v", s.Refused)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// The shares, from the assignment, and the export lines made from them (novox/hq ADR 0263).
|
||||
@@ -242,9 +243,38 @@ const (
|
||||
WalkLimit = 200000
|
||||
)
|
||||
|
||||
// LookKept is how long a look below a share that found no backup repository is believed. The look walks up
|
||||
// to WalkLimit folders, which on a large library is too much for every 30 s pass; a repository put under a
|
||||
// share is found within this long. A look that found one, or was cut short, is never kept: the share stays
|
||||
// refused and is looked at again on the next pass.
|
||||
const LookKept = time.Hour
|
||||
|
||||
// repositoryBelow finds a backup repository within WalkDepth levels below dir. complete is false when
|
||||
// the look stopped at its bound before it saw everything.
|
||||
func (m *Machine) repositoryBelow(dir string) (found string, complete bool) {
|
||||
now := time.Now()
|
||||
if m.Now != nil {
|
||||
now = m.Now()
|
||||
}
|
||||
m.cleanMu.Lock()
|
||||
defer m.cleanMu.Unlock()
|
||||
if at, kept := m.clean[dir]; kept && now.Sub(at) < LookKept {
|
||||
return "", true
|
||||
}
|
||||
found, complete = m.walkBelow(dir)
|
||||
if found == "" && complete {
|
||||
if m.clean == nil {
|
||||
m.clean = map[string]time.Time{}
|
||||
}
|
||||
m.clean[dir] = now
|
||||
} else {
|
||||
delete(m.clean, dir)
|
||||
}
|
||||
return found, complete
|
||||
}
|
||||
|
||||
// walkBelow is the look itself, breadth first, bounded by WalkDepth and WalkLimit.
|
||||
func (m *Machine) walkBelow(dir string) (found string, complete bool) {
|
||||
limit := m.WalkLimit
|
||||
if limit <= 0 {
|
||||
limit = WalkLimit
|
||||
|
||||
Reference in New Issue
Block a user