carlos / platform Public

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

Plain git — no account needed to clone.

Download

Download this file

1package console
2
3// The console's reads through the S3 change index (S3 change-index design
4// §4.6, discussion #336). Armed only by CARLOS_CHANGE_INDEX=read, which
5// cmd/console turns into a record view handed to SetRecordView; unarmed,
6// recordView stays nil and every sweep walks the bucket as before.
7
8import (
9 "context"
10 "log"
11
12 "github.com/carlosframework/platform/internal/provision"
13 "github.com/carlosframework/platform/internal/release"
14)
15
16// SetRecordView arms the run and seed sweeps' record reads with v. serve
17// calls it once, before it starts any worker; nil leaves them disarmed.
18func (s *Server) SetRecordView(v *provision.RecordView) { s.recordView = v }
19
20// The viewUse states; zero is none yet.
21const (
22 viewUseView int32 = 1 + iota
23 viewUseWalk
24)
25
26// recordWalkStore is the store a sweep's record walk reads: the armed view's
27// snapshot over live, refreshed first, when the refresh returned nil and the
28// snapshot is Complete. Otherwise ok is false and the store is live, so the
29// sweep walks the bucket as it did before the index (spec §3.4).
30//
31// Only record walks take it (provision.ListAllRecords*). The snapshot's
32// ListDirs of apps/<a>/ names only apps with record-family state, so it must
33// never reach an app enumerator, and every write and every non-record read
34// (runs/, seeds/) stays on live. ctx bounds the refresh, so a stuck index
35// poll or walk cannot hold the view, or the sweep, for good.
36func (s *Server) recordWalkStore(ctx context.Context, live release.Store) (release.Store, bool) {
37 v := s.recordView
38 if v == nil || live == nil {
39 return live, false
40 }
41 err := v.Refresh(ctx)
42 sn := v.Snapshot()
43 switch {
44 case err != nil:
45 s.noteViewUse(false, "the record view's refresh failed: "+err.Error())
46 return live, false
47 case sn == nil || !sn.Complete:
48 s.noteViewUse(false, "the record view's snapshot is incomplete")
49 return live, false
50 }
51 s.noteViewUse(true, "")
52 return sn.Store(live), true
53}
54
55// noteViewUse logs a switch between reading the view and walking the bucket,
56// once per change rather than on every pass.
57func (s *Server) noteViewUse(ok bool, why string) {
58 state := viewUseWalk
59 if ok {
60 state = viewUseView
61 }
62 if s.viewUse.Swap(state) == state {
63 return
64 }
65 if ok {
66 log.Printf("console: record view: the sweeps' record walks read the view")
67 return
68 }
69 log.Printf("console: record view: %s; the sweeps' record walks read the bucket until it can vouch again", why)
70}
71