@@ -19,12 +19,12 @@ type HeadGetter interface {
19
19
var _ ManifestProvider = (* FusingManifestProvider )(nil )
20
20
21
21
// FusingManifestProvider is a ManifestProvider that starts by providing dynamic manifest updates
22
- // then switches to a static manifest when we get within finality of said manifest's bootstrap
22
+ // then switches to a priority manifest when we get within finality of said manifest's bootstrap
23
23
// epoch.
24
24
type FusingManifestProvider struct {
25
- ec HeadGetter
26
- dynamic ManifestProvider
27
- static * Manifest
25
+ ec HeadGetter
26
+ dynamic ManifestProvider
27
+ priority ManifestProvider
28
28
29
29
manifestCh chan * Manifest
30
30
@@ -34,19 +34,17 @@ type FusingManifestProvider struct {
34
34
clock clock.Clock
35
35
}
36
36
37
- func NewFusingManifestProvider (ctx context.Context , ec HeadGetter , dynamic ManifestProvider , static * Manifest ) (* FusingManifestProvider , error ) {
38
- if err := static .Validate (); err != nil {
39
- return nil , err
40
- }
41
-
37
+ // NewFusingManifestProvider creates a provider that will lock into the priority manifest onces it reaches BootstrapEpoch of priority manifest
38
+ // the priority ManifestProvider needs to provide at least one manifest (or nil), a sign of life, to enable forwarding of dynamic manifests
39
+ func NewFusingManifestProvider (ctx context.Context , ec HeadGetter , dynamic ManifestProvider , priority ManifestProvider ) (* FusingManifestProvider , error ) {
42
40
clk := clock .GetClock (ctx )
43
41
ctx , cancel := context .WithCancel (context .WithoutCancel (ctx ))
44
42
errgrp , ctx := errgroup .WithContext (ctx )
45
43
46
44
return & FusingManifestProvider {
47
45
ec : ec ,
48
46
dynamic : dynamic ,
49
- static : static ,
47
+ priority : priority ,
50
48
errgrp : errgrp ,
51
49
cancel : cancel ,
52
50
runningCtx : ctx ,
@@ -60,41 +58,92 @@ func (m *FusingManifestProvider) ManifestUpdates() <-chan *Manifest {
60
58
}
61
59
62
60
func (m * FusingManifestProvider ) Start (ctx context.Context ) error {
63
- head , err := m .ec .GetHead (ctx )
64
- if err != nil {
65
- return fmt .Errorf ("failed to determine current head epoch" )
61
+ if err := m .priority .Start (ctx ); err != nil {
62
+ return err
66
63
}
67
64
68
- switchEpoch := m .static .BootstrapEpoch - m .static .EC .Finality
69
- headEpoch := head .Epoch ()
70
-
71
- if headEpoch >= switchEpoch {
72
- m .manifestCh <- m .static
73
- return nil
65
+ priorityManifest := <- m .priority .ManifestUpdates ()
66
+ var timer * clock.Timer
67
+ startTimeOfPriority := func (mani * Manifest ) (time.Time , error ) {
68
+ head , err := m .ec .GetHead (ctx )
69
+ if err != nil {
70
+ return time.Time {}, fmt .Errorf ("failed to determine current head epoch: %w" , err )
71
+ }
72
+ headEpoch := head .Epoch ()
73
+ switchEpoch := mani .BootstrapEpoch - mani .EC .Finality
74
+ epochDelay := switchEpoch - headEpoch
75
+ start := head .Timestamp ().Add (time .Duration (epochDelay ) * mani .EC .Period )
76
+ return start , nil
74
77
}
75
78
76
- epochDelay := switchEpoch - headEpoch
77
- start := head .Timestamp ().Add (time .Duration (epochDelay ) * m .static .EC .Period )
79
+ {
80
+ head , err := m .ec .GetHead (ctx )
81
+ if err != nil {
82
+ return fmt .Errorf ("failed to determine current head epoch: %w" , err )
83
+ }
84
+ headEpoch := head .Epoch ()
85
+ // exit early if priorityManifest is relevant right now
86
+ if priorityManifest != nil && headEpoch >= priorityManifest .BootstrapEpoch - priorityManifest .EC .Finality {
87
+ m .priority .Stop (ctx )
88
+ m .manifestCh <- priorityManifest
89
+ return nil
90
+ }
91
+
92
+ if priorityManifest != nil {
93
+ startTime , err := startTimeOfPriority (priorityManifest )
94
+ log .Infof ("starting the fusing manifest provider, will switch to the priority manifest at %s,(now %s)" ,
95
+ startTime , m .clock .Now ())
96
+ if err != nil {
97
+ return fmt .Errorf ("trying to compute start time: %w" , err )
98
+ }
99
+ timer = m .clock .Timer (m .clock .Until (startTime ))
100
+ } else {
101
+ // create a stopped timer
102
+ timer = m .clock .Timer (time .Hour )
103
+ timer .Stop ()
104
+ }
105
+ }
78
106
79
107
if err := m .dynamic .Start (ctx ); err != nil {
80
108
return err
81
109
}
82
110
83
- log .Infof ("starting the fusing manifest provider, will switch to the static manifest at %s" , start )
84
-
85
111
m .errgrp .Go (func () error {
86
- dynamicUpdates := m .dynamic .ManifestUpdates ()
87
- timer := m .clock .Timer (m .clock .Until (start ))
88
112
defer timer .Stop ()
113
+ defer m .priority .Stop (context .Background ())
89
114
90
115
for m .runningCtx .Err () == nil {
91
116
select {
117
+ case priorityManifest = <- m .priority .ManifestUpdates ():
118
+ if priorityManifest == nil {
119
+ timer .Stop ()
120
+ continue
121
+ }
122
+ startTime , err := startTimeOfPriority (priorityManifest )
123
+ if err != nil {
124
+ log .Errorf ("trying to compute start time: %+v" , err )
125
+ // set timer in one epoch, shouldn't happen but be defensive
126
+ timer .Reset (priorityManifest .EC .Period )
127
+ continue
128
+ }
129
+
130
+ log .Infof ("got new priorityManifest, will switch to the priority manifest at %s" ,
131
+ startTime )
132
+ timer .Reset (m .clock .Until (startTime ))
92
133
case <- timer .C :
134
+ log .Errorf ("timer fired" )
135
+ if priorityManifest == nil {
136
+ log .Errorf ("nil priorityManifest" )
137
+ // just a consistency check, timer might have fired before it was stopped
138
+ continue
139
+ }
140
+
93
141
// Make sure we're actually at the target epoch. This shouldn't be
94
142
// an issue unless our clocks are really funky, the network is
95
143
// behind, or we're in a lotus integration test
96
144
// (https://github.com/filecoin-project/lotus/issues/12557).
97
145
head , err := m .ec .GetHead (m .runningCtx )
146
+ switchEpoch := priorityManifest .BootstrapEpoch - priorityManifest .EC .Finality
98
147
switch {
99
148
case err != nil :
100
149
log .Errorw ("failed to get head in fusing manifest provider" , "error" , err )
@@ -103,27 +152,27 @@ func (m *FusingManifestProvider) Start(ctx context.Context) error {
103
152
log .Infow ("delaying fusing manifest switch-over because head is behind the target epoch" ,
104
153
"head" , head .Epoch (),
105
154
"target epoch" , switchEpoch ,
106
- "bootstrap epoch" , m . static .BootstrapEpoch ,
155
+ "bootstrap epoch" , priorityManifest .BootstrapEpoch ,
107
156
)
108
- timer .Reset (m . static .EC .Period )
157
+ timer .Reset (priorityManifest .EC .Period )
109
158
continue
110
159
}
111
160
112
161
log .Infow (
113
- "fusing to the static manifest, stopping the dynamic manifest provider" ,
114
- "network" , m . static .NetworkName ,
115
- "bootstrap epoch" , m . static .BootstrapEpoch ,
162
+ "fusing to the priority manifest, stopping the dynamic manifest provider" ,
163
+ "network" , priorityManifest .NetworkName ,
164
+ "bootstrap epoch" , priorityManifest .BootstrapEpoch ,
116
165
"current epoch" , head .Epoch (),
117
166
)
118
- m .updateManifest (m . static )
167
+ m .updateManifest (priorityManifest )
119
168
// Log any errors and move on. We don't bubble it because we don't
120
169
// want to stop everything if shutting down the dynamic manifest
121
- // provider fails when switching over to a static manifest.
170
+ // provider fails when switching over to a priority manifest.
122
171
if err := m .dynamic .Stop (context .Background ()); err != nil {
123
172
log .Errorw ("failure when stopping dynamic manifest provider" , "error" , err )
124
173
}
125
174
return nil
126
- case update := <- dynamicUpdates :
175
+ case update := <- m . dynamic . ManifestUpdates () :
127
176
m .updateManifest (update )
128
177
case <- m .runningCtx .Done ():
129
178
}
0 commit comments