From 5a804ac05bc3facd61953908da99310a257727a1 Mon Sep 17 00:00:00 2001 From: Anton Tiurin Date: Fri, 21 Nov 2014 03:15:34 +0300 Subject: [PATCH 1/2] [Client] Fix possible goroutine leak. Running goroutines with pullLayer are blocked to send error of a pull operation. If we abort pulling without notify them about cancelation they will get stucked forever. To avoid this possible leak cancelCh was introduced. In case of abort we close that channel to notify other goroutines about cancelation. --- client/pull.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/client/pull.go b/client/pull.go index 825b0c06..dffa392e 100644 --- a/client/pull.go +++ b/client/pull.go @@ -36,6 +36,11 @@ func Pull(c Client, objectStore ObjectStore, name, tag string) error { errChans[i] = make(chan error) } + // To avoid leak goroutine we must notify + // pullLayer goroutines about a cancelation, + // otherwise they will lock forever. + cancelCh := make(chan struct{}) + // Iterate over each layer in the manifest, simultaneously pulling no more // than simultaneousLayerPullWindow layers at a time. If an error is // received from a layer pull, we abort the push. @@ -45,13 +50,17 @@ func Pull(c Client, objectStore ObjectStore, name, tag string) error { err := <-errChans[dependentLayer] if err != nil { log.WithField("error", err).Warn("Pull aborted") + close(cancelCh) return err } } if i < len(manifest.FSLayers) { go func(i int) { - errChans[i] <- pullLayer(c, objectStore, name, manifest.FSLayers[i]) + select { + case errChans[i] <- pullLayer(c, objectStore, name, manifest.FSLayers[i]): + case <-cancelCh: // no chance to recv until cancelCh's closed + } }(i) } } From fdd053a618b1dda08d4ed72625318b8db041dca4 Mon Sep 17 00:00:00 2001 From: Anton Tiurin Date: Fri, 21 Nov 2014 03:24:25 +0300 Subject: [PATCH 2/2] Typo fix --- client/pull.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/pull.go b/client/pull.go index dffa392e..bce06756 100644 --- a/client/pull.go +++ b/client/pull.go @@ -36,7 +36,7 @@ func Pull(c Client, objectStore ObjectStore, name, tag string) error { errChans[i] = make(chan error) } - // To avoid leak goroutine we must notify + // To avoid leak of goroutines we must notify // pullLayer goroutines about a cancelation, // otherwise they will lock forever. cancelCh := make(chan struct{})