Skip to content

Commit

Permalink
solver: first pass of instruction cache
Browse files Browse the repository at this point in the history
Signed-off-by: Tonis Tiigi <[email protected]>
  • Loading branch information
tonistiigi committed Jul 7, 2017
1 parent c9e2493 commit 1fd611c
Show file tree
Hide file tree
Showing 14 changed files with 509 additions and 215 deletions.
111 changes: 111 additions & 0 deletions cache/instructioncache/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package instructioncache

import (
"github.com/boltdb/bolt"
"github.com/moby/buildkit/cache"
"github.com/moby/buildkit/cache/metadata"
"github.com/pkg/errors"
"golang.org/x/net/context"
)

const cacheKey = "buildkit.instructioncache"

type cacheGroup struct {
Snapshots []string `json:"snapshots"`
}

type LocalStore struct {
MetadataStore *metadata.Store
Cache cache.Accessor
}

func (ls *LocalStore) Set(key string, refsAny []interface{}) error {
refs, err := toReferenceArray(refsAny)
if err != nil {
return err
}
cg := cacheGroup{}
for _, r := range refs {
cg.Snapshots = append(cg.Snapshots, r.ID())
}
v, err := metadata.NewValue(cg)
if err != nil {
return err
}
v.Index = index(key)
for _, r := range refs {
si, _ := ls.MetadataStore.Get(r.ID())
if err := si.Update(func(b *bolt.Bucket) error { // TODO: should share transaction
return si.SetValue(b, index(key), *v)
}); err != nil {
return err
}
}
return nil
}

func (ls *LocalStore) Lookup(ctx context.Context, key string) ([]interface{}, error) {
snaps, err := ls.MetadataStore.Search(index(key))
if err != nil {
return nil, err
}
refs := make([]cache.ImmutableRef, 0)
var retErr error
for _, s := range snaps {
retErr = nil
for _, r := range refs {
r.Release(context.TODO())
}
refs = nil

v := s.Get(index(key))
if v != nil {
var cg cacheGroup
if err = v.Unmarshal(&cg); err != nil {
retErr = err
continue
}
for _, id := range cg.Snapshots {
r, err := ls.Cache.Get(ctx, id)
if err != nil {
retErr = err
continue
}
refs = append(refs, r)
}
retErr = nil
break
}
}
if retErr != nil {
for _, r := range refs {
r.Release(context.TODO())
}
refs = nil
}
return toAny(refs), retErr
}

func index(k string) string {
return cacheKey + "::" + k
}

func toReferenceArray(in []interface{}) ([]cache.ImmutableRef, error) {
out := make([]cache.ImmutableRef, 0, len(in))
for _, i := range in {
r, ok := i.(cache.ImmutableRef)
if !ok {
return nil, errors.Errorf("invalid reference")
}
out = append(out, r)
}
return out, nil
}

func toAny(in []cache.ImmutableRef) []interface{} {
out := make([]interface{}, 0, len(in))
for _, i := range in {
out = append(out, i)
}
return out
}
8 changes: 8 additions & 0 deletions cache/metadata/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,14 @@ func (s *StorageItem) Update(fn func(b *bolt.Bucket) error) error {
return s.storage.Update(s.id, fn)
}

func (s *StorageItem) Keys() []string {
keys := make([]string, 0, len(s.values))
for k := range s.values {
keys = append(keys, k)
}
return keys
}

