package check import ( "sort" "strings" "sync" "git.novox.be/novox/mesh-sdk/go/delivery" ) // Turns holds the gate's merge turns (novox/hq ADR 0548 ยง3), by repository, as a watch of the gate's turns bucket puts them // in: the checker claims no check of a repository a turn names, except the check of a waiting delivery's own heads, so an // approved merge goes before a check not yet started. A bucket not there is read as empty. type Turns struct { mu sync.Mutex byRepo map[string]delivery.Turn } // Put takes a value of the turns bucket in, or its delete, and answers whether what the checker holds changed. A value that // is not a turn is dropped as a delete would be: a turn the checker cannot read holds nothing. func (t *Turns) Put(key string, value []byte, deleted bool) bool { repository, err := delivery.ParseTurnsKey(key) if err != nil { return false } t.mu.Lock() defer t.mu.Unlock() if t.byRepo == nil { t.byRepo = map[string]delivery.Turn{} } cur, had := t.byRepo[repository] if !deleted { if turn, err := delivery.DecodeTurn(value); err == nil { t.byRepo[repository] = turn return !had || !delivery.SameTurn(cur, turn) } } delete(t.byRepo, repository) return had } // Holding names the first of the repositories (by name) a turn holds off the check of the heads, and the delivery that // waits first in it; false when none does. func (t *Turns) Holding(repositories []string, heads string) (string, delivery.TurnWait, bool) { if t == nil { return "", delivery.TurnWait{}, false } sorted := make([]string, 0, len(repositories)) for _, r := range repositories { sorted = append(sorted, strings.ToLower(r)) } sort.Strings(sorted) t.mu.Lock() defer t.mu.Unlock() for _, r := range sorted { turn, ok := t.byRepo[r] if !ok || !delivery.TurnHolds(turn, heads) { continue } for _, w := range turn.Waiting { if w.Heads != heads { return r, w, true } } } return "", delivery.TurnWait{}, false } // All is every turn held now, by repository (a copy). func (t *Turns) All() map[string]delivery.Turn { t.mu.Lock() defer t.mu.Unlock() out := make(map[string]delivery.Turn, len(t.byRepo)) for r, turn := range t.byRepo { out[r] = turn } return out }