def __init__(self, provider: ViewChangerDataProvider, timer: TimerService): self.provider = provider self._timer = timer self.inBox = deque() self.outBox = deque() self.inBoxRouter = Router( (InstanceChange, self.process_instance_change_msg) ) self.instance_changes = InstanceChangeProvider(self.config.OUTDATED_INSTANCE_CHANGES_CHECK_INTERVAL, node_status_db=self.provider.node_status_db) self.previous_view_no = None # Action for _schedule instanceChange messages self.instance_change_action = None # Count of instance change rounds self.instance_change_rounds = 0 # Time for view_change_starting self.start_view_change_ts = 0 # Force periodic view change if enabled in config force_view_change_freq = self.config.ForceViewChangeFreq if force_view_change_freq > 0: RepeatingTimer(self._timer, force_view_change_freq, self.on_master_degradation) # Start periodic freshness check state_freshness_update_interval = self.config.STATE_FRESHNESS_UPDATE_INTERVAL if state_freshness_update_interval > 0: RepeatingTimer(self._timer, state_freshness_update_interval, self.check_freshness)
def __init__(self, provider: ViewChangerDataProvider, timer: TimerService): self.provider = provider self._timer = timer self.pre_vc_strategy = None self._view_no = 0 # type: int self.inBox = deque() self.outBox = deque() self.inBoxRouter = Router( (InstanceChange, self.process_instance_change_msg), (ViewChangeDone, self.process_vchd_msg), (FutureViewChangeDone, self.process_future_view_vchd_msg)) self.instance_changes = InstanceChangeProvider( self.config.OUTDATED_INSTANCE_CHANGES_CHECK_INTERVAL, node_status_db=self.provider.node_status_db) # Tracks if other nodes are indicating that this node is in lower view # than others. Keeps a map of view no to senders # TODO: Consider if sufficient ViewChangeDone for 2 different (and # higher views) are received, should one view change be interrupted in # between. self._next_view_indications = {} self._view_change_in_progress = False self.pre_view_change_in_progress = False self.previous_view_no = None self.previous_master_primary = None self.set_defaults() self.initInsChngThrottling() # Action for _schedule instanceChange messages self.instance_change_action = None # Count of instance change rounds self.instance_change_rounds = 0 # Time for view_change_starting self.start_view_change_ts = 0 # Last successful viewNo. # In some cases view_change process can be uncompleted in time. # In that case we want to know, which viewNo was successful (last completed view_change) self.last_completed_view_no = 0 # Force periodic view change if enabled in config force_view_change_freq = self.config.ForceViewChangeFreq if force_view_change_freq > 0: RepeatingTimer(self._timer, force_view_change_freq, self.on_master_degradation) # Start periodic freshness check state_freshness_update_interval = self.config.STATE_FRESHNESS_UPDATE_INTERVAL if state_freshness_update_interval > 0: RepeatingTimer(self._timer, state_freshness_update_interval, self.check_freshness)
def __init__(self, data: ConsensusSharedData, timer: TimerService, bus: InternalBus, network: ExternalBus, db_manager: DatabaseManager, stasher: StashingRouter, is_master_degraded: Callable[[], bool], metrics: MetricsCollector = NullMetricsCollector()): self._data = data self._timer = timer self._bus = bus self._network = network self._stasher = stasher self._is_master_degraded = is_master_degraded self.metrics = metrics self._config = getConfig() self._instance_changes = \ InstanceChangeProvider(outdated_ic_interval=self._config.OUTDATED_INSTANCE_CHANGES_CHECK_INTERVAL, node_status_db=db_manager.get_store(NODE_STATUS_DB_LABEL), time_provider=timer.get_current_time) self._subscription = Subscription() self._subscription.subscribe(bus, VoteForViewChange, self.process_vote_for_view_change) self._subscription.subscribe(bus, NewViewAccepted, self.process_new_view_accepted) self._subscription.subscribe(stasher, InstanceChange, self.process_instance_change)
def test_fail_update_instance_changes_from_db(instance_change_provider, tconf, node_status_db, time_provider, logsearch): # test updating cache with view without votes node_status_db.iterator = lambda include_value=True: { "3": node_status_db_serializer.serialize(None) }.items() provider = InstanceChangeProvider( tconf.OUTDATED_INSTANCE_CHANGES_CHECK_INTERVAL, node_status_db, time_provider) assert not provider.has_view(3) # test updating cache with Vote with incorrect timestamp format node_status_db.iterator = lambda include_value=True: { "3": node_status_db_serializer.serialize({"voter": ["a", 10.4]}) }.items() logs, _ = logsearch(msgs=[ "InstanceChangeProvider: timestamp in Vote .* : .* - .* must " "be of float or int type" ]) InstanceChangeProvider(tconf.OUTDATED_INSTANCE_CHANGES_CHECK_INTERVAL, node_status_db, time_provider) assert logs # test updating cache with Vote with incorrect reason format node_status_db.iterator = lambda include_value=True: { "3": node_status_db_serializer.serialize({"voter": [5, 10.4]}) }.items() logs, _ = logsearch(msgs=[ "InstanceChangeProvider: reason in Vote .* : .* - .* must " "be of int type" ]) InstanceChangeProvider(tconf.OUTDATED_INSTANCE_CHANGES_CHECK_INTERVAL, node_status_db, time_provider) assert logs # test updating cache with incorrect view_no format node_status_db.iterator = lambda include_value=True: { "a": node_status_db_serializer.serialize({"voter": [5, 25]}) }.items() logs, _ = logsearch( msgs=["InstanceChangeProvider: view_no='.*' " "must be of int type"]) InstanceChangeProvider(tconf.OUTDATED_INSTANCE_CHANGES_CHECK_INTERVAL, node_status_db, time_provider) assert logs
def test_update_instance_changes_in_db(instance_change_provider, tconf, node_status_db, time_provider): frm = "Node1" view_no = 1 msg = InstanceChange(view_no, Suspicions.PRIMARY_DEGRADED.code) assert not instance_change_provider.has_view(view_no) assert not instance_change_provider.has_inst_chng_from(view_no, frm) assert not _is_view_in_db(view_no, instance_change_provider) instance_change_provider.add_vote(msg, frm) assert instance_change_provider.has_view(view_no) assert instance_change_provider.has_inst_chng_from(view_no, frm) assert _is_view_in_db(view_no, instance_change_provider) instance_change_provider._node_status_db.close() assert instance_change_provider._node_status_db.closed instance_change_provider._node_status_db.open() new_instance_change_provider = InstanceChangeProvider( tconf.OUTDATED_INSTANCE_CHANGES_CHECK_INTERVAL, node_status_db, time_provider) assert new_instance_change_provider.has_view(view_no) assert new_instance_change_provider.has_inst_chng_from(view_no, frm)
def instance_change_provider(tconf, node_status_db, time_provider): return InstanceChangeProvider( tconf.OUTDATED_INSTANCE_CHANGES_CHECK_INTERVAL, node_status_db, time_provider)