package activator import ( "context" "github.com/carlosframework/platform/internal/controlname" ) // SeedExclusion is a process-local preparation fence. Only its original // executor may resume it after failed cleanup; it is never a wire identity. type SeedExclusion struct { service *Service host string } func (a *Service) AcquireSeedExclusion(ctx context.Context, host string, prior *SeedExclusion) (*SeedExclusion, error) { if a == nil || ctx == nil || !controlname.ValidHostShape(host) { return nil, ErrFenceNotInstalled } for { if err := ctx.Err(); err != nil { return nil, err } a.mu.Lock() if a.shuttingDown { a.mu.Unlock() return nil, ErrFenceNotInstalled } if prior != nil { ok := prior.service == a && prior.host == host && a.seedExclusions[host] == prior && a.fences[host] == ^uint64(0) a.mu.Unlock() if !ok { return nil, ErrFenceHeld } return prior, nil } if a.fences[host] != 0 { a.mu.Unlock() return nil, ErrFenceHeld } wait := a.tokenPreparations[host] if e := a.entries[host]; e != nil { if e.state == actWaking { wait = e.ready } if e.state == actStopping { wait = e.stopped } } if wait != nil { a.mu.Unlock() select { case <-ctx.Done(): return nil, ctx.Err() case <-wait: continue } } token := &SeedExclusion{service: a, host: host} if a.seedExclusions == nil { a.seedExclusions = map[string]*SeedExclusion{} } if a.fences == nil { a.fences = map[string]uint64{} } a.seedExclusions[host] = token a.fences[host] = ^uint64(0) a.mu.Unlock() return token, nil } } func (t *SeedExclusion) Check(host string) error { if t == nil || t.service == nil || t.host != host { return ErrFenceHeld } a := t.service a.mu.Lock() defer a.mu.Unlock() if a.seedExclusions[host] != t || a.fences[host] != ^uint64(0) { return ErrFenceHeld } return nil } func (t *SeedExclusion) Release() error { if t == nil || t.service == nil { return ErrFenceHeld } a := t.service a.mu.Lock() defer a.mu.Unlock() if a.seedExclusions[t.host] != t || a.fences[t.host] != ^uint64(0) { return ErrFenceHeld } delete(a.seedExclusions, t.host) delete(a.fences, t.host) return nil }