Join item 3: the indexer's empty manifest-accepted takes its id from the event (EventID names module and revision)
delivery.ManifestAccepted.EventID now names, for an event with no digest, the module and the event's revision (J3, ruling A5(d)), so the indexer drops its own left id. The revision is the modules state's revision of the value that left (write hands the revision it read), so two leaves of one module are two events; asked again by hand for a module no longer held it is 0, and the again suffix keeps it unique. Row in TestAMergeThatRemovesAModuleDeletesItsKey (failed first: Revision 0, id naming the last digest). Claude-Session: https://claude.ai/code/session_01JG73KJNrH5EgFXMKKYSrig
This commit is contained in:
@@ -39,11 +39,12 @@ func acceptedOf(digest string, v delivery.ManifestVerdict, revision uint64, raw
|
||||
return a
|
||||
}
|
||||
|
||||
// leftOf is the empty manifest-accepted for module, which left the trunk, judged by judgeID; its event id names the module
|
||||
// and the manifest it last held, since its body names no digest.
|
||||
func leftOf(module, lastDigest, judgeID string) (delivery.ManifestAccepted, string) {
|
||||
a := delivery.ManifestAccepted{V: delivery.Version, Module: module, Judge: judgeID, BusState: []catalogue.BusStateEntry{}}
|
||||
return a, delivery.ManifestAcceptedEvent + "-left-" + module + "-" + lastDigest
|
||||
// leftOf is the empty manifest-accepted for module, which left the trunk, judged by judgeID; revision is the modules
|
||||
// state's revision of the value that left (0 when none is held), so its event id (delivery.ManifestAccepted.EventID, the
|
||||
// module and the revision, since its body names no digest) differs for each leave.
|
||||
func leftOf(module string, revision uint64, judgeID string) (delivery.ManifestAccepted, string) {
|
||||
a := delivery.ManifestAccepted{V: delivery.Version, Module: module, Judge: judgeID, BusState: []catalogue.BusStateEntry{}, Revision: revision}
|
||||
return a, a.EventID()
|
||||
}
|
||||
|
||||
// sayAccepted says a with the event id id, once more when the first publish fails; the module's finding is written when
|
||||
@@ -109,7 +110,7 @@ func (ix *Indexer) sayFor(ctx context.Context, module string, allowLeft, again b
|
||||
case !ok && !allowLeft:
|
||||
return "", fmt.Errorf("the indexer holds no module %s, so it has no accepted verdict to say", module)
|
||||
case !ok:
|
||||
a, id = leftOf(module, "", ix.judgeID())
|
||||
a, id = leftOf(module, 0, ix.judgeID())
|
||||
case m.Manifest == "" || ix.Verdicts == nil || ix.Manifests == nil:
|
||||
return "", fmt.Errorf("%s has no accepted verdict the indexer holds", module)
|
||||
default:
|
||||
|
||||
@@ -322,7 +322,8 @@ func (ix *Indexer) applyOpen(ctx context.Context, f delivery.Forge) error {
|
||||
|
||||
// write changes one key of a store by compare-and-set: compute is given the value read (found says there is one) and
|
||||
// answers the new value, or del to remove the key, or neither for no change. A conflict reads again, up to writeTries.
|
||||
func write(ctx context.Context, st Store, key string, compute func(value []byte, found bool) (next []byte, del bool, err error)) error {
|
||||
// read, when given, is set to the revision of the value compute was last given.
|
||||
func write(ctx context.Context, st Store, key string, compute func(value []byte, found bool) (next []byte, del bool, err error), read ...*uint64) error {
|
||||
for try := 0; try < writeTries; try++ {
|
||||
value, revision, found, err := st.Get(ctx, key)
|
||||
if err != nil {
|
||||
@@ -332,6 +333,9 @@ func write(ctx context.Context, st Store, key string, compute func(value []byte,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, r := range read {
|
||||
*r = revision
|
||||
}
|
||||
switch {
|
||||
case next == nil && !del:
|
||||
return nil
|
||||
|
||||
@@ -236,6 +236,7 @@ func (ix *Indexer) dropRemoved(ctx context.Context, repository string, held map[
|
||||
elsewhere[key] = f
|
||||
continue
|
||||
}
|
||||
var left uint64 // the revision of the value deleted, which names its leave (leftOf)
|
||||
err := write(ctx, ix.Modules, key, func(value []byte, found bool) ([]byte, bool, error) {
|
||||
if !found {
|
||||
return nil, false, nil
|
||||
@@ -244,13 +245,13 @@ func (ix *Indexer) dropRemoved(ctx context.Context, repository string, held map[
|
||||
return nil, false, nil
|
||||
}
|
||||
return nil, true, nil
|
||||
})
|
||||
}, &left)
|
||||
if err != nil {
|
||||
return fmt.Errorf("modules.%s: %w", key, err)
|
||||
}
|
||||
ix.logf("modules.%s deleted: %s holds no module of that name at its trunk (issue 1900)", key, repository)
|
||||
// The bus module hears the module asks nothing now, so its entries reach orphans (design 25 § 12.2, DLV-I9).
|
||||
a, id := leftOf(key, cur.Manifest, ix.judgeID())
|
||||
a, id := leftOf(key, left, ix.judgeID())
|
||||
_ = ix.sayAccepted(ctx, a, id)
|
||||
}
|
||||
for _, key := range handed {
|
||||
|
||||
@@ -37,7 +37,9 @@ func TestAMergeThatRemovesAModuleDeletesItsKey(t *testing.T) { // 1900/AC1
|
||||
for i, a := range said {
|
||||
if a.Digest == "" {
|
||||
left = append(left, a.Module)
|
||||
if a.BusState == nil || len(a.BusState) != 0 || !strings.Contains(ids[i], "-left-b") {
|
||||
// Join item 3: the id is the event's own (delivery.ManifestAccepted.EventID), naming the module and the
|
||||
// modules state's revision of the value that left, so two leaves of one module are two events.
|
||||
if a.BusState == nil || len(a.BusState) != 0 || a.Revision == 0 || ids[i] != a.EventID() || !strings.Contains(ids[i], "-left-b-") {
|
||||
t.Errorf("the empty manifest-accepted = %+v, id %s", a, ids[i])
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user