Avoid redundant HEAD requests for identical layers on push

pushV2Tag already deduplicates layers, but the scope of this
deduplication is only for a particular tag. If we are pushing all tags
in a repository, we may check layers several times. Fix this by moving
the layersSeen map from the pushV2Tag function to the v2Pusher struct.

In addition to avoiding some useless round-trips, this makes the "docker
push" output less confusing. It formerly could contain many repeated
lines like:

    124e2127157f: Image already exists
    124e2127157f: Image already exists
    ...

Add test coverage based on the "docker push" output: a hash should not
appear multiple times when pushing multiple tags.

Fixes #14873

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
This commit is contained in:
Aaron Lehmann
2015-07-22 17:54:20 -07:00
parent 5fdc102396
commit 810d3b2642
3 changed files with 41 additions and 13 deletions
+27 -3
View File
@@ -60,7 +60,32 @@ func (s *DockerRegistrySuite) TestPushMultipleTags(c *check.C) {
dockerCmd(c, "tag", "busybox", repoTag2)
dockerCmd(c, "push", repoName)
out, _ := dockerCmd(c, "push", repoName)
// There should be no duplicate hashes in the output
imageSuccessfullyPushed := ": Image successfully pushed"
imageAlreadyExists := ": Image already exists"
imagePushHashes := make(map[string]struct{})
outputLines := strings.Split(out, "\n")
for _, outputLine := range outputLines {
if strings.Contains(outputLine, imageSuccessfullyPushed) {
hash := strings.TrimSuffix(outputLine, imageSuccessfullyPushed)
if _, present := imagePushHashes[hash]; present {
c.Fatalf("Duplicate image push: %s", outputLine)
}
imagePushHashes[hash] = struct{}{}
} else if strings.Contains(outputLine, imageAlreadyExists) {
hash := strings.TrimSuffix(outputLine, imageAlreadyExists)
if _, present := imagePushHashes[hash]; present {
c.Fatalf("Duplicate image push: %s", outputLine)
}
imagePushHashes[hash] = struct{}{}
}
}
if len(imagePushHashes) == 0 {
c.Fatal(`Expected at least one line containing "Image successfully pushed"`)
}
}
func (s *DockerRegistrySuite) TestPushInterrupt(c *check.C) {
@@ -79,8 +104,7 @@ func (s *DockerRegistrySuite) TestPushInterrupt(c *check.C) {
c.Fatalf("Failed to kill push process: %v", err)
}
if out, _, err := dockerCmdWithError(c, "push", repoName); err == nil {
str := string(out)
if !strings.Contains(str, "already in progress") {
if !strings.Contains(out, "already in progress") {
c.Fatalf("Push should be continued on daemon side, but seems ok: %v, %s", err, out)
}
}