def read_via_policy(self, name): """ This method returns a version from either the log or the cache according to the read policy set on the replica server as follows: - COMMIT: return the latest commited version (ignoring cache) - LATEST: return latest version in log or in cache This method raises an exception on bad read policies. """ # If the policy is read committed, return the latest committed version if self.read_policy == ReadPolicy.COMMIT: return self.log.get_latest_commit(name) # If the policy is latest, read the latest and compare to cache. if self.read_policy == ReadPolicy.LATEST: # Get the latest version from the log (committed or not) version = self.log.get_latest_version(name) # If name in the cache and the cache version is greater, return it. if name in self.cache and version is not None: if self.cache[name] > version: return self.cache[name] # Return the latest version return version # If we've reached this point, we don't know what to do! raise SimulationException("Unknown read policy!")
def update(self, replica, commit=False, forte=False, **kwargs): """ The update method allows a Raft leader to now also update the forte on this particular instance version. The method does a quick sanity check just to make sure only the leader can do this, then happily performs the forte update. """ if forte: if not replica.consistency in { Consistency.STRONG, Consistency.RAFT }: raise SimulationException( "{} attempting to set forte with consistency {}".format( replica, replica.consistency)) if not replica.state == State.LEADER: raise SimulationException( "{} attempting to set forte in state {}".format( replica, replica.state)) self.forte = self.increment_forte() super(FederatedVersion, self).update(replica, commit, **kwargs)
def on_state_change(self): """ Setting the state decides how the Tag node will interact. """ # Do state specific tag modifications if self.state == State.READY: self.votes = None self.tag = None # Remove owner state self.nextIndex = None self.matchIndex = None # Also interrupt the heartbeat if self.heartbeat: self.heartbeat.stop() elif self.state == State.TAGGING: # Convert to tag acquisition/release self.epoch += 1 # Create election and vote for self self.votes = Election([node.id for node in self.quorum()]) self.votes.vote(self.id) # Also interrupt the heartbeat if self.heartbeat: self.heartbeat.stop() elif self.state == State.OWNER: # Create the next index and match index self.nextIndex = { node: { obj: self.log[obj].lastApplied + 1 for obj in self.view[self] } for node in self.neighbors() } self.matchIndex = { node: {obj: 0 for obj in self.view[self]} for node in self.neighbors() } else: raise SimulationException( "Unknown Tag Replica State: {!r} set on {}".format( state, self))
def get_leader_node(self): """ Searches for the leader amongst the neighbors. Raises an exception if there are multiple leaders, which is an extreme edge case. """ leaders = [ node for node in self.quorum() if node.state == State.LEADER ] if len(leaders) > 1: raise SimulationException("MutipleLeaders?!") elif len(leaders) < 1: return None else: return leaders[0]
def run(self): """ Implements the Raft consensus protocol and elections. """ while True: if self.state in {State.FOLLOWER, State.CANDIDATE}: yield self.timeout.start() elif self.state == State.LEADER: yield self.heartbeat.start() else: raise SimulationException( "Unknown Raft State: {!r} on {}".format(self.state, self) )
def on_state_change(self): """ Does the same stuff as super, but also - if leader; starts the anti entropy interval to do gossiping. """ super(FloatedRaftReplica, self).on_state_change() if self.state in (State.FOLLOWER, State.CANDIDATE): if hasattr(self, 'ae_timer') and self.ae_timer is not None: # Cancel the anti-entropy timer. self.ae_timer.stop() self.ae_timer = None elif self.state == State.LEADER: self.ae_timer = Timer(self.env, self.ae_delay, self.gossip) self.ae_timer.start() elif self.state == State.READY: # This happens on the call to super, just ignore for now. pass else: raise SimulationException( "Unknown Floating Raft State: {!r} set on {}".format( self.state, self))
def on_state_change(self): """ When the state on a replica changes the internal state of the replica must also change, particularly the properties that define how the node interacts with RPC messages and client reads/writes. """ if self.state in (State.FOLLOWER, State.CANDIDATE): self.votedFor = None self.nextIndex = None self.matchIndex = None elif self.state == State.CANDIDATE: pass elif self.state == State.LEADER: self.nextIndex = {node: self.log.lastApplied + 1 for node in self.quorum() if node != self} self.matchIndex = {node: 0 for node in self.quorum() if node != self} elif self.state == State.READY: # This happens on the call to super, just ignore for now. pass else: raise SimulationException( "Unknown Raft State: {!r} set on {}".format(self.state, self) )
def select_anti_entropy_neighbor(self): """ This is a No-Op for this type of replica. """ raise SimulationException( "Stentor replicas do not have a single neighbor selection policy.")
def run(self): raise SimulationException( "Timers cannot be run, they should be started and stopped!")