aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/pkg/ir.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-05-11 19:44:28 +0900
committerOphestra <cat@gensokyo.uk>2026-05-12 00:19:42 +0900
commit6e113b88364ade12b26c9f01c43608841b9378df (patch)
tree28386b65784d7b50f976e3c3f2634dc007f1661f /internal/pkg/ir.go
parentce9f4b5f713b2ff2a03adefe83175d75d16ef24f (diff)
internal/pkg: content-based dependency substitution
This change introduces a new fast path for FloodArtifact. It is taken when a curing artifact has identical-by-content controlled relevant inputs and are otherwise identical to an already-cured artifact. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/pkg/ir.go')
-rw-r--r--internal/pkg/ir.go58
1 files changed, 47 insertions, 11 deletions
diff --git a/internal/pkg/ir.go b/internal/pkg/ir.go
index c93abc9e..72a2c90c 100644
--- a/internal/pkg/ir.go
+++ b/internal/pkg/ir.go
@@ -76,6 +76,9 @@ type IContext struct {
// Written to by various methods, should be zeroed after [Artifact.Params]
// returns and must not be exposed directly.
w io.Writer
+ // Optional [Artifact] to cureRes cache, replaces [IRKindIdent] with
+ // checksum values if non-nil.
+ inputs map[Artifact]cureRes
}
// irZero is a zero IR word.
@@ -163,7 +166,15 @@ func (i *IContext) WriteIdent(a Artifact) {
defer i.ic.putIdentBuf(buf)
IRKindIdent.encodeHeader(0).put(buf[:])
- *(*ID)(buf[wordSize:]) = i.ic.Ident(a).Value()
+ if i.inputs != nil {
+ res, ok := i.inputs[a]
+ if !ok {
+ panic(InvalidLookupError(i.ic.Ident(a).Value()))
+ }
+ *(*ID)(buf[wordSize:]) = res.checksum.Value()
+ } else {
+ *(*ID)(buf[wordSize:]) = i.ic.Ident(a).Value()
+ }
i.mustWrite(buf[:])
}
@@ -207,19 +218,44 @@ func (i *IContext) WriteString(s string) {
// Encode writes a deterministic, efficient representation of a to w and returns
// the first non-nil error encountered while writing to w.
func (ic *irCache) Encode(w io.Writer, a Artifact) (err error) {
+ return ic.encode(w, a, nil)
+}
+
+// encode implements Encode but replaces identifiers with their cured checksums
+// for a non-nil ident. Caller must acquire Cache.identMu.
+func (ic *irCache) encode(
+ w io.Writer,
+ a Artifact,
+ inputs map[Artifact]cureRes,
+) (err error) {
deps := a.Dependencies()
idents := make([]*extIdent, len(deps))
- for i, d := range deps {
- dbuf, did := ic.unsafeIdent(d, true)
- if dbuf == nil {
- dbuf = ic.getIdentBuf()
+ if inputs == nil {
+ for i, d := range deps {
+ dbuf, did := ic.unsafeIdent(d, true)
+ if dbuf == nil {
+ dbuf = ic.getIdentBuf()
+ binary.LittleEndian.PutUint64(dbuf[:], uint64(d.Kind()))
+ *(*ID)(dbuf[wordSize:]) = did.Value()
+ } else {
+ ic.storeIdent(d, dbuf)
+ }
+ defer ic.putIdentBuf(dbuf)
+ idents[i] = dbuf
+ }
+ } else {
+ for i, d := range deps {
+ res, ok := inputs[d]
+ if !ok {
+ return InvalidLookupError(ic.Ident(d).Value())
+ }
+
+ dbuf := ic.getIdentBuf()
binary.LittleEndian.PutUint64(dbuf[:], uint64(d.Kind()))
- *(*ID)(dbuf[wordSize:]) = did.Value()
- } else {
- ic.storeIdent(d, dbuf)
+ *(*ID)(dbuf[wordSize:]) = res.checksum.Value()
+ defer ic.putIdentBuf(dbuf)
+ idents[i] = dbuf
}
- defer ic.putIdentBuf(dbuf)
- idents[i] = dbuf
}
slices.SortFunc(idents, func(a, b *extIdent) int {
return bytes.Compare(a[:], b[:])
@@ -244,7 +280,7 @@ func (ic *irCache) Encode(w io.Writer, a Artifact) (err error) {
}
func() {
- i := IContext{ic, w}
+ i := IContext{ic, w, inputs}
defer panicToError(&err)
defer func() { i.ic, i.w = nil, nil }()