@@ -17,14 +17,25 @@ import (
1717 "github.com/cockroachdb/cockroach/pkg/util/syncutil"
1818)
1919
20+ // supportState contains state pertaining to support provided to a single remote
21+ // store.
22+ type supportState struct {
23+ // SupportState contains all fields that must be persisted to disk.
24+ slpb.SupportState
25+
26+ // lastSupportWithdrawnTime is the timestamp at which support was last
27+ // withdrawn for the remote store.
28+ lastSupportWithdrawnTime hlc.Timestamp
29+ }
30+
2031// supporterState stores the core data structures for providing support.
2132type supporterState struct {
2233 // meta stores the SupporterMeta, including the max timestamp at which this
2334 // store has withdrawn support.
2435 meta slpb.SupporterMeta
25- // supportFor stores the SupportState for each remote store for which this
36+ // supportFor stores the supportState for each remote store for which this
2637 // store has provided support.
27- supportFor map [slpb.StoreIdent ]slpb. SupportState
38+ supportFor map [slpb.StoreIdent ]supportState
2839}
2940
3041// supporterStateHandler is the main interface for handling support for other
@@ -64,15 +75,15 @@ func newSupporterStateHandler() *supporterStateHandler {
6475 ssh := & supporterStateHandler {
6576 supporterState : supporterState {
6677 meta : slpb.SupporterMeta {},
67- supportFor : make (map [slpb.StoreIdent ]slpb. SupportState ),
78+ supportFor : make (map [slpb.StoreIdent ]supportState ),
6879 },
6980 }
7081 ssh .update .Store (
7182 & supporterStateForUpdate {
7283 checkedIn : & ssh .supporterState ,
7384 inProgress : supporterState {
7485 meta : slpb.SupporterMeta {},
75- supportFor : make (map [slpb.StoreIdent ]slpb. SupportState ),
86+ supportFor : make (map [slpb.StoreIdent ]supportState ),
7687 },
7788 },
7889 )
@@ -101,7 +112,7 @@ type supporterStateForUpdate struct {
101112func (ssh * supporterStateHandler ) getSupportFor (id slpb.StoreIdent ) slpb.SupportState {
102113 ssh .mu .RLock ()
103114 defer ssh .mu .RUnlock ()
104- return ssh .supporterState .supportFor [id ]
115+ return ssh .supporterState .supportFor [id ]. SupportState
105116}
106117
107118// getNumSupportFor returns the size of the supporterState.supportFor map.
@@ -116,9 +127,9 @@ func (ssh *supporterStateHandler) getNumSupportFor() int {
116127func (ssh * supporterStateHandler ) exportAllSupportFor () []slpb.SupportState {
117128 ssh .mu .RLock ()
118129 defer ssh .mu .RUnlock ()
119- supportStates := make ([]slpb.SupportState , len (ssh .supporterState .supportFor ))
130+ supportStates := make ([]slpb.SupportState , 0 , len (ssh .supporterState .supportFor ))
120131 for _ , ss := range ssh .supporterState .supportFor {
121- supportStates = append (supportStates , ss )
132+ supportStates = append (supportStates , ss . SupportState )
122133 }
123134 return supportStates
124135}
@@ -146,13 +157,11 @@ func (ssfu *supporterStateForUpdate) getMeta() slpb.SupporterMeta {
146157 return ssfu .checkedIn .meta
147158}
148159
149- // getSupportFor returns the SupportState from the inProgress view; if not
150- // present, it falls back to the SupportState from the checkedIn view.
160+ // getSupportFor returns the supportState from the inProgress view; if not
161+ // present, it falls back to the supportState from the checkedIn view.
151162// The returned boolean indicates whether the store is present in the supportFor
152163// map; it does NOT indicate whether support is provided.
153- func (ssfu * supporterStateForUpdate ) getSupportFor (
154- storeID slpb.StoreIdent ,
155- ) (slpb.SupportState , bool ) {
164+ func (ssfu * supporterStateForUpdate ) getSupportFor (storeID slpb.StoreIdent ) (supportState , bool ) {
156165 ss , ok := ssfu .inProgress .supportFor [storeID ]
157166 if ! ok {
158167 ss , ok = ssfu .checkedIn .supportFor [storeID ]
@@ -180,7 +189,8 @@ func (ssfu *supporterStateForUpdate) write(ctx context.Context, b storage.Batch)
180189 }
181190 }
182191 for _ , ss := range ssfu .inProgress .supportFor {
183- if err := writeSupportForState (ctx , b , ss ); err != nil {
192+ // Only write the persistent SupportState to disk.
193+ if err := writeSupportForState (ctx , b , ss .SupportState ); err != nil {
184194 return err
185195 }
186196 }
@@ -201,9 +211,9 @@ func (ssh *supporterStateHandler) read(ctx context.Context, r storage.Reader) er
201211 ssh .mu .Lock ()
202212 defer ssh .mu .Unlock ()
203213 ssh .supporterState .meta = meta
204- ssh .supporterState .supportFor = make (map [slpb.StoreIdent ]slpb. SupportState , len (supportFor ))
214+ ssh .supporterState .supportFor = make (map [slpb.StoreIdent ]supportState , len (supportFor ))
205215 for _ , s := range supportFor {
206- ssh .supporterState .supportFor [s .Target ] = s
216+ ssh .supporterState .supportFor [s .Target ] = supportState { SupportState : s }
207217 }
208218 return nil
209219}
@@ -256,12 +266,15 @@ func (ssfu *supporterStateForUpdate) handleHeartbeat(
256266 from := msg .From
257267 ss , ok := ssfu .getSupportFor (from )
258268 if ! ok {
259- ss = slpb.SupportState {Target : from }
269+ ss = supportState { SupportState : slpb.SupportState {Target : from } }
260270 }
261271 ssNew := handleHeartbeat (ss , msg )
272+ assert (ss .lastSupportWithdrawnTime == ssNew .lastSupportWithdrawnTime ,
273+ "lastSupportWithdrawnTime changed on successful heartbeat" ,
274+ )
262275 if ss != ssNew {
263276 ssfu .inProgress .supportFor [from ] = ssNew
264- logSupportForChange (ctx , ss , ssNew )
277+ logSupportForChange (ctx , ss . SupportState , ssNew . SupportState )
265278 }
266279 return slpb.Message {
267280 Type : slpb .MsgHeartbeatResp ,
@@ -274,7 +287,7 @@ func (ssfu *supporterStateForUpdate) handleHeartbeat(
274287
275288// handleHeartbeat contains the core logic for updating the epoch and expiration
276289// of a support requester upon receiving a heartbeat.
277- func handleHeartbeat (ss slpb. SupportState , msg * slpb.Message ) slpb. SupportState {
290+ func handleHeartbeat (ss supportState , msg * slpb.Message ) supportState {
278291 assert (! msg .Expiration .IsEmpty (), "requested support with zero expiration" )
279292 if ss .Epoch == msg .Epoch {
280293 ss .Expiration .Forward (msg .Expiration )
@@ -315,10 +328,10 @@ func (ssfu *supporterStateForUpdate) withdrawSupport(
315328 )
316329 supportWithdrawnForStoreIDs = make (map [roachpb.StoreID ]struct {})
317330 for id , ss := range ssfu .checkedIn .supportFor {
318- ssNew := maybeWithdrawSupport (ss , now )
319- if ss != ssNew {
331+ ssNew , withdrawn := maybeWithdrawSupport (ss , now )
332+ if withdrawn {
320333 ssfu .inProgress .supportFor [id ] = ssNew
321- log .KvExec .Infof (ctx , "withdrew support for %s" , supportChangeStr (ss , ssNew ))
334+ log .KvExec .Infof (ctx , "withdrew support for %s" , supportChangeStr (ss . SupportState , ssNew . SupportState ))
322335 meta := ssfu .getMeta ()
323336 if meta .MaxWithdrawn .Forward (now ) {
324337 ssfu .inProgress .meta = meta
@@ -330,11 +343,15 @@ func (ssfu *supporterStateForUpdate) withdrawSupport(
330343}
331344
332345// maybeWithdrawSupport contains the core logic for updating the epoch and
333- // expiration of a support requester when withdrawing support.
334- func maybeWithdrawSupport (ss slpb.SupportState , now hlc.ClockTimestamp ) slpb.SupportState {
346+ // expiration of a support requester when withdrawing support. If support is
347+ // withdrawn, lastSupportWithdrawnTime is updated to the current timestamp and
348+ // a boolean indicating as such is returned.
349+ func maybeWithdrawSupport (ss supportState , now hlc.ClockTimestamp ) (supportState , bool ) {
335350 if ! ss .Expiration .IsEmpty () && ss .Expiration .LessEq (now .ToTimestamp ()) {
336351 ss .Epoch ++
337352 ss .Expiration = hlc.Timestamp {}
353+ ss .lastSupportWithdrawnTime = now .ToTimestamp ()
354+ return ss , true
338355 }
339- return ss
356+ return ss , false
340357}
0 commit comments