func (s *StorageItem) Get(k string) *Value {
return s.values[k]
}
Expand Down
1 change: 1 addition & 0 deletions client/solve.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ func (c *Client) Solve(ctx context.Context, r io.Reader, statusChan chan *SolveS
Started: v.Started,
Completed: v.Completed,
Error: v.Error,
Cached: v.Cached,
})
}
for _, v := range resp.Statuses {
Expand Down
17 changes: 10 additions & 7 deletions control/control.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ import (
)

type Opt struct {
Snapshotter snapshot.Snapshotter
CacheManager cache.Manager
Worker worker.Worker
SourceManager *source.Manager
Snapshotter snapshot.Snapshotter
CacheManager cache.Manager
Worker worker.Worker
SourceManager *source.Manager
InstructionCache solver.InstructionCache
}

type Controller struct { // TODO: ControlService
Expand All @@ -30,9 +31,10 @@ func NewController(opt Opt) (*Controller, error) {
c := &Controller{
opt: opt,
solver: solver.NewLLBSolver(solver.LLBOpt{
SourceManager: opt.SourceManager,
CacheManager: opt.CacheManager,
Worker: opt.Worker,
SourceManager: opt.SourceManager,
CacheManager: opt.CacheManager,
Worker: opt.Worker,
InstructionCache: opt.InstructionCache,
}),
}
return c, nil
Expand Down Expand Up @@ -98,6 +100,7 @@ func (c *Controller) Status(req *controlapi.StatusRequest, stream controlapi.Con
Started: v.Started,
Completed: v.Completed,
Error: v.Error,
Cached: v.Cached,
})
}
for _, v := range ss.Statuses {
Expand Down
13 changes: 10 additions & 3 deletions control/control_default.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/containerd/containerd/rootfs"
ctdsnapshot "github.com/containerd/containerd/snapshot"
"github.com/moby/buildkit/cache"
"github.com/moby/buildkit/cache/instructioncache"
"github.com/moby/buildkit/cache/metadata"
"github.com/moby/buildkit/snapshot/blobmapping"
"github.com/moby/buildkit/source"
Expand Down Expand Up @@ -44,6 +45,11 @@ func defaultControllerOpts(root string, pd pullDeps) (*Opt, error) {
return nil, err
}

ic := &instructioncache.LocalStore{
MetadataStore: md,
Cache: cm,
}

sm, err := source.NewManager()
if err != nil {
return nil, err
Expand All @@ -62,8 +68,9 @@ func defaultControllerOpts(root string, pd pullDeps) (*Opt, error) {
sm.Register(is)

return &Opt{
Snapshotter: snapshotter,
CacheManager: cm,
SourceManager: sm,
Snapshotter: snapshotter,
CacheManager: cm,
SourceManager: sm,
InstructionCache: ic,
}, nil
}
28 changes: 22 additions & 6 deletions solver/exec.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package solver

import (
"encoding/json"
"io"
"os"

Expand All @@ -10,24 +11,39 @@ import (
"github.com/moby/buildkit/solver/pb"
"github.com/moby/buildkit/util/progress"
"github.com/moby/buildkit/worker"
digest "github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"golang.org/x/net/context"
)

type execOp struct {
op *pb.Op_Exec
op *pb.ExecOp
cm cache.Manager
w worker.Worker
}

func newExecOp(op *pb.Op_Exec, cm cache.Manager, w worker.Worker) (Op, error) {
return &execOp{
op: op,
op: op.Exec,
cm: cm,
w: w,
}, nil
}

func (e *execOp) CacheKey(ctx context.Context, inputs []string) (string, error) {
dt, err := json.Marshal(struct {
Inputs []string
Exec *pb.ExecOp
}{
Inputs: inputs,
Exec: e.op,
})
if err != nil {
return "", err
}
return digest.FromBytes(dt).String(), nil
}

func (e *execOp) Run(ctx context.Context, inputs []Reference) ([]Reference, error) {
mounts := make(map[string]cache.Mountable)

Expand All @@ -44,7 +60,7 @@ func (e *execOp) Run(ctx context.Context, inputs []Reference) ([]Reference, erro
}
}()

for _, m := range e.op.Exec.Mounts {
for _, m := range e.op.Mounts {
var mountable cache.Mountable
if int(m.Input) > len(inputs) {
return nil, errors.Errorf("missing input %d", m.Input)
Expand Down Expand Up @@ -72,9 +88,9 @@ func (e *execOp) Run(ctx context.Context, inputs []Reference) ([]Reference, erro
}

meta := worker.Meta{
Args: e.op.Exec.Meta.Args,
Env: e.op.Exec.Meta.Env,
Cwd: e.op.Exec.Meta.Cwd,
Args: e.op.Meta.Args,
Env: e.op.Meta.Env,
Cwd: e.op.Meta.Cwd,
}

stdout := newStreamWriter(ctx, 1)
Expand Down
Loading

0 comments on commit 1fd611c

Please sign in to comment.