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 "maps"
5 "path/filepath"
6 "reflect"
7 "sync"
8
9 "github.com/carlosframework/platform/internal/hostclaim"
10)
11
12type claimRestoreObservation struct {
13 mu sync.Mutex
14 observed hostclaim.Observed
15 box, dataDir, db string
16}
17
18func sameClaimObservation(a, b hostclaim.Observed) bool {
19 return !a.Absent && !b.Absent && a.Host == b.Host && a.ETag != "" && a.ETag == b.ETag && reflect.DeepEqual(a.Claim, b.Claim)
20}
21
22func (in ClaimLaunchInputs) observeClaimWrite(before, after hostclaim.Observed) error {
23 if in.claimWrite == nil || before.Claim == nil && after.Claim == nil {
24 return nil
25 }
26 return in.claimWrite(before, after)
27}
28
29func (r *claimRestoreObservation) snapshot() hostclaim.Observed {
30 r.mu.Lock()
31 defer r.mu.Unlock()
32 return r.observed
33}
34
35func (r *claimRestoreObservation) retag(before, after hostclaim.Observed) error {
36 return r.advance(before, after, func(expected *hostclaim.Claim) error {
37 db, err := filepath.Rel(r.dataDir, r.db)
38 if err != nil || !filepath.IsLocal(db) || expected.Holder == nil {
39 return hostclaim.ErrConflict
40 }
41 db = filepath.ToSlash(db)
42 entry := expected.Inventory[r.box]
43 old, left := entry.Paths[db]
44 marker, right := entry.Paths[db+".gen"]
45 if left != right || old != marker || left && (old == 0 || old >= expected.Holder.Stamp) {
46 return hostclaim.ErrConflict
47 }
48 expected.Inventory = maps.Clone(expected.Inventory)
49 if expected.Inventory == nil {
50 expected.Inventory = make(map[string]hostclaim.InventoryEntry)
51 }
52 entry.Paths = maps.Clone(entry.Paths)
53 if entry.Paths == nil {
54 entry.Paths = make(map[string]uint64)
55 }
56 if expected.Op.Kind == hostclaim.KindServing {
57 entry.Layout = "nested"
58 }
59 entry.Paths[db], entry.Paths[db+".gen"] = expected.Holder.Stamp, expected.Holder.Stamp
60 expected.Inventory[r.box] = entry
61 return nil
62 })
63}
64
65func (r *claimRestoreObservation) retry(before, after hostclaim.Observed) error {
66 return r.advance(before, after, func(expected *hostclaim.Claim) error {
67 if expected.Op.Kind != hostclaim.KindServing || expected.Holder == nil || after.Claim.Holder == nil {
68 return hostclaim.ErrConflict
69 }
70 holder := *expected.Holder
71 holder.WakeRetry = after.Claim.Holder.WakeRetry
72 expected.Holder = &holder
73 return nil
74 })
75}
76
77func (r *claimRestoreObservation) advance(before, after hostclaim.Observed, delta func(*hostclaim.Claim) error) error {
78 r.mu.Lock()
79 defer r.mu.Unlock()
80 if !sameClaimObservation(r.observed, before) || before.Claim == nil || after.Claim == nil || after.Absent || after.Host != before.Host || after.ETag == "" || after.ETag == before.ETag || after.Claim.Gen != before.Claim.Gen+1 {
81 return hostclaim.ErrConflict
82 }
83 expected := *before.Claim
84 expected.Gen++
85 if err := delta(&expected); err != nil {
86 return err
87 }
88 if !reflect.DeepEqual(&expected, after.Claim) {
89 return hostclaim.ErrConflict
90 }
91 r.observed = after
92 return nil
93}
94