Compare commits

..
1 Commits
Author SHA1 Message Date
sneak 4b017d1811 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 is measured from the bytes processed since the current path's
scan phase ended, so a later path's scan phase does not lower it.
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 03:06:46 +00:00
2 changed files with 10 additions and 11 deletions
+3 -4
View File
@@ -28,10 +28,9 @@ 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. The rate behind The totals now add up over the paths scanned so far, and the rate
the ETA restarts when each path's scan phase ends, so that phase does behind the ETA covers the current path's processing only, so a later
not lower the rate while the path is processed; until then the rate path's scan phase does not lower it.
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 last scan phase ended, and // Guarded by mu: when the current path's processing started, and
// BytesProcessed at that moment. // BytesProcessed at that moment.
processStartTime time.Time processStartTime time.Time
processStartBytes int64 processStartBytes int64
@@ -155,10 +155,9 @@ 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. Restarting the rate keeps a path's scan phase, // so the total does too. The rate covers the current path's processing
// which processes nothing, out of the rate while that path is processed. // only, so that the scan phase of a later path, which processes nothing,
// During a later path's scan phase the rate is still the previous // does not lower it.
// 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)
@@ -169,8 +168,9 @@ 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 last scan // processRate returns the bytes processed per second since the current
// phase ended, or 0 before the first path's scan phase is done. // path's processing started, or 0 before the first path's scan phase is
// 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()