diff options
-rw-r--r-- | tools/nixery/server/builder/builder.go | 1 | ||||
-rw-r--r-- | tools/nixery/server/layers/grouping.go | 8 | ||||
-rw-r--r-- | tools/nixery/server/manifest/manifest.go | 15 |
3 files changed, 20 insertions, 4 deletions
diff --git a/tools/nixery/server/builder/builder.go b/tools/nixery/server/builder/builder.go index d8cbbb8f21c9..614291e660c5 100644 --- a/tools/nixery/server/builder/builder.go +++ b/tools/nixery/server/builder/builder.go @@ -250,6 +250,7 @@ func prepareLayers(ctx context.Context, s *State, image *Image, result *ImageRes if err != nil { return nil, err } + entry.MergeRating = l.MergeRating go cacheLayer(ctx, s, l.Hash(), *entry) entries = append(entries, *entry) diff --git a/tools/nixery/server/layers/grouping.go b/tools/nixery/server/layers/grouping.go index 07a9e0e230a5..9992cd3c13d6 100644 --- a/tools/nixery/server/layers/grouping.go +++ b/tools/nixery/server/layers/grouping.go @@ -141,7 +141,7 @@ type Popularity = map[string]int // build for the container image. type Layer struct { Contents []string `json:"contents"` - mergeRating uint64 + MergeRating uint64 } // Hash the contents of a layer to create a deterministic identifier that can be @@ -153,7 +153,7 @@ func (l *Layer) Hash() string { func (a Layer) merge(b Layer) Layer { a.Contents = append(a.Contents, b.Contents...) - a.mergeRating += b.mergeRating + a.MergeRating += b.MergeRating return a } @@ -291,7 +291,7 @@ func groupLayer(dt *flow.DominatorTree, root *closure) Layer { // both the size and the popularity when making merge // decisions, but there might be a smarter way to do // it than a plain multiplication. - mergeRating: uint64(root.Popularity) * size, + MergeRating: uint64(root.Popularity) * size, } } @@ -309,7 +309,7 @@ func dominate(budget int, graph *simple.DirectedGraph) []Layer { } sort.Slice(layers, func(i, j int) bool { - return layers[i].mergeRating < layers[j].mergeRating + return layers[i].MergeRating < layers[j].MergeRating }) if len(layers) > budget { diff --git a/tools/nixery/server/manifest/manifest.go b/tools/nixery/server/manifest/manifest.go index f777e3f585df..2f236178b65f 100644 --- a/tools/nixery/server/manifest/manifest.go +++ b/tools/nixery/server/manifest/manifest.go @@ -6,6 +6,7 @@ import ( "crypto/sha256" "encoding/json" "fmt" + "sort" ) const ( @@ -27,6 +28,10 @@ type Entry struct { MediaType string `json:"mediaType,omitempty"` Size int64 `json:"size"` Digest string `json:"digest"` + + // This field is internal to Nixery and not part of the + // serialised entry. + MergeRating uint64 `json:"-"` } type manifest struct { @@ -85,6 +90,16 @@ func configLayer(hashes []string) ConfigLayer { // // Callers do not need to set the media type for the layer entries. func Manifest(layers []Entry) (json.RawMessage, ConfigLayer) { + // Sort layers by their merge rating, from highest to lowest. + // This makes it likely for a contiguous chain of shared image + // layers to appear at the beginning of a layer. + // + // Due to moby/moby#38446 Docker considers the order of layers + // when deciding which layers to download again. + sort.Slice(layers, func(i, j int) bool { + return layers[i].MergeRating > layers[j].MergeRating + }) + hashes := make([]string, len(layers)) for i, l := range layers { l.MediaType = "application/vnd.docker.image.rootfs.diff.tar" |