Skip to content

Commit 5619c5c

Browse files
author
rubyist
committed
Syncrhonize uploads until one is successful, then allow concurrent
To prevent being asked for credentials n times (where n = # of concurrent uploads), we process the upload queue synchronously until one of the uploads succeeds, and then allow concurrent uploads. This could be a bit faster if the condition is fired after the first successful API hit, rather than the first successful total upload, but some deeper refactoring will need to be done.
1 parent 23ea409 commit 5619c5c

File tree

1 file changed

+29
-4
lines changed

1 file changed

+29
-4
lines changed

lfs/upload_queue.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ import (
99
"sync/atomic"
1010
)
1111

12+
var (
13+
clientAuthorized = 0
14+
)
15+
1216
// Uploadable describes a file that can be uploaded.
1317
type Uploadable struct {
1418
OIDPath string
@@ -55,15 +59,17 @@ type UploadQueue struct {
5559
files int
5660
finished int64
5761
size int64
62+
authCond *sync.Cond
5863
}
5964

6065
// NewUploadQueue builds an UploadQueue, allowing `workers` concurrent uploads.
6166
func NewUploadQueue(workers, files int) *UploadQueue {
6267
return &UploadQueue{
63-
uploadc: make(chan *Uploadable, files),
64-
errorc: make(chan *WrappedError),
65-
workers: workers,
66-
files: files,
68+
uploadc: make(chan *Uploadable, files),
69+
errorc: make(chan *WrappedError),
70+
workers: workers,
71+
files: files,
72+
authCond: sync.NewCond(&sync.Mutex{}),
6773
}
6874
}
6975

@@ -88,9 +94,19 @@ func (q *UploadQueue) Process() {
8894
}
8995
}()
9096

97+
workersReady := make(chan int, q.workers)
98+
9199
for i := 0; i < q.workers; i++ {
92100
go func(n int) {
101+
workersReady <- 1
102+
93103
for upload := range q.uploadc {
104+
q.authCond.L.Lock()
105+
if clientAuthorized == 0 {
106+
q.authCond.Wait()
107+
}
108+
q.authCond.L.Unlock()
109+
94110
cb := func(total, read int64, current int) error {
95111
bar.Add(current)
96112
if upload.CB != nil {
@@ -102,7 +118,14 @@ func (q *UploadQueue) Process() {
102118
err := Upload(upload.OIDPath, upload.Filename, cb)
103119
if err != nil {
104120
q.errorc <- err
121+
// This one failed, send a Signal() to wake up the next one
122+
q.authCond.Signal()
123+
} else {
124+
// This one succeeded, set the auth condition to 1 and Broadcast()
125+
clientAuthorized = 1
126+
q.authCond.Broadcast()
105127
}
128+
106129
f := atomic.AddInt64(&q.finished, 1)
107130
bar.Prefix(fmt.Sprintf("(%d of %d files) ", f, q.files))
108131
q.wg.Done()
@@ -111,6 +134,8 @@ func (q *UploadQueue) Process() {
111134
}
112135

113136
close(q.uploadc)
137+
<-workersReady
138+
q.authCond.Signal() // Signal the first goroutine to run
114139
q.wg.Wait()
115140
close(q.errorc)
116141

0 commit comments

Comments
 (0)