aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/pkg
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-07-02 20:06:27 +0900
committerOphestra <cat@gensokyo.uk>2026-07-02 20:08:28 +0900
commitb538c69e01ea29217ccc4b442f2c8b2b7ce99c7d (patch)
tree81a73c981e1328d57c807e1f3e1124046883c158 /internal/pkg
parentc921ba4680c3942022561831b64a6d23b60dbd35 (diff)
internal/pkg: cache extern responses
This prepares substitute computation for shallow extern replacements. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/pkg')
-rw-r--r--internal/pkg/pkg.go55
1 files changed, 33 insertions, 22 deletions
diff --git a/internal/pkg/pkg.go b/internal/pkg/pkg.go
index f1e6279d..d8e059bd 100644
--- a/internal/pkg/pkg.go
+++ b/internal/pkg/pkg.go
@@ -770,6 +770,8 @@ type Cache struct {
// Optional external cache implementation.
extern External
+ // Caches responses from extern.
+ externCache map[unique.Handle[ID]]unique.Handle[Checksum]
// Synchronises access to extern.
externMu sync.RWMutex
@@ -930,6 +932,7 @@ func readlinkChecksum(a *check.Absolute, buf *Checksum) error {
// SetExternal sets e as the [External] implementation of c.
func (c *Cache) SetExternal(e External) {
c.externMu.Lock()
+ c.externCache = make(map[unique.Handle[ID]]unique.Handle[Checksum])
c.extern = e
c.externMu.Unlock()
}
@@ -1849,37 +1852,45 @@ func (r *RContext) NewMeasuredReader(
}
// tryExtern attempts to obtain an [Artifact] outcome from extern.
-func (c *Cache) tryExtern(ctx context.Context, id unique.Handle[ID]) (
+func (c *Cache) tryExtern(
+ ctx context.Context,
+ id unique.Handle[ID],
+ status *io.ReadCloser,
+) (
unique.Handle[Checksum],
- io.ReadCloser,
error,
) {
c.externMu.RLock()
defer c.externMu.RUnlock()
- if c.extern == nil {
- return zeroChecksum, nil, nil
- }
+ checksum, ok := c.externCache[id]
+ if !ok {
+ if c.extern == nil {
+ return zeroChecksum, nil
+ }
- v, err := c.extern.Artifact(ctx, id)
- if err != nil {
- return zeroChecksum, nil, err
- }
- if v == nil {
- return zeroChecksum, nil, nil
- }
- checksum := unique.Make(*v)
+ v, err := c.extern.Artifact(ctx, id)
+ if err != nil {
+ return zeroChecksum, err
+ }
+ if v == nil {
+ return zeroChecksum, nil
+ }
+ checksum = unique.Make(*v)
- var got unique.Handle[Checksum]
- if _, got, err = c.Cure(c.extern.Checksum(checksum)); err != nil {
- return checksum, nil, err
- } else if got != checksum {
- return zeroChecksum, nil, &ChecksumMismatchError{got.Value(), checksum.Value()}
+ var got unique.Handle[Checksum]
+ if _, got, err = c.Cure(c.extern.Checksum(checksum)); err != nil {
+ return checksum, err
+ } else if got != checksum {
+ return zeroChecksum, &ChecksumMismatchError{got.Value(), checksum.Value()}
+ }
}
- var status io.ReadCloser
- status, err = c.extern.Status(&RContext{common{ctx, c}}, id)
- return checksum, status, err
+ var err error
+ if status != nil {
+ *status, err = c.extern.Status(&RContext{common{ctx, c}}, id)
+ }
+ return checksum, err
}
// cure implements Cure without acquiring a read lock on abortMu. cure must not
@@ -2225,7 +2236,7 @@ func (c *Cache) cure(a Artifact, curesExempt bool) (
externChecksum unique.Handle[Checksum]
externStatus io.ReadCloser
)
- if externChecksum, externStatus, err = c.tryExtern(ctx, id); err != nil {
+ if externChecksum, err = c.tryExtern(ctx, id, &externStatus); err != nil {
if c.msg.IsVerbose() {
c.msg.Verbosef("extern %s: %v", reportName(ca, id), err)
}