Previously, its other return value was used even when it returned an
error. This is awkward and goes against the convention. It also could
have resulted in a nil pointer dereference when an error was returned
because of an unknown pool type. This changes the unknown pool type
error to a panic (since the pool types are hardcoded at call sites and
must always be "push" or "pull"), and returns a "found" boolean instead
of an error.
Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
| ... | ... |
@@ -106,8 +106,8 @@ func (s *TagStore) recursiveLoad(address, tmpImageDir string) error {
|
| 106 | 106 |
} |
| 107 | 107 |
|
| 108 | 108 |
// ensure no two downloads of the same layer happen at the same time |
| 109 |
- if ps, err := s.poolAdd("pull", "layer:"+img.ID); err != nil {
|
|
| 110 |
- logrus.Debugf("Image (id: %s) load is already running, waiting: %v", img.ID, err)
|
|
| 109 |
+ if ps, found := s.poolAdd("pull", "layer:"+img.ID); found {
|
|
| 110 |
+ logrus.Debugf("Image (id: %s) load is already running, waiting", img.ID)
|
|
| 111 | 111 |
ps.Wait(nil, nil) |
| 112 | 112 |
return nil |
| 113 | 113 |
} |
| ... | ... |
@@ -17,20 +17,17 @@ func TestPools(t *testing.T) {
|
| 17 | 17 |
pushingPool: make(map[string]*progressreader.ProgressStatus), |
| 18 | 18 |
} |
| 19 | 19 |
|
| 20 |
- if _, err := s.poolAdd("pull", "test1"); err != nil {
|
|
| 21 |
- t.Fatal(err) |
|
| 22 |
- } |
|
| 23 |
- if _, err := s.poolAdd("pull", "test2"); err != nil {
|
|
| 24 |
- t.Fatal(err) |
|
| 20 |
+ if _, found := s.poolAdd("pull", "test1"); found {
|
|
| 21 |
+ t.Fatal("Expected pull test1 not to be in progress")
|
|
| 25 | 22 |
} |
| 26 |
- if _, err := s.poolAdd("push", "test1"); err == nil || err.Error() != "pull test1 is already in progress" {
|
|
| 27 |
- t.Fatalf("Expected `pull test1 is already in progress`")
|
|
| 23 |
+ if _, found := s.poolAdd("pull", "test2"); found {
|
|
| 24 |
+ t.Fatal("Expected pull test2 not to be in progress")
|
|
| 28 | 25 |
} |
| 29 |
- if _, err := s.poolAdd("pull", "test1"); err == nil || err.Error() != "pull test1 is already in progress" {
|
|
| 30 |
- t.Fatalf("Expected `pull test1 is already in progress`")
|
|
| 26 |
+ if _, found := s.poolAdd("push", "test1"); !found {
|
|
| 27 |
+ t.Fatalf("Expected pull test1 to be in progress`")
|
|
| 31 | 28 |
} |
| 32 |
- if _, err := s.poolAdd("wait", "test3"); err == nil || err.Error() != "Unknown pool type" {
|
|
| 33 |
- t.Fatalf("Expected `Unknown pool type`")
|
|
| 29 |
+ if _, found := s.poolAdd("pull", "test1"); !found {
|
|
| 30 |
+ t.Fatalf("Expected pull test1 to be in progress`")
|
|
| 34 | 31 |
} |
| 35 | 32 |
if err := s.poolRemove("pull", "test2"); err != nil {
|
| 36 | 33 |
t.Fatal(err) |
| ... | ... |
@@ -44,7 +41,4 @@ func TestPools(t *testing.T) {
|
| 44 | 44 |
if err := s.poolRemove("push", "test1"); err != nil {
|
| 45 | 45 |
t.Fatal(err) |
| 46 | 46 |
} |
| 47 |
- if err := s.poolRemove("wait", "test3"); err == nil || err.Error() != "Unknown pool type" {
|
|
| 48 |
- t.Fatalf("Expected `Unknown pool type`")
|
|
| 49 |
- } |
|
| 50 | 47 |
} |
| ... | ... |
@@ -138,8 +138,8 @@ func (p *v1Puller) pullRepository(askedTag string) error {
|
| 138 | 138 |
} |
| 139 | 139 |
|
| 140 | 140 |
// ensure no two downloads of the same image happen at the same time |
| 141 |
- ps, err := p.poolAdd("pull", "img:"+img.ID)
|
|
| 142 |
- if err != nil {
|
|
| 141 |
+ ps, found := p.poolAdd("pull", "img:"+img.ID)
|
|
| 142 |
+ if found {
|
|
| 143 | 143 |
msg := p.sf.FormatProgress(stringid.TruncateID(img.ID), "Layer already being pulled by another client. Waiting.", nil) |
| 144 | 144 |
ps.Wait(out, msg) |
| 145 | 145 |
out.Write(p.sf.FormatProgress(stringid.TruncateID(img.ID), "Download complete", nil)) |
| ... | ... |
@@ -155,7 +155,7 @@ func (p *v1Puller) pullRepository(askedTag string) error {
|
| 155 | 155 |
|
| 156 | 156 |
ps.Write(p.sf.FormatProgress(stringid.TruncateID(img.ID), fmt.Sprintf("Pulling image (%s) from %s", img.Tag, p.repoInfo.CanonicalName), nil))
|
| 157 | 157 |
success := false |
| 158 |
- var lastErr error |
|
| 158 |
+ var lastErr, err error |
|
| 159 | 159 |
var isDownloaded bool |
| 160 | 160 |
for _, ep := range p.repoInfo.Index.Mirrors {
|
| 161 | 161 |
ep += "v1/" |
| ... | ... |
@@ -244,9 +244,9 @@ func (p *v1Puller) pullImage(out io.Writer, imgID, endpoint string, token []stri |
| 244 | 244 |
id := history[i] |
| 245 | 245 |
|
| 246 | 246 |
// ensure no two downloads of the same layer happen at the same time |
| 247 |
- ps, err := p.poolAdd("pull", "layer:"+id)
|
|
| 248 |
- if err != nil {
|
|
| 249 |
- logrus.Debugf("Image (id: %s) pull is already running, skipping: %v", id, err)
|
|
| 247 |
+ ps, found := p.poolAdd("pull", "layer:"+id)
|
|
| 248 |
+ if found {
|
|
| 249 |
+ logrus.Debugf("Image (id: %s) pull is already running, skipping", id)
|
|
| 250 | 250 |
msg := p.sf.FormatProgress(stringid.TruncateID(imgID), "Layer already being pulled by another client. Waiting.", nil) |
| 251 | 251 |
ps.Wait(out, msg) |
| 252 | 252 |
} else {
|
| ... | ... |
@@ -73,8 +73,8 @@ func (p *v2Puller) pullV2Repository(tag string) (err error) {
|
| 73 | 73 |
|
| 74 | 74 |
} |
| 75 | 75 |
|
| 76 |
- ps, err := p.poolAdd("pull", taggedName)
|
|
| 77 |
- if err != nil {
|
|
| 76 |
+ ps, found := p.poolAdd("pull", taggedName)
|
|
| 77 |
+ if found {
|
|
| 78 | 78 |
// Another pull of the same repository is already taking place; just wait for it to finish |
| 79 | 79 |
msg := p.sf.FormatStatus("", "Repository %s already being pulled by another client. Waiting.", p.repoInfo.CanonicalName)
|
| 80 | 80 |
ps.Wait(p.config.OutStream, msg) |
| ... | ... |
@@ -119,8 +119,8 @@ func (p *v2Puller) download(di *downloadInfo) {
|
| 119 | 119 |
|
| 120 | 120 |
out := di.out |
| 121 | 121 |
|
| 122 |
- ps, err := p.poolAdd("pull", "img:"+di.img.ID)
|
|
| 123 |
- if err != nil {
|
|
| 122 |
+ ps, found := p.poolAdd("pull", "img:"+di.img.ID)
|
|
| 123 |
+ if found {
|
|
| 124 | 124 |
msg := p.sf.FormatProgress(stringid.TruncateID(di.img.ID), "Layer already being pulled by another client. Waiting.", nil) |
| 125 | 125 |
ps.Wait(out, msg) |
| 126 | 126 |
out.Write(p.sf.FormatProgress(stringid.TruncateID(di.img.ID), "Download complete", nil)) |
| ... | ... |
@@ -214,7 +214,6 @@ func (p *v1Pusher) pushImageToEndpoint(endpoint string, imageIDs []string, tags |
| 214 | 214 |
|
| 215 | 215 |
// pushRepository pushes layers that do not already exist on the registry. |
| 216 | 216 |
func (p *v1Pusher) pushRepository(tag string) error {
|
| 217 |
- |
|
| 218 | 217 |
logrus.Debugf("Local repo: %s", p.localRepo)
|
| 219 | 218 |
p.out = ioutils.NewWriteFlusher(p.config.OutStream) |
| 220 | 219 |
imgList, tags, err := p.getImageList(tag) |
| ... | ... |
@@ -229,8 +228,8 @@ func (p *v1Pusher) pushRepository(tag string) error {
|
| 229 | 229 |
logrus.Debugf("Pushing ID: %s with Tag: %s", data.ID, data.Tag)
|
| 230 | 230 |
} |
| 231 | 231 |
|
| 232 |
- if _, err := p.poolAdd("push", p.repoInfo.LocalName); err != nil {
|
|
| 233 |
- return err |
|
| 232 |
+ if _, found := p.poolAdd("push", p.repoInfo.LocalName); found {
|
|
| 233 |
+ return fmt.Errorf("push or pull %s is already in progress", p.repoInfo.LocalName)
|
|
| 234 | 234 |
} |
| 235 | 235 |
defer p.poolRemove("push", p.repoInfo.LocalName)
|
| 236 | 236 |
|
| ... | ... |
@@ -57,8 +57,8 @@ func (p *v2Pusher) getImageTags(askedTag string) ([]string, error) {
|
| 57 | 57 |
|
| 58 | 58 |
func (p *v2Pusher) pushV2Repository(tag string) error {
|
| 59 | 59 |
localName := p.repoInfo.LocalName |
| 60 |
- if _, err := p.poolAdd("push", localName); err != nil {
|
|
| 61 |
- return err |
|
| 60 |
+ if _, found := p.poolAdd("push", localName); found {
|
|
| 61 |
+ return fmt.Errorf("push or pull %s is already in progress", localName)
|
|
| 62 | 62 |
} |
| 63 | 63 |
defer p.poolRemove("push", localName)
|
| 64 | 64 |
|
| ... | ... |
@@ -428,27 +428,32 @@ func validateDigest(dgst string) error {
|
| 428 | 428 |
return nil |
| 429 | 429 |
} |
| 430 | 430 |
|
| 431 |
-func (store *TagStore) poolAdd(kind, key string) (*progressreader.ProgressStatus, error) {
|
|
| 431 |
+// poolAdd checks if a push or pull is already running, and returns (ps, true) |
|
| 432 |
+// if a running operation is found. Otherwise, it creates a new one and returns |
|
| 433 |
+// (ps, false). |
|
| 434 |
+func (store *TagStore) poolAdd(kind, key string) (*progressreader.ProgressStatus, bool) {
|
|
| 432 | 435 |
store.Lock() |
| 433 | 436 |
defer store.Unlock() |
| 434 | 437 |
|
| 435 | 438 |
if p, exists := store.pullingPool[key]; exists {
|
| 436 |
- return p, fmt.Errorf("pull %s is already in progress", key)
|
|
| 439 |
+ return p, true |
|
| 437 | 440 |
} |
| 438 | 441 |
if p, exists := store.pushingPool[key]; exists {
|
| 439 |
- return p, fmt.Errorf("push %s is already in progress", key)
|
|
| 442 |
+ return p, true |
|
| 440 | 443 |
} |
| 441 | 444 |
|
| 442 | 445 |
ps := progressreader.NewProgressStatus() |
| 446 |
+ |
|
| 443 | 447 |
switch kind {
|
| 444 | 448 |
case "pull": |
| 445 | 449 |
store.pullingPool[key] = ps |
| 446 | 450 |
case "push": |
| 447 | 451 |
store.pushingPool[key] = ps |
| 448 | 452 |
default: |
| 449 |
- return nil, fmt.Errorf("Unknown pool type")
|
|
| 453 |
+ panic("Unknown pool type")
|
|
| 450 | 454 |
} |
| 451 |
- return ps, nil |
|
| 455 |
+ |
|
| 456 |
+ return ps, false |
|
| 452 | 457 |
} |
| 453 | 458 |
|
| 454 | 459 |
func (store *TagStore) poolRemove(kind, key string) error {
|