make sure execerror is released on cancellation

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
v0.8
Tonis Tiigi 2020-11-25 15:13:59 -08:00
parent 372df78cc8
commit df3a9cad23
3 changed files with 47 additions and 3 deletions

View File

@ -659,6 +659,7 @@ func (s *sharedOp) CalcSlowCache(ctx context.Context, index Index, p PreprocessF
case <-ctx.Done():
if strings.Contains(err.Error(), context.Canceled.Error()) {
complete = false
releaseError(err)
err = errors.Wrap(ctx.Err(), err.Error())
}
default:
@ -717,6 +718,7 @@ func (s *sharedOp) CacheMap(ctx context.Context, index int) (resp *cacheMapResp,
case <-ctx.Done():
if strings.Contains(err.Error(), context.Canceled.Error()) {
complete = false
releaseError(err)
err = errors.Wrap(ctx.Err(), err.Error())
}
default:
@ -774,6 +776,7 @@ func (s *sharedOp) Exec(ctx context.Context, inputs []Result) (outputs []Result,
case <-ctx.Done():
if strings.Contains(err.Error(), context.Canceled.Error()) {
complete = false
releaseError(err)
err = errors.Wrap(ctx.Err(), err.Error())
}
default:
@ -911,3 +914,15 @@ func WrapSlowCache(err error, index Index, res Result) error {
}
return &SlowCacheError{Index: index, Result: res, error: err}
}
func releaseError(err error) {
if err == nil {
return
}
if re, ok := err.(interface {
Release() error
}); ok {
re.Release()
}
releaseError(errors.Unwrap(err))
}

View File

@ -167,6 +167,8 @@ func newResultProxy(b *llbBridge, req frontend.SolveRequest) *resultProxy {
rp.errResults = append(rp.errResults, res)
return nil
})
// acquire ownership so ExecError finalizer doesn't attempt to release as well
ee.OwnerBorrowed = true
}
return res, err
}

View File

@ -1,14 +1,19 @@
package errdefs
import (
"context"
"runtime"
"github.com/moby/buildkit/solver"
"github.com/sirupsen/logrus"
)
// ExecError will be returned when an error is encountered when evaluating an op.
type ExecError struct {
error
Inputs []solver.Result
Mounts []solver.Result
Inputs []solver.Result
Mounts []solver.Result
OwnerBorrowed bool
}
func (e *ExecError) Unwrap() error {
@ -35,13 +40,35 @@ func (e *ExecError) EachRef(fn func(solver.Result) error) (err error) {
return err
}
func (e *ExecError) Release() error {
if e.OwnerBorrowed {
return nil
}
err := e.EachRef(func(r solver.Result) error {
r.Release(context.TODO())
return nil
})
e.OwnerBorrowed = true
return err
}
func WithExecError(err error, inputs, mounts []solver.Result) error {
if err == nil {
return nil
}
return &ExecError{
ee := &ExecError{
error: err,
Inputs: inputs,
Mounts: mounts,
}
runtime.SetFinalizer(ee, func(e *ExecError) {
if !e.OwnerBorrowed {
e.EachRef(func(r solver.Result) error {
logrus.Warn("leaked execError detected and released")
r.Release(context.TODO())
return nil
})
}
})
return ee
}