make sure execerror is released on cancellation
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>v0.8
parent
372df78cc8
commit
df3a9cad23
|
@ -659,6 +659,7 @@ func (s *sharedOp) CalcSlowCache(ctx context.Context, index Index, p PreprocessF
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
if strings.Contains(err.Error(), context.Canceled.Error()) {
|
if strings.Contains(err.Error(), context.Canceled.Error()) {
|
||||||
complete = false
|
complete = false
|
||||||
|
releaseError(err)
|
||||||
err = errors.Wrap(ctx.Err(), err.Error())
|
err = errors.Wrap(ctx.Err(), err.Error())
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -717,6 +718,7 @@ func (s *sharedOp) CacheMap(ctx context.Context, index int) (resp *cacheMapResp,
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
if strings.Contains(err.Error(), context.Canceled.Error()) {
|
if strings.Contains(err.Error(), context.Canceled.Error()) {
|
||||||
complete = false
|
complete = false
|
||||||
|
releaseError(err)
|
||||||
err = errors.Wrap(ctx.Err(), err.Error())
|
err = errors.Wrap(ctx.Err(), err.Error())
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -774,6 +776,7 @@ func (s *sharedOp) Exec(ctx context.Context, inputs []Result) (outputs []Result,
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
if strings.Contains(err.Error(), context.Canceled.Error()) {
|
if strings.Contains(err.Error(), context.Canceled.Error()) {
|
||||||
complete = false
|
complete = false
|
||||||
|
releaseError(err)
|
||||||
err = errors.Wrap(ctx.Err(), err.Error())
|
err = errors.Wrap(ctx.Err(), err.Error())
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -911,3 +914,15 @@ func WrapSlowCache(err error, index Index, res Result) error {
|
||||||
}
|
}
|
||||||
return &SlowCacheError{Index: index, Result: res, error: err}
|
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))
|
||||||
|
}
|
||||||
|
|
|
@ -167,6 +167,8 @@ func newResultProxy(b *llbBridge, req frontend.SolveRequest) *resultProxy {
|
||||||
rp.errResults = append(rp.errResults, res)
|
rp.errResults = append(rp.errResults, res)
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
// acquire ownership so ExecError finalizer doesn't attempt to release as well
|
||||||
|
ee.OwnerBorrowed = true
|
||||||
}
|
}
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,19 @@
|
||||||
package errdefs
|
package errdefs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
"github.com/moby/buildkit/solver"
|
"github.com/moby/buildkit/solver"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ExecError will be returned when an error is encountered when evaluating an op.
|
// ExecError will be returned when an error is encountered when evaluating an op.
|
||||||
type ExecError struct {
|
type ExecError struct {
|
||||||
error
|
error
|
||||||
Inputs []solver.Result
|
Inputs []solver.Result
|
||||||
Mounts []solver.Result
|
Mounts []solver.Result
|
||||||
|
OwnerBorrowed bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *ExecError) Unwrap() error {
|
func (e *ExecError) Unwrap() error {
|
||||||
|
@ -35,13 +40,35 @@ func (e *ExecError) EachRef(fn func(solver.Result) error) (err error) {
|
||||||
return err
|
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 {
|
func WithExecError(err error, inputs, mounts []solver.Result) error {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return &ExecError{
|
ee := &ExecError{
|
||||||
error: err,
|
error: err,
|
||||||
Inputs: inputs,
|
Inputs: inputs,
|
||||||
Mounts: mounts,
|
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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue