carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package host
2
3import (
4 "context"
5 "errors"
6 "os"
7
8 "github.com/carlosframework/platform/internal/hostbox"
9 "github.com/carlosframework/platform/internal/hostclaim"
10 execlease "github.com/carlosframework/platform/internal/hostexec"
11)
12
13// Acknowledged is region HA's read of main's participation for a
14// relocating operation (rev 2, ruling 42). It adds no authority: it is
15// Prepare, exactly as WorkSource.Prepare and the participation loop call
16// it, then the slot's own Ready. Whichever caller comes first opens the
17// box's one controller for {host, op}; every later caller gets that same
18// controller's state. A lost or failed controller is main's retained
19// denial (CC9), returned as its error and never replaced here.
20func (p *productionClaimLocal) Acknowledged(ctx context.Context, o hostclaim.Observed) (execlease.State, error) {
21 if o.Claim == nil || o.Claim.Holder == nil || o.Claim.Op.Kind != hostclaim.KindRelocating {
22 return execlease.State{}, hostbox.ErrChanged
23 }
24 if err := p.Prepare(ctx, o); err != nil {
25 return execlease.State{}, err
26 }
27 p.mu.Lock()
28 slot := p.slots[o.Host]
29 p.mu.Unlock()
30 if slot == nil {
31 return execlease.State{}, execlease.ErrInactive
32 }
33 select {
34 case <-slot.Ready:
35 case <-ctx.Done():
36 return execlease.State{}, ctx.Err()
37 }
38 if slot.Err != nil {
39 return execlease.State{}, slot.Err
40 }
41 if slot.Controller == nil {
42 return execlease.State{}, execlease.ErrInactive
43 }
44 return slot.Controller.Ready(ctx)
45}
46
47// boundAssembly is the assembly Build bound this owner to: the copy whose
48// reconcile adapter, census and guard reader Build configured. Nil before
49// Build. N1's second accessor.
50func (p *productionClaimLocal) boundAssembly() *ClaimAssembly {
51 p.mu.Lock()
52 defer p.mu.Unlock()
53 return p.assembly
54}
55
56// DischargeCompleted is ruling 66's gate before a completed relocation's
57// hold is released: main's own Prepare for the serving observation, which
58// closes the participation slot (its cleanup is C10's discharge, first)
59// and clears the .hostexec record, or, after a restart, clears the
60// untracked record through clearUntracked (the same discharge, keyed by
61// the persisted binding). It succeeds only once neither a slot nor a
62// record is left for the host. N1's third accessor; no new authority.
63func (p *productionClaimLocal) DischargeCompleted(ctx context.Context, o hostclaim.Observed) error {
64 if o.Claim == nil || o.Claim.Holder == nil || o.Claim.Op.Kind != hostclaim.KindServing {
65 return hostbox.ErrChanged
66 }
67 actor, err := p.Identity.Verify(ctx)
68 if err != nil {
69 return err
70 }
71 return p.dischargeCompletedAs(ctx, actor, o)
72}
73
74// dischargeCompletedAs is DischargeCompleted for a verified actor: main's
75// prepareWith, then nothing of the participation may be left.
76func (p *productionClaimLocal) dischargeCompletedAs(ctx context.Context, actor hostbox.Actor, o hostclaim.Observed) error {
77 if err := p.prepareWith(ctx, actor, o); err != nil {
78 return err
79 }
80 p.mu.Lock()
81 slot := p.slots[o.Host]
82 p.mu.Unlock()
83 if slot != nil {
84 return execlease.ErrInactive
85 }
86 if !p.legacyParticipation {
87 return nil
88 }
89 if _, err := execlease.InspectLocal(p.Resources.DataDir, o.Host); !errors.Is(err, os.ErrNotExist) {
90 return errors.Join(execlease.ErrInactive, err)
91 }
92 return nil
93}
94