[builder] Make build cache ignore mtime

Build cache uses pgk/tarsum to get a digest of content which is
ADD'd or COPY'd during a build. The builder has always used v0 of
the tarsum algorithm which includes mtimes however since the whole
file is hashed anyway, the mtime doesn't really provide any extra
information about whether the file has changed and many version
control tools like Git strip mtime from files when they are cloned.

This patch updates the build subsystem to use v1 of Tarsum which
explicitly ignores mtime when calculating a digest. Now ADD and
COPY will result in a cache hit if only the mtime and not the file
contents have changed.

NOTE: Tarsum is NOT a meant to be a cryptographically secure hash
function. It is a best-effort approach to determining if two sets of
filesystem content are different.

Docker-DCO-1.1-Signed-off-by: Josh Hawn <josh.hawn@docker.com> (github: jlhawn)
Upstream-commit: 0e10507a1c5985e6fda0ff48e9313ba7a4de761b
Component: engine
This commit is contained in:
Josh Hawn
2015-04-02 10:42:40 -07:00
parent fda82af70c
commit e778cd68a0
2 changed files with 9 additions and 26 deletions

View File

@ -50,7 +50,7 @@ func (b *Builder) readContext(context io.Reader) error {
return err
}
if b.context, err = tarsum.NewTarSum(decompressedStream, true, tarsum.Version0); err != nil {
if b.context, err = tarsum.NewTarSum(decompressedStream, true, tarsum.Version1); err != nil {
return err
}
@ -345,7 +345,7 @@ func calcCopyInfo(b *Builder, cmdName string, cInfos *[]*copyInfo, origPath stri
if err != nil {
return err
}
tarSum, err := tarsum.NewTarSum(r, true, tarsum.Version0)
tarSum, err := tarsum.NewTarSum(r, true, tarsum.Version1)
if err != nil {
return err
}

View File

@ -2768,7 +2768,6 @@ func (s *DockerSuite) TestBuildAddCurrentDirWithCache(c *check.C) {
name2 := name + "2"
name3 := name + "3"
name4 := name + "4"
name5 := name + "5"
dockerfile := `
FROM scratch
MAINTAINER dockerio
@ -2806,7 +2805,8 @@ func (s *DockerSuite) TestBuildAddCurrentDirWithCache(c *check.C) {
if id2 == id3 {
c.Fatal("The cache should have been invalided but hasn't.")
}
// Check that changing file to same content invalidate cache of "ADD ."
// Check that changing file to same content with different mtime does not
// invalidate cache of "ADD ."
time.Sleep(1 * time.Second) // wait second because of mtime precision
if err := ctx.Add("foo", "hello1"); err != nil {
c.Fatal(err)
@ -2815,14 +2815,7 @@ func (s *DockerSuite) TestBuildAddCurrentDirWithCache(c *check.C) {
if err != nil {
c.Fatal(err)
}
if id3 == id4 {
c.Fatal("The cache should have been invalided but hasn't.")
}
id5, err := buildImageFromContext(name5, ctx, true)
if err != nil {
c.Fatal(err)
}
if id4 != id5 {
if id3 != id4 {
c.Fatal("The cache should have been used but hasn't.")
}
}
@ -2921,7 +2914,6 @@ func (s *DockerSuite) TestBuildAddRemoteFileMTime(c *check.C) {
name := "testbuildaddremotefilemtime"
name2 := name + "2"
name3 := name + "3"
name4 := name + "4"
files := map[string]string{"baz": "hello"}
server, err := fakeStorage(files)
@ -2951,8 +2943,8 @@ func (s *DockerSuite) TestBuildAddRemoteFileMTime(c *check.C) {
c.Fatal("The cache should have been used but wasn't - #1")
}
// Now create a different server withsame contents (causes different mtim)
// This time the cache should not be used
// Now create a different server with same contents (causes different mtime)
// The cache should still be used
// allow some time for clock to pass as mtime precision is only 1s
time.Sleep(2 * time.Second)
@ -2974,17 +2966,8 @@ func (s *DockerSuite) TestBuildAddRemoteFileMTime(c *check.C) {
if err != nil {
c.Fatal(err)
}
if id1 == id3 {
c.Fatal("The cache should not have been used but was")
}
// And for good measure do it again and make sure cache is used this time
id4, err := buildImageFromContext(name4, ctx2, true)
if err != nil {
c.Fatal(err)
}
if id3 != id4 {
c.Fatal("The cache should have been used but wasn't - #2")
if id1 != id3 {
c.Fatal("The cache should have been used but wasn't")
}
}