Skip to content

Commit

Permalink
Merge pull request #5374 from jsternberg/marshal-constraints-cache
Browse files Browse the repository at this point in the history
llb: deterministic marshaling for protobuf and store results from multiple constraints
  • Loading branch information
tonistiigi authored Oct 2, 2024
2 parents a38e4cc + d59218e commit 8445ccf
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 49 deletions.
10 changes: 4 additions & 6 deletions client/llb/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (

"github.com/moby/buildkit/solver/pb"
digest "github.com/opencontainers/go-digest"
protobuf "google.golang.org/protobuf/proto"
)

type DiffOp struct {
Expand All @@ -32,8 +31,8 @@ func (m *DiffOp) Validate(ctx context.Context, constraints *Constraints) error {
}

func (m *DiffOp) Marshal(ctx context.Context, constraints *Constraints) (digest.Digest, []byte, *pb.OpMetadata, []*SourceLocation, error) {
if m.Cached(constraints) {
return m.Load()
if dgst, dt, md, srcs, err := m.Load(constraints); err == nil {
return dgst, dt, md, srcs, nil
}
if err := m.Validate(ctx, constraints); err != nil {
return "", nil, nil, nil, err
Expand Down Expand Up @@ -68,13 +67,12 @@ func (m *DiffOp) Marshal(ctx context.Context, constraints *Constraints) (digest.

proto.Op = &pb.Op_Diff{Diff: op}

dt, err := protobuf.Marshal(proto)
dt, err := deterministicMarshal(proto)
if err != nil {
return "", nil, nil, nil, err
}

m.Store(dt, md, m.constraints.SourceLocations, constraints)
return m.Load()
return m.Store(dt, md, m.constraints.SourceLocations, constraints)
}

func (m *DiffOp) Output() Output {
Expand Down
10 changes: 5 additions & 5 deletions client/llb/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,10 @@ func (e *ExecOp) Validate(ctx context.Context, c *Constraints) error {
}

func (e *ExecOp) Marshal(ctx context.Context, c *Constraints) (digest.Digest, []byte, *pb.OpMetadata, []*SourceLocation, error) {
if e.Cached(c) {
return e.Load()
if dgst, dt, md, srcs, err := e.Load(c); err == nil {
return dgst, dt, md, srcs, nil
}

if err := e.Validate(ctx, c); err != nil {
return "", nil, nil, nil, err
}
Expand Down Expand Up @@ -442,12 +443,11 @@ func (e *ExecOp) Marshal(ctx context.Context, c *Constraints) (digest.Digest, []
peo.Mounts = append(peo.Mounts, pm)
}

dt, err := proto.Marshal(pop)
dt, err := deterministicMarshal(pop)
if err != nil {
return "", nil, nil, nil, err
}
e.Store(dt, md, e.constraints.SourceLocations, c)
return e.Load()
return e.Store(dt, md, e.constraints.SourceLocations, c)
}

func (e *ExecOp) Output() Output {
Expand Down
10 changes: 5 additions & 5 deletions client/llb/fileop.go
Original file line number Diff line number Diff line change
Expand Up @@ -730,9 +730,10 @@ func (ms *marshalState) add(fa *FileAction, c *Constraints) (*fileActionState, e
}

func (f *FileOp) Marshal(ctx context.Context, c *Constraints) (digest.Digest, []byte, *pb.OpMetadata, []*SourceLocation, error) {
if f.Cached(c) {
return f.Load()
if dgst, dt, md, srcs, err := f.Load(c); err == nil {
return dgst, dt, md, srcs, nil
}

if err := f.Validate(ctx, c); err != nil {
return "", nil, nil, nil, err
}
Expand Down Expand Up @@ -795,12 +796,11 @@ func (f *FileOp) Marshal(ctx context.Context, c *Constraints) (digest.Digest, []
})
}

dt, err := proto.Marshal(pop)
dt, err := deterministicMarshal(pop)
if err != nil {
return "", nil, nil, nil, err
}
f.Store(dt, md, f.constraints.SourceLocations, c)
return f.Load()
return f.Store(dt, md, f.constraints.SourceLocations, c)
}

func normalizePath(parent, p string, keepSlash bool) string {
Expand Down
8 changes: 4 additions & 4 deletions client/llb/llbbuild/llbbuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ func (b *build) Validate(context.Context, *llb.Constraints) error {
}

func (b *build) Marshal(ctx context.Context, c *llb.Constraints) (digest.Digest, []byte, *pb.OpMetadata, []*llb.SourceLocation, error) {
if b.Cached(c) {
return b.Load()
if dgst, dt, md, srcs, err := b.Load(c); err == nil {
return dgst, dt, md, srcs, nil
}

pbo := &pb.BuildOp{
Builder: int64(pb.LLBBuilder),
Inputs: map[string]*pb.BuildInput{
Expand Down Expand Up @@ -84,8 +85,7 @@ func (b *build) Marshal(ctx context.Context, c *llb.Constraints) (digest.Digest,
if err != nil {
return "", nil, nil, nil, err
}
b.Store(dt, md, b.constraints.SourceLocations, c)
return b.Load()
return b.Store(dt, md, b.constraints.SourceLocations, c)
}

func (b *build) Output() llb.Output {
Expand Down
44 changes: 29 additions & 15 deletions client/llb/marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package llb

import (
"io"
"sync"

cerrdefs "github.com/containerd/errdefs"
"github.com/containerd/platforms"
"github.com/moby/buildkit/solver/pb"
digest "github.com/opencontainers/go-digest"
Expand Down Expand Up @@ -115,25 +117,37 @@ func MarshalConstraints(base, override *Constraints) (*pb.Op, *pb.OpMetadata) {
}

type MarshalCache struct {
digest digest.Digest
dt []byte
md *pb.OpMetadata
srcs []*SourceLocation
constraints *Constraints
cache sync.Map
}

func (mc *MarshalCache) Cached(c *Constraints) bool {
return mc.dt != nil && mc.constraints == c
func (mc *MarshalCache) Load(c *Constraints) (digest.Digest, []byte, *pb.OpMetadata, []*SourceLocation, error) {
v, ok := mc.cache.Load(c)
if !ok {
return "", nil, nil, nil, cerrdefs.ErrNotFound
}

res := v.(*marshalCacheResult)
return res.digest, res.dt, res.md, res.srcs, nil
}

func (mc *MarshalCache) Store(dt []byte, md *pb.OpMetadata, srcs []*SourceLocation, c *Constraints) (digest.Digest, []byte, *pb.OpMetadata, []*SourceLocation, error) {
res := &marshalCacheResult{
digest: digest.FromBytes(dt),
dt: dt,
md: md,
srcs: srcs,
}
mc.cache.Store(c, res)
return res.digest, res.dt, res.md, res.srcs, nil
}

func (mc *MarshalCache) Load() (digest.Digest, []byte, *pb.OpMetadata, []*SourceLocation, error) {
return mc.digest, mc.dt, mc.md, mc.srcs, nil
type marshalCacheResult struct {
digest digest.Digest
dt []byte
md *pb.OpMetadata
srcs []*SourceLocation
}

func (mc *MarshalCache) Store(dt []byte, md *pb.OpMetadata, srcs []*SourceLocation, c *Constraints) {
mc.digest = digest.FromBytes(dt)
mc.dt = dt
mc.md = md
mc.constraints = c
mc.srcs = srcs
func deterministicMarshal[Message proto.Message](m Message) ([]byte, error) {
return proto.MarshalOptions{Deterministic: true}.Marshal(m)
}
11 changes: 5 additions & 6 deletions client/llb/merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"github.com/moby/buildkit/solver/pb"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"google.golang.org/protobuf/proto"
)

type MergeOp struct {
Expand All @@ -33,9 +32,10 @@ func (m *MergeOp) Validate(ctx context.Context, constraints *Constraints) error
}

func (m *MergeOp) Marshal(ctx context.Context, constraints *Constraints) (digest.Digest, []byte, *pb.OpMetadata, []*SourceLocation, error) {
if m.Cached(constraints) {
return m.Load()
if dgst, dt, md, srcs, err := m.Load(constraints); err == nil {
return dgst, dt, md, srcs, nil
}

if err := m.Validate(ctx, constraints); err != nil {
return "", nil, nil, nil, err
}
Expand All @@ -54,13 +54,12 @@ func (m *MergeOp) Marshal(ctx context.Context, constraints *Constraints) (digest
}
pop.Op = &pb.Op_Merge{Merge: op}

dt, err := proto.Marshal(pop)
dt, err := deterministicMarshal(pop)
if err != nil {
return "", nil, nil, nil, err
}

m.Store(dt, md, m.constraints.SourceLocations, constraints)
return m.Load()
return m.Store(dt, md, m.constraints.SourceLocations, constraints)
}

func (m *MergeOp) Output() Output {
Expand Down
11 changes: 5 additions & 6 deletions client/llb/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"github.com/moby/buildkit/util/sshutil"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
protobuf "google.golang.org/protobuf/proto"
)

type SourceOp struct {
Expand Down Expand Up @@ -50,9 +49,10 @@ func (s *SourceOp) Validate(ctx context.Context, c *Constraints) error {
}

func (s *SourceOp) Marshal(ctx context.Context, constraints *Constraints) (digest.Digest, []byte, *pb.OpMetadata, []*SourceLocation, error) {
if s.Cached(constraints) {
return s.Load()
if dgst, dt, md, srcs, err := s.Load(constraints); err == nil {
return dgst, dt, md, srcs, nil
}

if err := s.Validate(ctx, constraints); err != nil {
return "", nil, nil, nil, err
}
Expand All @@ -77,13 +77,12 @@ func (s *SourceOp) Marshal(ctx context.Context, constraints *Constraints) (diges
proto.Platform = nil
}

dt, err := protobuf.Marshal(proto)
dt, err := deterministicMarshal(proto)
if err != nil {
return "", nil, nil, nil, err
}

s.Store(dt, md, s.constraints.SourceLocations, constraints)
return s.Load()
return s.Store(dt, md, s.constraints.SourceLocations, constraints)
}

func (s *SourceOp) Output() Output {
Expand Down
8 changes: 6 additions & 2 deletions solver/llbsolver/vertex.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ func recomputeDigests(ctx context.Context, all map[digest.Digest]*pb.Op, visited
return dgst, nil
}

dt, err := proto.Marshal(op)
dt, err := deterministicMarshal(op)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -263,7 +263,7 @@ func loadLLB(ctx context.Context, def *pb.Definition, polEngine SourcePolicyEval
return solver.Edge{}, errors.Wrap(err, "error evaluating the source policy")
}
if mutated {
dtMutated, err := proto.Marshal(&op)
dtMutated, err := deterministicMarshal(&op)
if err != nil {
return solver.Edge{}, err
}
Expand Down Expand Up @@ -397,3 +397,7 @@ func fileOpName(actions []*pb.FileAction) string {

return strings.Join(names, ", ")
}

func deterministicMarshal[Message proto.Message](m Message) ([]byte, error) {
return proto.MarshalOptions{Deterministic: true}.Marshal(m)
}

0 comments on commit 8445ccf

Please sign in to comment.