返回 DeepSeek-Reasonix
session_catalog_watch_pacing.go
根目录 / desktop / session_catalog_watch_pacing.go
1 package main
2
3 import "time"
4
5 const (
6 catalogWatchBatchDelay = 250 * time.Millisecond
7 catalogRootPaceInitial = time.Second
8 catalogRootPaceMax = time.Minute
9 )
10
11 // catalogRootPacer bounds full-root rescans per directory. A root invalidated
12 // again soon after its last admission waits twice as long as before, so a
13 // trigger that never settles converges to one scan per catalogRootPaceMax.
14 type catalogRootPacer struct {
15 roots map[string]catalogRootPace
16 }
17
18 type catalogRootPace struct {
19 last time.Time
20 delay time.Duration
21 expedited bool // a session file was removed or renamed since the last admission
22 }
23
24 func (p *catalogRootPacer) due(key string) time.Time {
25 pace := p.roots[key]
26 if pace.expedited {
27 return time.Time{}
28 }
29 return pace.last.Add(pace.delay)
30 }
31
32 // expedite admits the root's next scan at once without growing its backoff:
33 // a vanished transcript is user-visible and must not wait behind churn.
34 func (p *catalogRootPacer) expedite(key string) {
35 if p == nil {
36 return
37 }
38 if p.roots == nil {
39 p.roots = map[string]catalogRootPace{}
40 }
41 pace := p.roots[key]
42 pace.expedited = true
43 p.roots[key] = pace
44 }
45
46 func (p *catalogRootPacer) forget(key string) {
47 if p != nil {
48 delete(p.roots, key)
49 }
50 }
51
52 func (p *catalogRootPacer) admitted(key string, now time.Time) {
53 if p.roots == nil {
54 p.roots = map[string]catalogRootPace{}
55 }
56 pace := p.roots[key]
57 if pace.expedited {
58 pace.expedited, pace.last = false, now
59 p.roots[key] = pace
60 return
61 }
62 if pace.last.IsZero() || now.Sub(pace.last) >= 2*catalogRootPaceMax {
63 pace.delay = 0
64 } else {
65 pace.delay = min(max(2*pace.delay, catalogRootPaceInitial), catalogRootPaceMax)
66 }
67 pace.last = now
68 p.roots[key] = pace
69 }
70
71 // catalogWatchBatchTimer keeps one pending batch wake-up, moved earlier when a
72 // new invalidation needs a sooner batch than the deferred one already armed.
73 type catalogWatchBatchTimer struct {
74 timer *time.Timer
75 ready <-chan time.Time
76 at time.Time
77 }
78
79 func (b *catalogWatchBatchTimer) arm(wait time.Duration) {
80 at := time.Now().Add(wait)
81 if b.ready != nil && !at.Before(b.at) {
82 return
83 }
84 if b.timer != nil {
85 b.timer.Stop()
86 }
87 b.timer, b.at = time.NewTimer(wait), at
88 b.ready = b.timer.C
89 }
90
91 func (b *catalogWatchBatchTimer) stop() {
92 if b.timer != nil {
93 b.timer.Stop()
94 }
95 }
96
96 lines GO