Skip to content

Commit cdbc363

Browse files
committed
cmd/go: record both build ID and content ID in archives and binaries
The content ID will be needed for content-based staleness determination. It is defined as the SHA256 hash of the file in which it appears, with occurrences of the build+content IDs changed to zeros during the hashing operation. Storing the content ID in the archives is a little tricky but it means that later builds need not rehash the archives each time they are referenced, so under the assumption that each package is imported at least once after being compiled, hashing at build time is a win. (Also the whole file is more likely to be in cache at build time, since we just wrote it.) In my unscientific tests, the time for "go build -a std cmd" rises from about 14.3s to 14.5s on my laptop, or under 2%. Change-Id: Ia3d4dc657d003e8295631f73363868bd92ebf96a Reviewed-on: https://go-review.googlesource.com/69054 Reviewed-by: David Crawshaw <[email protected]>
1 parent 85f93c8 commit cdbc363

File tree

3 files changed

+93
-5
lines changed

3 files changed

+93
-5
lines changed

src/cmd/dist/deps.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/cmd/go/internal/load/pkg.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,12 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
11181118
// For binary-only package, use build ID from supplied package binary.
11191119
buildID, err := buildid.ReadFile(p.Target)
11201120
if err == nil {
1121+
// The stored build ID used to be "<actionID>".
1122+
// Now it is "<actionID>.<contentID>".
1123+
// For now at least, we want only the <actionID> part here.
1124+
if i := strings.Index(buildID, "."); i >= 0 {
1125+
buildID = buildID[:i]
1126+
}
11211127
p.Internal.BuildID = buildID
11221128
}
11231129
} else {
@@ -1215,6 +1221,9 @@ func PackageList(roots []*Package) []*Package {
12151221
// at the named pkgs (command-line arguments).
12161222
func ComputeStale(pkgs ...*Package) {
12171223
for _, p := range PackageList(pkgs) {
1224+
if p.Internal.BuildID == "" {
1225+
computeBuildID(p)
1226+
}
12181227
p.Stale, p.StaleReason = isStale(p)
12191228
}
12201229
}
@@ -1541,6 +1550,12 @@ func isStale(p *Package) (bool, string) {
15411550
// two versions of Go compiling a single GOPATH.
15421551
// See issue 8290 and issue 10702.
15431552
targetBuildID, err := buildid.ReadFile(p.Target)
1553+
// The build ID used to be "<actionID>".
1554+
// Now we've started writing "<actionID>.<contentID>".
1555+
// Ignore contentID for now and record only "<actionID>" here.
1556+
if i := strings.Index(targetBuildID, "."); i >= 0 {
1557+
targetBuildID = targetBuildID[:i]
1558+
}
15441559
if err == nil && targetBuildID != p.Internal.BuildID {
15451560
return true, "build ID mismatch"
15461561
}

src/cmd/go/internal/work/build.go

Lines changed: 77 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"bufio"
99
"bytes"
1010
"container/heap"
11+
"crypto/sha256"
1112
"debug/elf"
1213
"encoding/json"
1314
"errors"
@@ -684,6 +685,7 @@ type Action struct {
684685
Args []string // additional args for runProgram
685686

686687
triggers []*Action // inverse of deps
688+
buildID string
687689

688690
// Generated files, directories.
689691
Objdir string // directory for intermediate objects
@@ -1466,6 +1468,18 @@ func (b *Builder) build(a *Action) (err error) {
14661468
}
14671469
}
14681470

1471+
// We want to keep the action ID available for consultation later,
1472+
// but we'll append to it the SHA256 of the file (without this ID included).
1473+
// We don't know the SHA256 yet, so make one up to find and replace
1474+
// later. Becuase the action ID is a hash of the inputs to this built,
1475+
// the chance of SHA256(actionID) occurring elsewhere in the result
1476+
// of the build is essentially zero, at least in 2017.
1477+
actionID := a.Package.Internal.BuildID
1478+
if actionID == "" {
1479+
return fmt.Errorf("missing action ID")
1480+
}
1481+
a.buildID = actionID + "." + fmt.Sprintf("%x", sha256.Sum256([]byte(actionID)))
1482+
14691483
var gofiles, cgofiles, objdirCgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
14701484

14711485
gofiles = append(gofiles, a.Package.GoFiles...)
@@ -1682,6 +1696,10 @@ func (b *Builder) build(a *Action) (err error) {
16821696
}
16831697
}
16841698

1699+
if err := b.updateBuildID(a, actionID, objpkg); err != nil {
1700+
return err
1701+
}
1702+
16851703
return nil
16861704
}
16871705

@@ -1699,11 +1717,65 @@ func (b *Builder) link(a *Action) (err error) {
16991717
}
17001718
}
17011719

