Compare commits

..
1 Commits
Author SHA1 Message Date
sneak 731126e289 Keep the progress line of a multi-path snapshot within 100% (closes #271)
check / check (push) Canceled after 0s
One progress reporter spans every path of a snapshot. Its counts of
files and bytes processed run across all the paths, while the totals
they were divided by were reset to each path's own, so a second path
smaller than the first showed more than 100% and an ETA of `unknown`.
The totals now add up over the paths scanned so far. The rate behind
the ETA restarts when each path's scan phase ends, so that phase does
not lower the rate while the path is processed; until then the rate is
the previous path's. SetTotalSize is renamed AddTotalSize because it
now adds.

The issue says the ETA went negative; it was computed negative and
printed as `unknown`.

Model: opus-5-5
2026-10-08 04:13:37 +00:00
2 changed files with 11 additions and 10 deletions
+4 -3
View File
@@ -28,9 +28,10 @@ the tag exists and is exercised; what is left is merging `next` to
bytes and files processed counted every path, but the totals they bytes and files processed counted every path, but the totals they
were divided by held only the current path's, so a second path were divided by held only the current path's, so a second path
smaller than the first showed more than 100% and an ETA of `unknown`. smaller than the first showed more than 100% and an ETA of `unknown`.
The totals now add up over the paths scanned so far, and the rate The totals now add up over the paths scanned so far. The rate behind
behind the ETA covers the current path's processing only, so a later the ETA restarts when each path's scan phase ends, so that phase does
path's scan phase does not lower it. not lower the rate while the path is processed; until then the rate
is the previous path's.
- 2026-10-08: Made a second `snapshot create` of one name succeed when - 2026-10-08: Made a second `snapshot create` of one name succeed when
it starts in the same second as the first it starts in the same second as the first
+7 -7
View File
@@ -73,7 +73,7 @@ type ProgressStats struct {
mu sync.RWMutex mu sync.RWMutex
lastDetailTime time.Time lastDetailTime time.Time
// Guarded by mu: when the current path's processing started, and // Guarded by mu: when the last scan phase ended, and
// BytesProcessed at that moment. // BytesProcessed at that moment.
processStartTime time.Time processStartTime time.Time
processStartBytes int64 processStartBytes int64
@@ -155,9 +155,10 @@ func (pr *ProgressReporter) GetStats() *ProgressStats {
// AddTotalSize adds the size one path of the snapshot has to process to // AddTotalSize adds the size one path of the snapshot has to process to
// the total, once that path's scan phase is done, and starts measuring // the total, once that path's scan phase is done, and starts measuring
// the processing rate again. The processed counts run across every path, // the processing rate again. The processed counts run across every path,
// so the total does too. The rate covers the current path's processing // so the total does too. Restarting the rate keeps a path's scan phase,
// only, so that the scan phase of a later path, which processes nothing, // which processes nothing, out of the rate while that path is processed.
// does not lower it. // During a later path's scan phase the rate is still the previous
// path's, and falls as that scan goes on.
func (pr *ProgressReporter) AddTotalSize(size int64) { func (pr *ProgressReporter) AddTotalSize(size int64) {
pr.stats.TotalSize.Add(size) pr.stats.TotalSize.Add(size)
@@ -168,9 +169,8 @@ func (pr *ProgressReporter) AddTotalSize(size int64) {
pr.stats.processStartBytes = pr.stats.BytesProcessed.Load() pr.stats.processStartBytes = pr.stats.BytesProcessed.Load()
} }
// processRate returns the bytes processed per second since the current // processRate returns the bytes processed per second since the last scan
// path's processing started, or 0 before the first path's scan phase is // phase ended, or 0 before the first path's scan phase is done.
// done.
func (s *ProgressStats) processRate() float64 { func (s *ProgressStats) processRate() float64 {
s.mu.RLock() s.mu.RLock()
defer s.mu.RUnlock() defer s.mu.RUnlock()