Refactor to file action indexed outputs

Signed-off-by: Edgar Lee <edgarl@netflix.com>
v0.8
Edgar Lee 2020-10-28 18:16:44 -07:00
parent 2d23d0cc43
commit 7e1dc9bec1
8 changed files with 59 additions and 34 deletions

View File

@ -1279,8 +1279,8 @@ func testClientGatewayFileActionError(t *testing.T, sb integration.Sandbox) {
require.True(t, errors.As(solveErr, &se)) require.True(t, errors.As(solveErr, &se))
// There are no inputs because rootfs is scratch. // There are no inputs because rootfs is scratch.
require.Len(t, se.Solve.InputIDs, 0) require.Len(t, se.Solve.InputIDs, 0)
// There is one output for the mutable mount used for the fileop actions. // There is one output for every action (3).
require.Len(t, se.Solve.OutputIDs, 1) require.Len(t, se.Solve.OutputIDs, 3)
op, ok := se.Solve.Op.Op.(*pb.Op_File) op, ok := se.Solve.Op.Op.(*pb.Op_File)
require.True(t, ok) require.True(t, ok)
@ -1289,10 +1289,10 @@ func testClientGatewayFileActionError(t *testing.T, sb integration.Sandbox) {
require.True(t, ok) require.True(t, ok)
idx := subject.File.Index idx := subject.File.Index
require.Greater(t, len(op.File.Actions), int(idx)) require.Less(t, int(idx), len(op.File.Actions))
// Verify the index is pointing to the action that failed. // Verify the index is pointing to the action that failed.
action := op.File.Actions[subject.File.Index] action := op.File.Actions[idx]
mkfile, ok := action.Action.(*pb.FileAction_Mkfile) mkfile, ok := action.Action.(*pb.FileAction_Mkfile)
require.True(t, ok) require.True(t, ok)
require.Equal(t, mkfile.Mkfile.Path, "/notfound/foo") require.Equal(t, mkfile.Mkfile.Path, "/notfound/foo")
@ -1317,7 +1317,7 @@ func testClientGatewayFileActionError(t *testing.T, sb integration.Sandbox) {
}, { }, {
Dest: "/problem", Dest: "/problem",
MountType: pb.MountType_BIND, MountType: pb.MountType_BIND,
ResultID: se.Solve.OutputIDs[0], ResultID: se.Solve.OutputIDs[idx],
}}, }},
}) })
require.NoError(t, err) require.NoError(t, err)

View File

