carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package activator
2
3import (
4 "context"
5 "github.com/carlosframework/platform/internal/controlname"
6)
7
8// SeedExclusion is a process-local preparation fence. Only its original
9// executor may resume it after failed cleanup; it is never a wire identity.
10type SeedExclusion struct {
11 service *Service
12 host string
13}
14
15func (a *Service) AcquireSeedExclusion(ctx context.Context, host string, prior *SeedExclusion) (*SeedExclusion, error) {
16 if a == nil || ctx == nil || !controlname.ValidHostShape(host) {
17 return nil, ErrFenceNotInstalled
18 }
19 for {
20 if err := ctx.Err(); err != nil {
21 return nil, err
22 }
23 a.mu.Lock()
24 if a.shuttingDown {
25 a.mu.Unlock()
26 return nil, ErrFenceNotInstalled
27 }
28 if prior != nil {
29 ok := prior.service == a && prior.host == host && a.seedExclusions[host] == prior && a.fences[host] == ^uint64(0)
30 a.mu.Unlock()
31 if !ok {
32 return nil, ErrFenceHeld
33 }
34 return prior, nil
35 }
36 if a.fences[host] != 0 {
37 a.mu.Unlock()
38 return nil, ErrFenceHeld
39 }
40 wait := a.tokenPreparations[host]
41 if e := a.entries[host]; e != nil {
42 if e.state == actWaking {
43 wait = e.ready
44 }
45 if e.state == actStopping {
46 wait = e.stopped
47 }
48 }
49 if wait != nil {
50 a.mu.Unlock()
51 select {
52 case <-ctx.Done():
53 return nil, ctx.Err()
54 case <-wait:
55 continue
56 }
57 }
58 token := &SeedExclusion{service: a, host: host}
59 if a.seedExclusions == nil {
60 a.seedExclusions = map[string]*SeedExclusion{}
61 }
62 if a.fences == nil {
63 a.fences = map[string]uint64{}
64 }
65 a.seedExclusions[host] = token
66 a.fences[host] = ^uint64(0)
67 a.mu.Unlock()
68 return token, nil
69 }
70}
71func (t *SeedExclusion) Check(host string) error {
72 if t == nil || t.service == nil || t.host != host {
73 return ErrFenceHeld
74 }
75 a := t.service
76 a.mu.Lock()
77 defer a.mu.Unlock()
78 if a.seedExclusions[host] != t || a.fences[host] != ^uint64(0) {
79 return ErrFenceHeld
80 }
81 return nil
82}
83func (t *SeedExclusion) Release() error {
84 if t == nil || t.service == nil {
85 return ErrFenceHeld
86 }
87 a := t.service
88 a.mu.Lock()
89 defer a.mu.Unlock()
90 if a.seedExclusions[t.host] != t || a.fences[t.host] != ^uint64(0) {
91 return ErrFenceHeld
92 }
93 delete(a.seedExclusions, t.host)
94 delete(a.fences, t.host)
95 return nil
96}
97