diff options
Diffstat (limited to 'internal/pkg/pkg.go')
| -rw-r--r-- | internal/pkg/pkg.go | 105 |
1 files changed, 92 insertions, 13 deletions
diff --git a/internal/pkg/pkg.go b/internal/pkg/pkg.go index 78e62e85..aadfa308 100644 --- a/internal/pkg/pkg.go +++ b/internal/pkg/pkg.go @@ -368,7 +368,7 @@ var _ error = InvalidLookupError{} // GetArtifact returns the identifier pathname and checksum of an [Artifact]. // Calling Pathname with an [Artifact] not part of the slice returned by -// [Artifact.Dependencies] panics. +// [Artifact.Inputs] panics. func (f *FContext) GetArtifact(a Artifact) ( pathname *check.Absolute, checksum unique.Handle[Checksum], @@ -678,6 +678,10 @@ const ( // CIgnoreSubstitutes disables content-based dependency substitution. CIgnoreSubstitutes + + // CExternShallow arranges for only non-flood inputs to be fetched when + // curing an [Artifact] available via the external cache. + CExternShallow ) // toplevel holds [context.WithCancel] over caller-supplied context, where all @@ -1914,25 +1918,57 @@ func (c *Cache) tryExtern(ctx context.Context, id unique.Handle[ID]) ( } // cureMany concurrently collects outcome of multiple [Artifact]. -func (c *Cache) cureMany(inputs []Artifact, r map[Artifact]cureRes) error { +func (c *Cache) cureMany( + inputs []Artifact, + r map[Artifact]cureRes, + shallow bool, +) ([]bool, error) { var wg sync.WaitGroup wg.Add(len(inputs)) + var mask []bool res := make([]cureRes, len(inputs)) errs := make(DependencyCureError, 0, len(inputs)) var errsMu sync.Mutex + if shallow { + mask = make([]bool, len(inputs)) + } for i, d := range inputs { + if shallow { + if _, ok := d.(FloodArtifact); ok { + mask[i] = true + wg.Done() + continue + } + + if kc, ok := d.(KnownChecksum); ok { + res[i].checksum = unique.Make(kc.Checksum()) + wg.Done() + continue + } + } pending := pendingArtifactDep{d, &res[i], &errs, &errsMu, &wg} go pending.cure(c) } wg.Wait() if len(errs) > 0 { - return &errs + return mask, &errs } for i, p := range res { + if shallow && mask[i] { + continue + } r[inputs[i]] = p } - return nil + return mask, nil +} + +// HangingInputError describes an input of an [Artifact] on a sparse cache +// without an outcome available locally or via [External]. +type HangingInputError unique.Handle[ID] + +func (e HangingInputError) Error() string { + return Encode(unique.Handle[ID](e).Value()) + " is unavailable" } // cure implements Cure without acquiring a read lock on abortMu. cure must not @@ -2193,12 +2229,62 @@ func (c *Cache) cure(a Artifact, curesExempt bool) ( break case FloodArtifact: + var externChecksum unique.Handle[Checksum] + if externChecksum, err = c.tryExtern(ctx, id); err != nil { + if c.msg.IsVerbose() { + c.msg.Verbosef("extern %s: %v", reportName(ca, id), err) + } + return + } + extern := externChecksum != zeroChecksum + shallow := extern && c.flags&CExternShallow != 0 + inputs := a.Inputs() f := FContext{t, make(map[Artifact]cureRes, len(inputs))} - if err = c.cureMany(inputs, f.inputs); err != nil { + var mask []bool + if mask, err = c.cureMany(inputs, f.inputs, shallow); err != nil { return } + if shallow { + for i, d := range inputs { + if !mask[i] { + continue + } + + if kc, ok := d.(KnownChecksum); ok { + f.inputs[d] = cureRes{checksum: unique.Make(kc.Checksum())} + continue + } + + var sum unique.Handle[Checksum] + did := c.Ident(d) + sum, err = c.tryLocal(did) + if err != nil { + if !errors.Is(err, os.ErrNotExist) { + return + } + + sum, err = c.tryExtern(ctx, did) + if err != nil { + return + } + if sum == zeroChecksum { + if c.msg.IsVerbose() { + c.msg.Verbosef( + "input %s not available", + reportName(d, did), + ) + } + err = HangingInputError(did) + return + } + } + + f.inputs[d] = cureRes{checksum: sum} + } + } + sh := sha512.New384() err = c.encode(sh, a, f.inputs) if err != nil { @@ -2245,14 +2331,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) ( defer f.destroy(&err) - var externChecksum unique.Handle[Checksum] - if externChecksum, err = c.tryExtern(ctx, id); err != nil { - if c.msg.IsVerbose() { - c.msg.Verbosef("extern %s: %v", reportName(ca, id), err) - } - return - } - if externChecksum != zeroChecksum { + if extern { if checksum != zeroChecksum && externChecksum != checksum { err = &ChecksumMismatchError{externChecksum.Value(), checksum.Value()} if c.msg.IsVerbose() { |
