internal/pkg: optional shallow external cure
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m54s
Test / ShareFS (push) Successful in 4m6s
Test / Hakurei (push) Successful in 4m12s
Test / Sandbox (race detector) (push) Successful in 5m49s
Test / Hakurei (race detector) (push) Successful in 6m51s
Test / Flake checks (push) Successful in 1m22s
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m54s
Test / ShareFS (push) Successful in 4m6s
Test / Hakurei (push) Successful in 4m12s
Test / Sandbox (race detector) (push) Successful in 5m49s
Test / Hakurei (race detector) (push) Successful in 6m51s
Test / Flake checks (push) Successful in 1m22s
This saves time and is often more practical even for package maintainers. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
+92
-13
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user