mesh-issues: an open whose write may have landed never says nothing was opened, and a module must itself be registered
mesh/merge-gate pass: builds new: modules/mesh-issues, sent nowhere; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery delivered
mesh/merge-gate pass: builds new: modules/mesh-issues, sent nowhere; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery delivered
From the review: a taken key that cannot be read back, or a write never confirmed, now tells the caller to get the number before opening again; an owner entry naming a module is owned only by that module registered; link targets get the secret guard; line separators are refused in one-line fields; the acceptance test now proves the counter's own updates were contended.
This commit is contained in:
@@ -40,7 +40,7 @@ const (
|
||||
// caller is told, and nothing was written.
|
||||
const (
|
||||
// counterRounds × counterAttempts is how many times one open tries to advance the counter.
|
||||
counterRounds = 12
|
||||
counterRounds = 20
|
||||
counterAttempts = 8
|
||||
// issueAttempts is how many times a change to one issue is read and written again.
|
||||
issueAttempts = 16
|
||||
@@ -129,9 +129,6 @@ func (t *Tracker) Open(a OpenAsk) (*Opened, error) {
|
||||
if record == "" {
|
||||
is.Status = StatusOpen
|
||||
}
|
||||
if size, _ := json.Marshal(is); len(size) > MostIssueBytes-1024 {
|
||||
return nil, fmt.Errorf("the issue is %d bytes; one issue is kept in at most %d", len(size), MostIssueBytes)
|
||||
}
|
||||
|
||||
n, err := t.next()
|
||||
if err != nil {
|
||||
@@ -161,13 +158,22 @@ func (t *Tracker) create(is *Issue) error {
|
||||
key := keyOf(is.Number)
|
||||
var err error
|
||||
for i := 0; i < createAttempts; i++ {
|
||||
if i > 0 {
|
||||
t.Sleep(jitter(time.Duration(i) * 50 * time.Millisecond))
|
||||
}
|
||||
_, err = t.Store.Create(IssuesState, key, is)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if errors.Is(err, stdio.ErrChanged) {
|
||||
// Ours, written by an attempt whose answer was lost?
|
||||
if there, _, rerr := read(t.Store, is.Number); rerr == nil && there.Opening == is.Opening {
|
||||
there, _, rerr := read(t.Store, is.Number)
|
||||
if rerr != nil {
|
||||
t.Logf("[mesh-issues] issue %d is kept and could not be read back: %v", is.Number, rerr)
|
||||
return fmt.Errorf("issue %d may have been written by this open: the key is taken and could not be read "+
|
||||
"back (%v). Call get %d before opening it again, so it is not opened twice", is.Number, rerr, is.Number)
|
||||
}
|
||||
if there.Opening == is.Opening {
|
||||
return nil
|
||||
}
|
||||
t.Logf("[mesh-issues] the counter handed out %d and an issue %d is already kept: not overwritten", is.Number, is.Number)
|
||||
@@ -176,9 +182,13 @@ func (t *Tracker) create(is *Issue) error {
|
||||
"and tell the operator the counter is behind the issues kept", is.Number, is.Number, is.Number)
|
||||
}
|
||||
}
|
||||
t.Logf("[mesh-issues] number %d was taken and the issue could not be written: %v", is.Number, err)
|
||||
return fmt.Errorf("number %d was taken and the issue could not be written (%v); nothing was opened and %d "+
|
||||
"stays unused. Open it again", is.Number, err, is.Number)
|
||||
// A write that timed out may still have landed: say so, never "nothing was opened".
|
||||
t.Logf("[mesh-issues] number %d was taken and the issue's write was not confirmed: %v", is.Number, err)
|
||||
if there, _, rerr := read(t.Store, is.Number); rerr == nil && there.Opening == is.Opening {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("number %d was taken and the issue's write was not confirmed (%v): it may have been written. "+
|
||||
"Call get %d before opening it again; if there is no issue %d, it stays unused", is.Number, err, is.Number, is.Number)
|
||||
}
|
||||
|
||||
// next takes the next issue number: the counter advanced only at the revision read, so two openers — in
|
||||
|
||||
Reference in New Issue
Block a user