diff options
| author | Ophestra <cat@gensokyo.uk> | 2026-01-09 01:51:39 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2026-01-09 05:20:34 +0900 |
| commit | f7124667145d1f7c614d9fc644bc07bb6174454a (patch) | |
| tree | 9585573da6d016a27ce7fd066b795f611d1ce877 /internal/pkg/exec.go | |
| parent | f2430b5f5ef7ac0361d1c4976b7ec7bebaa15f63 (diff) | |
internal/pkg: move dependency flooding to cache
This imposes a hard upper limit to concurrency during dependency satisfaction and moves all dependency-related code out of individual implementations of Artifact. This change also includes ctx and msg as part of Cache.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/pkg/exec.go')
| -rw-r--r-- | internal/pkg/exec.go | 142 |
1 files changed, 27 insertions, 115 deletions
diff --git a/internal/pkg/exec.go b/internal/pkg/exec.go index e3b6b437..db0cf9f0 100644 --- a/internal/pkg/exec.go +++ b/internal/pkg/exec.go @@ -5,7 +5,6 @@ import ( "context" "errors" "os" - "runtime" "slices" "strconv" "syscall" @@ -15,7 +14,6 @@ import ( "hakurei.app/container/check" "hakurei.app/container/fhs" "hakurei.app/container/std" - "hakurei.app/message" ) // AbsWork is the container pathname [CureContext.GetWorkDir] is mounted on. @@ -30,7 +28,7 @@ type ExecPath struct { // If there are multiple entries or W is true, P is set up as an overlay // mount, and entries of A must not implement [File]. A []Artifact - // Whether to make the mount point writable via an invisible tmpfs upperdir. + // Whether to make the mount point writable via the temp directory. W bool } @@ -50,17 +48,8 @@ func MustPath(pathname string, writable bool, a ...Artifact) ExecPath { // Methods of execArtifact does not modify any struct field or underlying arrays // referred to by slices. type execArtifact struct { - // Caller-supplied context. - ctx context.Context // Caller-supplied inner mount points. paths []ExecPath - // Caller-supplied logging facility, passed through to [container] and used - // internally to produce verbose output. - msg message.Msg - - // Number of [Artifact] to concurrently cure. A value of 0 or lower is - // equivalent to the value returned by [runtime.NumCPU]. - cures int // Passed through to [container.Params]. dir *check.Absolute @@ -93,10 +82,10 @@ func (a *execNetArtifact) Params() []byte { return slices.Concat(a.checksum[:], a.execArtifact.Params()) } -// Cure cures the [Artifact] by curing all its dependencies then running the -// container described by the caller. The container retains host networking. -func (a *execNetArtifact) Cure(c *CureContext) error { - return a.cure(c, true) +// Cure cures the [Artifact] in the container described by the caller. The +// container retains host networking. +func (a *execNetArtifact) Cure(f *FContext) error { + return a.cure(f, true) } // NewExec returns a new [Artifact] bounded by ctx, it cures all [Artifact] @@ -114,13 +103,7 @@ func (a *execNetArtifact) Cure(c *CureContext) error { // // If checksum is non-nil, the resulting [Artifact] implements [KnownChecksum] // and its container runs in the host net namespace. -// -// A cures value of 0 or lower is equivalent to the value returned by -// [runtime.NumCPU]. func NewExec( - ctx context.Context, - msg message.Msg, - cures int, checksum *Checksum, dir *check.Absolute, @@ -130,7 +113,7 @@ func NewExec( paths ...ExecPath, ) Artifact { - a := execArtifact{ctx, paths, msg, cures, dir, env, path, args} + a := execArtifact{paths, dir, env, path, args} if checksum == nil { return &a } @@ -186,10 +169,9 @@ func (a *execArtifact) Dependencies() []Artifact { return slices.Concat(artifacts...) } -// Cure cures the [Artifact] by curing all its dependencies then running the -// container described by the caller. -func (a *execArtifact) Cure(c *CureContext) (err error) { - return a.cure(c, false) +// Cure cures the [Artifact] in the container described by the caller. +func (a *execArtifact) Cure(f *FContext) (err error) { + return a.cure(f, false) } const ( @@ -199,20 +181,8 @@ const ( // cure is like Cure but allows optional host net namespace. This is used for // the [KnownChecksum] variant where networking is allowed. -func (a *execArtifact) cure(c *CureContext, hostNet bool) (err error) { - cures := a.cures - if cures < 1 { - cures = runtime.NumCPU() - } - +func (a *execArtifact) cure(f *FContext, hostNet bool) (err error) { overlayWorkIndex := -1 - type curePath struct { - // Copied from ExecPath.P. - dst *check.Absolute - // Cured from ExecPath.A. - src []*check.Absolute - } - paths := make([]curePath, len(a.paths)) for i, p := range a.paths { if p.P == nil || len(p.A) == 0 { return os.ErrInvalid @@ -220,8 +190,6 @@ func (a *execArtifact) cure(c *CureContext, hostNet bool) (err error) { if p.P.Is(AbsWork) { overlayWorkIndex = i } - paths[i].dst = p.P - paths[i].src = make([]*check.Absolute, len(p.A)) } var artifactCount int @@ -229,71 +197,10 @@ func (a *execArtifact) cure(c *CureContext, hostNet bool) (err error) { artifactCount += len(p.A) } - if len(paths) > 0 { - type cureArtifact struct { - // Index of pending Artifact in paths. - index [2]int - // Pending artifact. - a Artifact - } - ac := make(chan cureArtifact, artifactCount) - for i, p := range a.paths { - for j, d := range p.A { - ac <- cureArtifact{[2]int{i, j}, d} - } - } - - type cureRes struct { - // Index of result in paths. - index [2]int - // Cured pathname. - pathname *check.Absolute - // Error returned by c. - err error - } - res := make(chan cureRes) - - for i := 0; i < cures; i++ { - go func() { - for d := range ac { - // computing and encoding identifier is expensive - if a.msg.IsVerbose() { - a.msg.Verbosef("curing %s...", Encode(Ident(d.a))) - } - - var cr cureRes - cr.index = d.index - cr.pathname, _, cr.err = c.Cure(d.a) - res <- cr - } - }() - } - - var count int - errs := make([]error, 0, artifactCount) - for cr := range res { - count++ - - if cr.err != nil { - errs = append(errs, cr.err) - } else { - paths[cr.index[0]].src[cr.index[1]] = cr.pathname - } - - if count == artifactCount { - break - } - } - close(ac) - if err = errors.Join(errs...); err != nil { - return - } - } - - ctx, cancel := context.WithCancel(a.ctx) + ctx, cancel := context.WithCancel(f.Unwrap()) defer cancel() - z := container.New(ctx, a.msg) + z := container.New(ctx, f.GetMessage()) z.WaitDelay = execWaitDelay z.SeccompPresets |= std.PresetStrict z.ParentPerm = 0700 @@ -303,15 +210,20 @@ func (a *execArtifact) cure(c *CureContext, hostNet bool) (err error) { z.Hostname = "cure-net" } z.Uid, z.Gid = (1<<10)-1, (1<<10)-1 - if a.msg.IsVerbose() { + if f.GetMessage().IsVerbose() { z.Stdout, z.Stderr = os.Stdout, os.Stderr } z.Dir, z.Env, z.Path, z.Args = a.dir, a.env, a.path, a.args - z.Grow(len(paths) + 4) + z.Grow(len(a.paths) + 4) + + temp, work := f.GetTempDir(), f.GetWorkDir() + for i, b := range a.paths { + layers := make([]*check.Absolute, len(b.A)) + for j, d := range b.A { + layers[j] = f.Pathname(d) + } - temp, work := c.GetTempDir(), c.GetWorkDir() - for i, b := range paths { if i == overlayWorkIndex { if err = os.MkdirAll(work.String(), 0700); err != nil { return @@ -324,7 +236,7 @@ func (a *execArtifact) cure(c *CureContext, hostNet bool) (err error) { AbsWork, work, tempWork, - b.src..., + layers..., ) continue } @@ -341,11 +253,11 @@ func (a *execArtifact) cure(c *CureContext, hostNet bool) (err error) { if err = os.MkdirAll(tempWork.String(), 0700); err != nil { return } - z.Overlay(b.dst, tempUpper, tempWork, b.src...) - } else if len(b.src) == 1 { - z.Bind(b.src[0], b.dst, 0) + z.Overlay(b.P, tempUpper, tempWork, layers...) + } else if len(layers) == 1 { + z.Bind(layers[0], b.P, 0) } else { - z.OverlayReadonly(b.dst, b.src...) + z.OverlayReadonly(b.P, layers...) } } if overlayWorkIndex < 0 { @@ -356,7 +268,7 @@ func (a *execArtifact) cure(c *CureContext, hostNet bool) (err error) { ) } z.Bind( - c.GetTempDir(), + f.GetTempDir(), fhs.AbsTmp, std.BindWritable|std.BindEnsure, ) |