@ -158,6 +158,9 @@ func (c *bridgeClient) registerResultIDs(results ...solver.Result) (ids []string
ids = make([]string, len(results)) ids = make([]string, len(results))
for i, res := range results { for i, res := range results {
if res == nil {
continue
}
workerRef, ok := res.Sys().(*worker.WorkerRef) workerRef, ok := res.Sys().(*worker.WorkerRef)
if !ok { if !ok {
return ids, errors.Errorf("unexpected type for result, got %T", res.Sys()) return ids, errors.Errorf("unexpected type for result, got %T", res.Sys())

View File

@ -533,6 +533,9 @@ func (lbf *llbBridgeForwarder) registerResultIDs(results ...solver.Result) (ids
ids = make([]string, len(results)) ids = make([]string, len(results))
for i, res := range results { for i, res := range results {
if res == nil {
continue
}
workerRef, ok := res.Sys().(*worker.WorkerRef) workerRef, ok := res.Sys().(*worker.WorkerRef)
if !ok { if !ok {
return ids, errors.Errorf("unexpected type for result, got %T", res.Sys()) return ids, errors.Errorf("unexpected type for result, got %T", res.Sys())

View File

@ -29,7 +29,7 @@ func (rm *RefManager) Prepare(ctx context.Context, ref fileoptypes.Ref, readonly
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &Mount{m: m}, nil return &Mount{m: m, readonly: readonly}, nil
} }
mr, err := rm.cm.New(ctx, ir, g, cache.WithDescription("fileop target"), cache.CachePolicyRetain) mr, err := rm.cm.New(ctx, ir, g, cache.WithDescription("fileop target"), cache.CachePolicyRetain)
@ -40,7 +40,7 @@ func (rm *RefManager) Prepare(ctx context.Context, ref fileoptypes.Ref, readonly
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &Mount{m: m, mr: mr}, nil return &Mount{m: m, mr: mr, readonly: readonly}, nil
} }
func (rm *RefManager) Commit(ctx context.Context, mount fileoptypes.Mount) (fileoptypes.Ref, error) { func (rm *RefManager) Commit(ctx context.Context, mount fileoptypes.Mount) (fileoptypes.Ref, error) {
@ -58,8 +58,9 @@ func (rm *RefManager) Commit(ctx context.Context, mount fileoptypes.Mount) (file
} }
type Mount struct { type Mount struct {
m snapshot.Mountable m snapshot.Mountable
mr cache.MutableRef mr cache.MutableRef
readonly bool
} }
func (m *Mount) Release(ctx context.Context) error { func (m *Mount) Release(ctx context.Context) error {
@ -69,3 +70,7 @@ func (m *Mount) Release(ctx context.Context) error {
return nil return nil
} }
func (m *Mount) IsFileOpMount() {} func (m *Mount) IsFileOpMount() {}
func (m *Mount) Readonly() bool {
return m.readonly
}

View File

@ -160,7 +160,6 @@ func (f *fileOp) Exec(ctx context.Context, g session.Group, inputs []solver.Resu
outs, err := f.solver.Solve(ctx, inpRefs, f.op.Actions, g) outs, err := f.solver.Solve(ctx, inpRefs, f.op.Actions, g)
if err != nil { if err != nil {
return nil, err return nil, err
// return nil, errdefs.WithExecError(err, inputs, nil)
} }
outResults := make([]solver.Result, 0, len(outs)) outResults := make([]solver.Result, 0, len(outs))
@ -347,7 +346,7 @@ func (s *FileOpSolver) Solve(ctx context.Context, inputs []fileoptypes.Ref, acti
} }
inp, err := s.getInput(ctx, idx, inputs, actions, g) inp, err := s.getInput(ctx, idx, inputs, actions, g)
if err != nil { if err != nil {
return errdefs.WithFileActionError(err, idx) return errdefs.WithFileActionError(err, idx-len(inputs))
} }
outs[i] = inp.ref outs[i] = inp.ref
return nil return nil
@ -405,32 +404,42 @@ func (s *FileOpSolver) getInput(ctx context.Context, idx int, inputs []fileoptyp
var inpMount, inpMountSecondary fileoptypes.Mount var inpMount, inpMountSecondary fileoptypes.Mount
var toRelease []fileoptypes.Mount var toRelease []fileoptypes.Mount
var inpMountPrepared bool action := actions[idx-len(inputs)]
defer func() { defer func() {
if err != nil && inpMount != nil {
inputRes := make([]solver.Result, len(inputs))
for i, input := range inputs {
inputRes[i] = worker.NewWorkerRefResult(input.(cache.ImmutableRef), s.w)
}
outputRes := make([]solver.Result, len(actions))
// Commit the mutable for the primary input of the failed action.
if !inpMount.Readonly() {
ref, cerr := s.r.Commit(ctx, inpMount)
if cerr == nil {
outputRes[idx-len(inputs)] = worker.NewWorkerRefResult(ref.(cache.ImmutableRef), s.w)
}
inpMount.Release(context.TODO())
}
// If the action has a secondary input, commit it and set the ref on
// the output results.
if inpMountSecondary != nil && !inpMountSecondary.Readonly() {
ref2, cerr := s.r.Commit(ctx, inpMountSecondary)
if cerr == nil {
outputRes[int(action.SecondaryInput)-len(inputs)] = worker.NewWorkerRefResult(ref2.(cache.ImmutableRef), s.w)
}
}
err = errdefs.WithExecError(err, inputRes, outputRes)
}
for _, m := range toRelease { for _, m := range toRelease {
m.Release(context.TODO()) m.Release(context.TODO())
} }
if err != nil && inpMount != nil {
if inpMountPrepared {
inpMount.Release(context.TODO())
}
var (
inputRes []solver.Result
outputRes []solver.Result
)
for _, input := range inputs {
inputRes = append(inputRes, worker.NewWorkerRefResult(input.(cache.ImmutableRef), s.w))
}
ref, cerr := s.r.Commit(ctx, inpMount)
if cerr == nil {
outputRes = append(outputRes, worker.NewWorkerRefResult(ref.(cache.ImmutableRef), s.w))
}
err = errdefs.WithExecError(err, inputRes, outputRes)
}
}() }()
action := actions[idx-len(inputs)]
loadInput := func(ctx context.Context) func() error { loadInput := func(ctx context.Context) func() error {
return func() error { return func() error {
inp, err := s.getInput(ctx, int(action.Input), inputs, actions, g) inp, err := s.getInput(ctx, int(action.Input), inputs, actions, g)
@ -443,7 +452,6 @@ func (s *FileOpSolver) getInput(ctx context.Context, idx int, inputs []fileoptyp
return err return err
} }
inpMount = m inpMount = m
inpMountPrepared = true
return nil return nil
} }
inpMount = inp.mount inpMount = inp.mount
@ -542,7 +550,6 @@ func (s *FileOpSolver) getInput(ctx context.Context, idx int, inputs []fileoptyp
return nil, err return nil, err
} }
inpMount = m inpMount = m
inpMountPrepared = true
} }
switch a := action.Action.(type) { switch a := action.Action.(type) {

View File

@ -581,6 +581,7 @@ type testMount struct {
callback func() callback func()
unmounted bool unmounted bool
active *testFileRef active *testFileRef
readonly bool
} }
func (tm *testMount) addUser(user, group fileoptypes.Mount) { func (tm *testMount) addUser(user, group fileoptypes.Mount) {
@ -617,6 +618,10 @@ func (tm *testMount) Release(ctx context.Context) error {
return nil return nil
} }
func (tm *testMount) Readonly() bool {
return tm.readonly
}
type testFileBackend struct { type testFileBackend struct {
} }
@ -674,7 +679,7 @@ func (b *testFileRefBackend) Prepare(ctx context.Context, ref fileoptypes.Ref, r
rr := ref.(*testFileRef) rr := ref.(*testFileRef)
m := rr.mount m := rr.mount
if m == nil { if m == nil {
m = &testMount{b: b, id: "mount-" + rr.id, callback: rr.callback} m = &testMount{b: b, id: "mount-" + rr.id, callback: rr.callback, readonly: readonly}
} }
m.initID = m.id m.initID = m.id
m.active = active m.active = active

View File

@ -14,6 +14,7 @@ type Ref interface {
type Mount interface { type Mount interface {
IsFileOpMount() IsFileOpMount()
Release(context.Context) error Release(context.Context) error
Readonly() bool
} }
type Backend interface { type Backend interface {

View File

@ -144,6 +144,7 @@ func (s *Solver) Solve(ctx context.Context, id string, sessionID string, req fro
eg.Go(func() error { eg.Go(func() error {
_, err := ref.Result(ctx2) _, err := ref.Result(ctx2)
if err != nil { if err != nil {
// Also release any results referenced by exec errors.
var ee *errdefs.ExecError var ee *errdefs.ExecError
if errors.As(err, &ee) { if errors.As(err, &ee) {
ee.EachRef(func(res solver.Result) error { ee.EachRef(func(res solver.Result) error {