Files
Snow LeeandClaude Opus 4.8 64fa269e52 perf(sync): parallel blob upload + progress bar for initial import
The initial import was latency-bound: the push loop uploaded blobs strictly
serially, doing an Exists round-trip then a Put per blob (~2-3N sequential
round-trips against the hub).

- Upload unique blobs in parallel (errgroup, 16 in flight) — the main win.
- Drop the separate Exists round-trip: the backend's Put is idempotent and
  the hub already skips content it has (reported during signing), so the
  check was redundant.
- Session.OnProgress emits upload progress (done/total files + bytes) from
  the push phase; the CLI renders an in-place bar on a TTY and periodic
  percentage lines otherwise, wired into `bdrive init`'s initial cycle and
  `bdrive sync`. The daemon stays silent.

Multi-device convergence tests pass with -race; new TestPushProgress covers
the progress emission.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01R7Q9ZKSZRTdvrSJkYLUmYs
2026-07-10 10:11:54 -07:00

59 lines
1.6 KiB
Go

package main
import (
"fmt"
"os"
"strings"
"sync"
"time"
"github.com/mattn/go-isatty"
"github.com/runbear-io/beardrive/internal/syncer"
)
// progressReporter returns a syncer.OnProgress callback that shows upload
// progress: an in-place bar on a TTY, periodic percentage lines otherwise.
// It's safe to call concurrently from upload workers, and renders are
// throttled so many small blobs don't thrash the terminal. It stays silent
// when there's nothing to upload.
func progressReporter() func(syncer.Progress) {
tty := isatty.IsTerminal(os.Stderr.Fd())
var mu sync.Mutex
var lastDraw time.Time
lastPct := -1
return func(p syncer.Progress) {
if p.Total == 0 {
return
}
mu.Lock()
defer mu.Unlock()
final := p.Done >= p.Total
pct := p.Done * 100 / p.Total
if tty {
if !final && time.Since(lastDraw) < 100*time.Millisecond {
return
}
lastDraw = time.Now()
const w = 24
filled := pct * w / 100
bar := strings.Repeat("█", filled) + strings.Repeat("░", w-filled)
fmt.Fprintf(os.Stderr, "\r uploading [%s] %3d%% %d/%d files %s / %s",
bar, pct, p.Done, p.Total, humanBytes(p.Bytes), humanBytes(p.ToBytes))
if final {
fmt.Fprintln(os.Stderr)
}
return
}
// Non-TTY: announce the total once, then a line every ~10% and at the end.
if lastPct < 0 {
fmt.Fprintf(os.Stderr, " uploading %d files (%s)\n", p.Total, humanBytes(p.ToBytes))
}
if final || pct/10 > lastPct/10 {
fmt.Fprintf(os.Stderr, " %d%% %d/%d files %s / %s\n",
pct, p.Done, p.Total, humanBytes(p.Bytes), humanBytes(p.ToBytes))
}
lastPct = pct
}
}