1720+
actionID := a.Package.Internal.BuildID
1721+
if actionID == "" {
1722+
return fmt.Errorf("missing action ID")
1723+
}
1724+
a.buildID = actionID + "." + fmt.Sprintf("%x", sha256.Sum256([]byte(actionID)))
1725+
17021726
objpkg := a.Objdir + "_pkg_.a"
17031727
if err := BuildToolchain.ld(b, a, a.Target, importcfg, objpkg); err != nil {
17041728
return err
17051729
}
17061730

1731+
if err := b.updateBuildID(a, actionID, a.Target); err != nil {
1732+
return err
1733+
}
1734+
1735+
return nil
1736+
}
1737+
1738+
func (b *Builder) updateBuildID(a *Action, actionID, target string) error {
1739+
if cfg.BuildX || cfg.BuildN {
1740+
b.Showcmd("", "%s # internal", joinUnambiguously(str.StringList(base.Tool("buildid"), "-w", target)))
1741+
if cfg.BuildN {
1742+
return nil
1743+
}
1744+
}
1745+
1746+
// Find occurrences of old ID and compute new content-based ID.
1747+
r, err := os.Open(target)
1748+
if err != nil {
1749+
return err
1750+
}
1751+
matches, hash, err := buildid.FindAndHash(r, a.buildID, 0)
1752+
r.Close()
1753+
if err != nil {
1754+
return err
1755+
}
1756+
newID := fmt.Sprintf("%s.%x", actionID, hash)
1757+
if len(newID) != len(a.buildID) {
1758+
return fmt.Errorf("internal error: build ID length mismatch %d+1+%d != %d", len(actionID), len(hash)*2, len(a.buildID))
1759+
}
1760+
1761+
// Replace with new content-based ID.
1762+
a.buildID = newID
1763+
if len(matches) == 0 {
1764+
// Assume the user specified -buildid= to override what we were going to choose.
1765+
return nil
1766+
}
1767+
w, err := os.OpenFile(target, os.O_WRONLY, 0)
1768+
if err != nil {
1769+
return err
1770+
}
1771+
err = buildid.Rewrite(w, matches, newID)
1772+
if err != nil {
1773+
w.Close()
1774+
return err
1775+
}
1776+
if err := w.Close(); err != nil {
1777+
return err
1778+
}
17071779
return nil
17081780
}
17091781

@@ -2451,8 +2523,8 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg []byte, a
24512523
if cfg.BuildContext.InstallSuffix != "" {
24522524
gcargs = append(gcargs, "-installsuffix", cfg.BuildContext.InstallSuffix)
24532525
}
2454-
if p.Internal.BuildID != "" {
2455-
gcargs = append(gcargs, "-buildid", p.Internal.BuildID)
2526+
if a.buildID != "" {
2527+
gcargs = append(gcargs, "-buildid", a.buildID)
24562528
}
24572529
platform := cfg.Goos + "/" + cfg.Goarch
24582530
if p.Internal.OmitDebug || platform == "nacl/amd64p32" || platform == "darwin/arm" || platform == "darwin/arm64" || cfg.Goos == "plan9" {
@@ -2758,7 +2830,7 @@ func (gcToolchain) ld(b *Builder, root *Action, out, importcfg, mainpkg string)
27582830
// Store BuildID inside toolchain binaries as a unique identifier of the
27592831
// tool being run, for use by content-based staleness determination.
27602832
if root.Package.Goroot && strings.HasPrefix(root.Package.ImportPath, "cmd/") {
2761-
ldflags = append(ldflags, "-X=cmd/internal/objabi.buildID="+root.Package.Internal.BuildID)
2833+
ldflags = append(ldflags, "-X=cmd/internal/objabi.buildID="+root.buildID)
27622834
}
27632835

27642836
// If the user has not specified the -extld option, then specify the
@@ -2772,8 +2844,8 @@ func (gcToolchain) ld(b *Builder, root *Action, out, importcfg, mainpkg string)
27722844
compiler = envList("CC", cfg.DefaultCC)
27732845
}
27742846
ldflags = append(ldflags, "-buildmode="+ldBuildmode)
2775-
if root.Package.Internal.BuildID != "" {
2776-
ldflags = append(ldflags, "-buildid="+root.Package.Internal.BuildID)
2847+
if root.buildID != "" {
2848+
ldflags = append(ldflags, "-buildid="+root.buildID)
27772849
}
27782850
ldflags = append(ldflags, cfg.BuildLdflags...)
27792851
ldflags = setextld(ldflags, compiler)

0 commit comments

Comments
 (0)