The indexer says take-in.taken under every claimed entry's own key too (issue 1966, note 195)

A merge waiting behind a gathered group is named by indexer_pending under its own key; when the
group ends it joins the group's revision under the oldest member's key, so its own key was never
said taken. takenWaits now also says every claimed entry's key, no key twice. T8 checks the merge
behind the group ends under its own key.

Builds: design 47 "Taken in by the indexer it names" (A wait is bounded, said and recoverable); 1966/AC195-1, AC195-3

Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
This commit is contained in:
2026-11-10 23:45:52 +01:00
parent 393f69f766
commit 3ed2a3dd33
2 changed files with 12 additions and 9 deletions
@@ -1093,11 +1093,11 @@ func (ix *Indexer) takeInWholeBy(ctx context.Context, entries []PendingEntry, ow
return applied, nil
}
// takenWaits are the taken events of a take-in: every wait the entries were said under (saidWaits) and every wait
// indexer_pending names the entries by (PendingWaits: a revision by its oldest merge's key, a group by its g. key) not
// already ended by one of those, so a wait the watchman learned of without the indexer marking it (seeded from
// indexer_pending, or said by the own-build-unknown path) ends too (design 47, Taken in by the indexer it names). No key is
// said twice.
// takenWaits are the taken events of a take-in: every wait the entries were said under (saidWaits), every wait
// indexer_pending names the claimed entries by now (WaitsOf: a revision by its oldest merge's key, a group by its g. key) and
// the key of every claimed entry, since indexer_pending named it by that key earlier when it waited behind a group. So a wait
// the watchman learned of without the indexer marking it (seeded from indexer_pending, or said by the own-build-unknown
// path) ends too (design 47, Taken in by the indexer it names). No key is said twice.
func takenWaits(entries []PendingEntry) []takein.TakeIn {
out := saidWaits(entries)
said := map[string]bool{}
@@ -1115,6 +1115,9 @@ func takenWaits(entries []PendingEntry) []takein.TakeIn {
for _, g := range slices.Sorted(maps.Keys(w.Behind)) {
named = append(named, revisionWait(takein.TakeInTaken, w.Behind[g], w.Behind[g][len(w.Behind[g])-1].Value.WaitsFor))
}
for _, e := range entries {
named = append(named, revisionWait(takein.TakeInTaken, []PendingEntry{e}, e.Value.WaitsFor))
}
for _, t := range named {
if !said[t.Key] {
said[t.Key] = true
@@ -228,8 +228,8 @@ func TestTakeIn(t *testing.T) { // 1585/T3-T13 (ADR 0633)
b.arrive(t, 9, b.merge(32, sha('d'), "tree-avahi-4", "tree-indexer-2"))
b.said = nil
b.arrive(t, 10, b.merge(33, sha('e'), "tree-avahi-5", b.base.Trees["modules/"+Module]))
if want := []string{"taken " + takein.PendingKey(8)}; !slices.Equal(b.events(), want) || len(b.keys()) != 0 {
t.Errorf("said %v, pending %v: want %v once", b.events(), b.keys(), want)
if want := []string{"taken " + takein.PendingKey(8), "taken " + takein.PendingKey(9), "taken " + takein.PendingKey(10)}; !slices.Equal(b.events(), want) || len(b.keys()) != 0 {
t.Errorf("said %v, pending %v: want %v, the wait's key (m.8, said pending) once and each other entry's own", b.events(), b.keys(), want)
}
})
t.Run("T7 and T3 a merge alone, an indexer change, a merge behind it and a revert", func(t *testing.T) {
@@ -287,7 +287,7 @@ func TestTakeIn(t *testing.T) { // 1585/T3-T13 (ADR 0633)
if len(b.keys()) != 0 || b.fp(t, Module) != own || b.commit(t, "avahi") != sha('e') {
t.Fatalf("revert: pending %v, indexer %s, avahi at %s: want all taken in", b.keys(), b.fp(t, Module), b.commit(t, "avahi"))
}
if want := []string{"pending " + takein.PendingKey(2), "taken " + takein.PendingKey(2)}; !slices.Equal(b.events(), want) {
if want := []string{"pending " + takein.PendingKey(2), "taken " + takein.PendingKey(2), "taken " + takein.PendingKey(3), "taken " + takein.PendingKey(4)}; !slices.Equal(b.events(), want) {
t.Errorf("said %v, want %v", b.events(), want)
}
})
@@ -487,7 +487,7 @@ func TestTakeIn(t *testing.T) { // 1585/T3-T13 (ADR 0633)
if len(b.keys()) != 0 || b.commit(t, "avahi") != sha('6') {
t.Fatalf("end: pending %v, avahi at %s: want the group and the merge behind it taken in", b.keys(), b.commit(t, "avahi"))
}
if want := []string{"pending g.feat/take-in", "taken " + takein.PendingKey(2), "pending g.feat/take-in", "taken g.feat/take-in", "taken " + takein.PendingKey(1)}; !slices.Equal(b.events(), want) {
if want := []string{"pending g.feat/take-in", "taken " + takein.PendingKey(2), "pending g.feat/take-in", "taken g.feat/take-in", "taken " + takein.PendingKey(1), "taken " + takein.PendingKey(3), "taken " + takein.PendingKey(4)}; !slices.Equal(b.events(), want) {
t.Errorf("said %v, want %v", b.events(), want)
}
// R1: the end published again after the take-in changes nothing and is not delivered again.