@@ -311,7 +311,7 @@ def _observe_leader(self):
311311 cluster = self .dcs .get_cluster ()
312312
313313 if cluster .is_unlocked ():
314- logger .info ("Multisite has no leader" )
314+ logger .info ("Multisite has no leader because cluster is unlocked " )
315315 self ._disconnected_operation ()
316316 else :
317317 # There is a leader cluster
@@ -328,17 +328,39 @@ def _observe_leader(self):
328328 logger .warning (f"Error accessing multisite DCS: { e } " )
329329
330330 def _update_history (self , cluster : Cluster ):
331- if cluster .history and cluster .history .lines and isinstance (cluster .history .lines [0 ], dict ):
332- self .site_switches = cluster .history .lines [0 ].get ('switches' )
331+ # The history lines are of type dcs._HistoryTuple to match normal timeline history. The data stored by tuple
332+ # index:
333+ # 0: site switch count
334+ # 1: 0 (constant) TODO: maybe store the LSN when the switch happened - in that case it will match the LSN of the
335+ # timeline switch
336+ # 2: site switch timestamp
337+ # 3: new leader site name
338+ #
339+ # The full history is a list of the tuples described above, the latest one being the last element.
340+ # The older implementation was a single item list of dict, we replace it with the list of tuples.
341+ # TODO: once we are sure there are no such instances, the dict references can be removed alongside the ugly
342+ # pyright repellant comments.
343+
344+ if cluster .history and cluster .history .lines :
345+ if isinstance (cluster .history .lines [0 ], dict ): # older implementation, will get replaced by this update
346+ self .site_switches = cluster .history .lines [0 ].get ('switches' ) # noqa: E501 # pyright: ignore [reportUnknownMemberType]
347+ else :
348+ self .site_switches = cluster .history .lines [- 1 ][0 ]
333349
334350 if self ._has_leader :
335- if cluster .history and cluster .history .lines and isinstance (cluster .history .lines [0 ], dict ):
336- history_state = cluster .history .lines [0 ]
337- if history_state .get ('last_leader' ) != self .name :
338- new_state = [{'last_leader' : self .name , 'switches' : history_state .get ('switches' , 0 ) + 1 }]
339- self .dcs .set_history_value (json .dumps (new_state ))
340- else :
341- self .dcs .set_history_value (json .dumps ([{'last_leader' : self .name , 'switches' : 0 }]))
351+ if cluster .history and cluster .history .lines :
352+ if isinstance (cluster .history .lines [0 ], dict ):
353+ history_state = cluster .history .lines [0 ]
354+ if history_state .get ('last_leader' ) != self .name : # pyright: ignore [reportUnknownMemberType]
355+ new_state = (history_state .get ('switches' , 0 ) + 1 , 0 , '' , self .name ) # noqa: E501 # pyright: ignore [reportUnknownMemberType, reportUnknownVariableType]
356+ self .dcs .set_history_value (json .dumps (new_state )) # FIXME: append instead
357+ else :
358+ history_state = cluster .history .lines [- 1 ]
359+ if len (history_state ) > 3 and history_state [3 ] != self .name :
360+ new_state = (history_state [0 ] + 1 , 0 , '' , self .name )
361+ self .dcs .set_history_value (json .dumps (cluster .history .lines .append (new_state )))
362+ else : # no history yet, set initial item
363+ self .dcs .set_history_value (json .dumps ([(0 , 0 , '' , self .name )])) # FIXME: append to list instead
342364
343365 def _check_for_failover (self , cluster : Cluster ):
344366 if cluster .failover and cluster .failover .target_site :
0 commit comments