def accept_value(self, leaderNum, req_id, seqNum, value): # leaderNum, value # TODO: could be bug to not have greather than or equal... # int(seqNum) not in self.seq_dict:# #if int(leaderNum) >= self.selected_leaderNum and int(seqNum) > int(self.accepted_seqNum): seqNum = int(seqNum) if int(leaderNum) >= self.selected_leaderNum and int( seqNum ) not in self.locked_seq_nums: # and int(seqNum) not in self.seq_dict: #DREW DEBUG? DOES TIS NEED TO BE HERE? # D2 #if req_id in self.req_dict and self.req_dict[req_id] != int(seqNum): # if you already gave this req_id a different seq_num, send a NOP for this seq_num # self.learner.acceptValue(leaderNum, self.idnum, "NOP", seqNum, "NOP") # self.send_value(leaderNum, "NOP", seqNum, "NOP") #else: # else accept as usual self.accepted_lastVal = value self.accepted_req_id = req_id self.accepted_seqNum = seqNum self.seq_dict[int(seqNum)] = (req_id, value) self.locked_seq_nums.add(int(seqNum)) self.learner.acceptValue(leaderNum, self.idnum, req_id, seqNum, value) self.send_value(leaderNum, req_id, seqNum, value) #self.req_dict[req_id] = int(seqNum) #D2 else: printd( "Acceptor {} did not accept value with leaderNum = {} and sequence number = {}, while message has been proposed from leaderNum: {} with seq_number {}" .format(self.idnum, self.selected_leaderNum, self.accepted_seqNum, leaderNum, seqNum))
def acceptRequest( self, origin_socket, client_name, client_seq_number, value ): # value, seq_number, seq_number_override=-1): self.client_name, self.client_seq_number, value self.value = value req_id = str(client_name) + '-' + str(client_seq_number) if self.am_leader == True: #if ( (client_name,client_seq_number) not in self.request_history ): # if you've never seen this client_name, client_seq_num pair, it is a new request self.seq_number += 1 if self.seq_number in self.skips: # skip logic: set up leader 0 to skip seq_num 3, then be killed on seq_num 5 print("\nMANUALLY SKIPPING SEQ_NUM {}".format(self.seq_number)) self.seq_number += 1 msg = str(self.leaderNum) msg += "," + req_id msg += "," + str(self.seq_number) msg += "," + str(self.value) full_msg = str(MessageType.COMMAND.value) + ":" + msg printd("Leader " + str(self.leaderNum) + "'s sequence number is " + str(self.seq_number)) self.acceptor.accept_value( self.leaderNum, req_id, self.seq_number, self.value) # We should also accept a value locally Messenger.broadcast_message(self.socket_connections_list, full_msg) printd("Request accepted on replica {} (leader number: {})".format( str(self.idnum), str(self.leaderNum)))
def execute_command (self, command): seq_number = command[0] value = command[1] req_id = command[2] self.add_msg_to_chat_log(seq_number, value, req_id) self.last_executed_seq_number = max(self.last_executed_seq_number,int(seq_number)) printd(str(self.idnum) + " EXECUTES COMMAND " + str(command))
def setup_server(self, numb_replicas): i = 0 while i < numb_replicas: # We know we should accept connections from all other replicas (clientsocket, address) = self.serversocket.accept() self.connections_list.append(clientsocket) printd( str(self.idnum) + " Accepted connection " + str(clientsocket.getsockname())) i += 1 printd("Server is set up for " + str(self.idnum))
def reply_to_client (self, req_id, value): if req_id == "NOP" or req_id == "NONE": return # no client to reply to client_name, client_seq_number = req_id.split('-') if client_name in self.client_mapping: # This client name must be in the client mapping clientsock = self.client_mapping[client_name] printd("Responding to client {} with client_seq_number {}.".format(client_name, client_seq_number)) Messenger.send_message(clientsock, req_id) else: raise RuntimeError("This client name: {}, is not in our mapping for replica {}.".format(client_name, self.idnum))
def recv_message(aSocket): try: msg_size = recv_header(aSocket) chunk = aSocket.recv(msg_size) if chunk == '': raise RuntimeError("Receiving message failed") return chunk except (SocketError, ValueError) as e: printd( "Socket error in receive but should be no problem if you're killing a process" ) return ''
def wait_for_message(self): while self.active: # Should just continue to wait for messages rd, wd, ed = select.select(self.connections_list, [], [], (self.timeout * int(self.idnum)) + self.timeout) if len(rd) == 0: # We haven't received a message in a while... printd("Creating a new proposer on replica " + str(self.idnum)) self.initialize_proposer() # Handle received messages for s in rd: self.recv_message(s)
def wait_for_client_connections(self): while 1: (clientsock, address) = self.serversocket.accept() printd("Accept new client on socket " + str(clientsock.getsockname())) # Receive clients name and add it to learners name->socket mapping clientname = Messenger.recv_message(clientsock) printd("Replica {} received connection to client {}.".format( self.idnum, clientname)) self.learner.add_client(clientname, clientsock) ct = threading.Thread(target=self.client_thread, args=(clientsock, )) ct.start()
def send_message(aSocket, msg): try: if not should_drop_message(): header = '%8s' % len(msg) sent = aSocket.send(header + msg) #printd("socket {} sent msg: {} to: {}".format(socket.getsockname(),msg, socket.getpeername())) if sent == 0: raise RuntimeError("Send message failed") else: printd("Dropped message ".upper() + str(msg)) except SocketError as e: printd( "Socket error in send but should be no problem if you're killing a process" ) return ''
def acceptValue (self, leaderNum, idnum, req_id, seq_number, value): seq = int(seq_number) if seq > self.last_executed_seq_number:# or req_id == "NOP": # Else we should ignore self.seq_dict[seq].add(int(idnum)) # We've now seen one of these values if len(self.seq_dict[seq]) == self.majority_numb: printd(str(self.idnum) + " has majority for value at {} of {} (last exec seq num = {})".format(seq_number,str(value),self.last_executed_seq_number)) self.reply_to_client(req_id, value) # so we can go ahead and reply to the client self.add_and_execute_seq_command(seq, value, req_id) del self.seq_dict[seq] return True else: printd("{} cannot execute for {},{} because we've only seen messages from{}.".format(self.idnum, seq_number, value, self.seq_dict[seq])) return False
def operate (self, num_messages, manual_messages): printd("Client {} is operating".format(self.client_name)) for i in range(num_messages): if manual_messages: msg = raw_input("What is Client {}'s msg? ".format(self.client_name)) else: msg = self.generate_msg_text() self.send_message(str(msg))#self.client_seq_number) + ":" + msg) recvd_msg = str(self.recv_message()) printd("Client received message {}.".format(recvd_msg)) time.sleep(.1) # after completion, wait for the os to shut off client while not False: time.sleep(1)
def get_value_at_seq_number(self, missing_seq_number): missing_seq_number = int(missing_seq_number) if missing_seq_number in self.seq_dict.keys(): printd( "Replica {}'s acceptor is sending value {} for sequence number {}." .format(self.idnum, self.seq_dict[missing_seq_number][1], missing_seq_number)) seq_number_found = "True" missing_req_id = self.seq_dict[missing_seq_number][0] missing_value = self.seq_dict[missing_seq_number][1] else: printd("Replica {}'s accpetor is also behind sequence number {}.". format(self.idnum, missing_seq_number)) seq_number_found = "False" missing_req_id = "NONE" missing_value = '' self.locked_seq_nums.add(int(missing_seq_number)) return (seq_number_found, missing_req_id, missing_value)
def __init__(self, idnum, ip, port, server_pairs, semaphore, test_cases, proposer=False): self.idnum = idnum self.ip = ip self.port = int(port) self.semaphore = semaphore # This semaphore is shared with all processes to wait till all connections are made self.num_replicas = len(server_pairs) self.majority = (len(server_pairs) // 2) + 1 # interger division rounds down, so add one self.other_replicas = [ x for x in server_pairs if x != (ip, str(port)) ] # List of tuples (ip, port) printd("\nREPLICA {}\nServer Pairs: {}\nOther Replicas: {}".format( self.idnum, server_pairs, self.other_replicas)) self.learner = Learner.Learner(self.num_replicas, self.majority, self.idnum) self.acceptor = Acceptor.Acceptor(self.idnum, self.learner) self.learner.set_acceptor(self.acceptor) # This is nauseating... self.proposer = None self.should_kill = False self.skips = [] self.kills = [] for case in test_cases: if case[0] == "kill": # if kill case active, put the seq_num into kills list self.kills.append(case[1]) if case[0] == "skip": # if skip test case active, put the seq_num into skips list self.skips.append(case[1]) self.kill_next_round = False
def acceptLeader(self, newLeaderNum, socket): # send YOU_ARE_LEADER to proposer with seqNum, accepted_lastVal, and selected_leaderNum # We must only promise to follow leaders with leader numbers higher than our current leader if int(newLeaderNum) > self.selected_leaderNum: self.selected_leaderNum = int(newLeaderNum) printd("Replica " + str(self.idnum) + " accepts leader number {}".format(newLeaderNum)) msg = "{}:{},{},{},{},{}".format(MessageType.YOU_ARE_LEADER.value, self.selected_leaderNum, self.idnum, self.accepted_req_id, self.accepted_seqNum, self.accepted_lastVal) else: msg = "{}:{},{}".format(MessageType.NACK.value, self.selected_leaderNum, self.idnum) printd("Not a high enough leader id {} because our current id {}.". format(newLeaderNum, self.selected_leaderNum)) Messenger.send_message(socket, msg)
def send_iamleader_message(self): self.follower_collection = [] # need to add its own acceptor to collection self.followers = set() self.followers.add(self.idnum) # Let's include ourselves self.am_leader = False if self.acceptor.selected_leaderNum > self.leaderNum: self.leaderNum = self.acceptor.leaderNum self.value = self.acceptor.accepted_lastVal else: self.acceptor.selected_leaderNum = self.leaderNum printd("Sending message with leader value " + str(self.leaderNum)) full_msg = str(MessageType.I_AM_LEADER.value) + ":" + str( self.leaderNum) if self.socket_connections_list: Messenger.broadcast_message(self.socket_connections_list, full_msg) else: raise RuntimeError( "Socket connections list has not been initialized for the proposer" )
def try_to_execute_commands (self): if not self.commands_to_execute.empty() and self.last_executed_seq_number + 1 < int(self.commands_to_execute.queue[0][0]): printd("Replica {} sending catchup because it's missing {}.".format(self.idnum, self.last_executed_seq_number + 1).upper()) (seq_number_found, missing_req_id, missing_value) = self.acceptor.get_value_at_seq_number(self.last_executed_seq_number + 1) self.fill_missing_value(seq_number_found, self.idnum, missing_req_id, self.last_executed_seq_number + 1, missing_value) if self.proposer: self.proposer.note_missing_value(seq_number_found, self.idnum, self.last_executed_seq_number + 1 ) else: printd("NO PROPOSER FOR " + str(self.idnum)) msg = "{}:{}".format(MessageType.CATCHUP.value, self.last_executed_seq_number + 1) Messenger.broadcast_message (self.connections_list, msg) # keep track of how many times you request catchup. After so many, timeout if self.last_executed_seq_number + 1 in self.catchup_requests_count: self.catchup_requests_count[self.last_executed_seq_number + 1] += 1 else: self.catchup_requests_count[self.last_executed_seq_number + 1] = 1 printd("CATCHUP ATTEMPT COUNT: {}".format(self.catchup_requests_count[self.last_executed_seq_number + 1])) return # Convoluted way to peek at PriorityQueue while not self.commands_to_execute.empty() and int(self.commands_to_execute.queue[0][0]) == self.last_executed_seq_number + 1: command = self.commands_to_execute.get() self.execute_command(command)
def recv_message (self): while 1: rd, wd, ed = select.select(self.connection_sockets, [], [], self.client_timeout) if len(rd) == 0: # Haven't received a message in a while... printd("Client {} timed-out and is resending {}." .format(self.client_name, self.msg)) Messenger.broadcast_message(self.connection_sockets, self.msg) # Handle received messages for s in rd: message = Messenger.recv_message(s) if int(message.split('-')[1]) < int(self.client_seq_number): # Only should accept one message back pass elif message is not '': self.client_seq_number += 1 # move on to next client sequence number and next command self.msg = None return message else: # We got a socket disconnection from one of our replicas which means its kaputs for good... self.connection_sockets.remove(s)
def send_value_at_seq_number(self, socket, missing_seq_number): missing_seq_number = int(missing_seq_number) if missing_seq_number in self.seq_dict.keys(): printd( "Replica {}'s acceptor is sending value {} for sequence number {}." .format(self.idnum, self.seq_dict[missing_seq_number], missing_seq_number)) seq_number_found = "True" missing_req_id = self.seq_dict[missing_seq_number][0] missing_value = self.seq_dict[missing_seq_number][1] else: printd("Replica {}'s acceptor is also behind sequence number {}.". format(self.idnum, missing_seq_number)) seq_number_found = "False" missing_req_id = "NONE" missing_value = '' msg = "{}:{},{},{},{},{}".format(MessageType.MISSING_VALUE.value, seq_number_found, self.idnum, missing_req_id, missing_seq_number, missing_value) #Messenger.broadcast_message(self.connections_list, msg) Messenger.send_message(socket, msg) self.locked_seq_nums.add(int(missing_seq_number))
def fill_missing_value (self, seq_number_found, acceptor_id, missing_req_id, missing_seq_number, missing_value): #if missing_seq_number in self.missing_vals_of_learners: # if we have not already resolved this issue missing_seq_number = int(missing_seq_number) if missing_req_id not in self.prev_leader_nums[missing_seq_number]: self.prev_leader_nums[missing_seq_number][missing_req_id] = set() self.prev_leader_nums[missing_seq_number][missing_req_id].add(acceptor_id) printd("{} IN MISSING VALUE, NUM UNIQUE REQ_IDS = {}".format(self.idnum,len(self.prev_leader_nums[missing_seq_number]))) if missing_seq_number in self.prev_leader_nums: # do not need to iterate through req_ids. In this call, only the current req_id could have attained majority #for i in range(len(self.prev_leader_nums[missing_seq_number])): # iterate through each unique req_id # if i not in self.prev_leader_nums[missing_seq_number]: # continue sum_of_votes = 0 for i in self.prev_leader_nums[missing_seq_number].values(): sum_of_votes += len(i) printd("{} has {} votes for req_id: {} at seq_num: {} (total num votes = {})".format(self.idnum,len(self.prev_leader_nums[missing_seq_number][missing_req_id]),missing_req_id,missing_seq_number,sum_of_votes)) if len(self.prev_leader_nums[missing_seq_number][missing_req_id]) == self.majority_numb: # if this seq_num, req_id combo has majority value = missing_value #max(self.prev_leader_nums[missing_seq_number], key=itemgetter(0))[1] del self.prev_leader_nums[missing_seq_number] if missing_seq_number > self.last_executed_seq_number and self.commands_to_execute.queue and missing_seq_number < int(self.commands_to_execute.queue[0][0]): # ignore previous messages #self.chat_log[missing_seq_number] = missing_value # DREW: why is this the case? The last executed command shouldn't change, right? # #self.last_executed_seq_number = missing_seq_number # + 1 #del self.missing_vals_of_learners[missing_seq_number] printd("A different learner had the missing value. Fixing internal to the learners") if seq_number_found == "True": self.add_and_execute_seq_command(missing_seq_number, value, missing_req_id) else: self.add_and_execute_seq_command(missing_seq_number, "NOP5", "NOP") #print("Defaulted to NOP when seq_num = {}, val = {}, and req_id ={}".format(missing_seq_number, value, missing_req_id)) #self.commands_to_execute.put((missing_seq_number, value, "NONE")) #self.try_to_execute_commands() # Now try to process commands again else: # need to check if majority impossible. If so, take NOP sum_of_votes = 0 for i in self.prev_leader_nums[missing_seq_number].values(): sum_of_votes += len(i) # if this is true, it is unable to achieve majority and all learners should execute NOP (catchup_requests_count acts as timeout) if sum_of_votes >= self.majority_numb and self.catchup_requests_count[missing_seq_number] > 20: #print("Catchup attempts: {}".format(self.catchup_requests_count[missing_seq_number])) self.add_and_execute_seq_command(missing_seq_number, "NOP6", "NOP") '''
def note_missing_value(self, seq_number_found, learner_id, missing_seq_number): printd("NOTE MISSING VALUE {}".format(missing_seq_number)) missing_seq_number = int(missing_seq_number) learner_id = int(learner_id) self.missing_vals_of_learners[missing_seq_number].add(learner_id) if seq_number_found == "True": self.missing_vals_of_learners[missing_seq_number] = set() return elif seq_number_found == "False": printd(self.missing_vals_of_learners[missing_seq_number]) if len(self.missing_vals_of_learners[missing_seq_number] ) >= self.majority_numb: # Count ourselves too self.acceptor.accept_value( self.leaderNum, "NOP-SHOULD NOT HAPPEN", missing_seq_number, "NOP-SHOULD NOT HAPPEN" ) # We should also accept a value locally if int(missing_seq_number) == self.seq_number + 1: printd("INCREMENTING SEQ NUMBER IN PROPOSER") self.seq_number += 1 full_msg = str( MessageType.COMMAND.value) + ":{},NOP,{},NOP1".format( self.leaderNum, missing_seq_number) Messenger.broadcast_message(self.socket_connections_list, full_msg) self.missing_vals_of_learners[missing_seq_number] = set() printd("Leader num {} is proposing NOP at seq_num {}".format( self.leaderNum, missing_seq_number)) else: raise RuntimeError( "Error: invalid seq_number_found arg for MISSING_VALUE command" )
def connect_to_replicas(self, replicas): i = 0 printd( str(self.idnum) + " will connect to replicas: " + str(replicas) + "- len = " + str(len(replicas))) for replica in replicas: connected = False while not connected: try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect( (replica[0], int(replica[1]))) # Connect to (ip, port) connected = True except Exception as e: time.sleep(0.1) # yield thread printd( str(self.idnum) + " successfuly connected on (ip, port) " + str(replica)) self.connections_list.append(s) printd( str(len(replicas)) + " connections set up for " + str(self.idnum))
'--replicas', help='The pairs of all replicas already in the system') args = parser.parse_args() if args.mode == 'manual': man_mode = True else: # default or automatic mode man_mode = False if args.number_messages: # use config file num_messages = int(args.number_messages) else: # default number of messages is 50 num_messages = 50 if args.replicas: config = Config(None, 1, args.replicas, None) else: raise RuntimeError("No replicas provided to the client") printd("Client server pairs:") printd(config.server_pairs) printd("client name: " + args.client_name) client1 = Client(config.server_pairs, args.client_name) client1.connect_to_all_replicas( ) # Connect to all replicas even if they don't have a proposer yet time.sleep(2) client1.operate(num_messages, man_mode)
def newFollower(self, prev_leaderNum, acceptor_id, req_id, seq_number, last_value): self.follower_collection.append( (int(prev_leaderNum), str(req_id), int(seq_number), str(last_value))) # add follower info to collection if not self.am_leader and acceptor_id not in self.followers: # if not leader self.followers.add( acceptor_id) # We have another follower who's joined us if len( self.followers ) == self.majority_numb: # time to become leader since we have enough followers self.am_leader = True self.seq_number = int(seq_number) # do not repeat manual kills if int(seq_number) in self.kills: self.kills.remove(int(seq_number)) if int(seq_number) + 1 in self.kills: self.kills.remove(int(seq_number) + 1) # need to decide most relavant last value. # find follower with highest prevLeaderNum. Break ties with seq_num, then val. max_last_follower = [-1, ".-.", -1, ''] max_prevLeader = -1 max_prevSeqNum = -1 max_prevVal = '' for follower in self.follower_collection: if follower[0] > max_last_follower[ 0]: # if prev_leaderNum > max_prevLeader max_last_follower = follower continue if follower[0] == max_last_follower[ 0] and follower[2] > max_last_follower[2]: max_last_follower = follower continue if follower[0] == max_last_follower[0] and follower[ 2] == max_last_follower[ 2] and follower[3] > max_last_follower[3]: max_last_follower = follower continue # As first order of business as new leader, broadcast the most recent/relavant message you got back from accepts if (int(max_last_follower[0]) != -1 and int(max_last_follower[2]) != -1): # do not repeat manual kills self.seq_number = max_last_follower[2] - 1 if int(self.seq_number) in self.kills: self.kills.remove(int(self.seq_number)) if int(self.seq_number) + 1 in self.kills: self.kills.remove(int(self.seq_number + 1)) n_client_name = max_last_follower[1].split('-')[0] n_client_seq_num = max_last_follower[1].split('-')[1] n_val = max_last_follower[3] self.acceptRequest(None, n_client_name, n_client_seq_num, n_val) printd( "Replica {} just became the leader with value = {}, sequence number = {}, req_id = {}" .format(self.idnum, n_val, self.seq_number, max_last_follower[1])) else: printd( "Replica {} just became the leader with default values" .format(self.idnum)) else: printd(str(self.idnum) + " was already the leader!")
def send_message (self, value): self.msg = "{}:{},{},{}".format(MessageType.REQUEST.value, self.client_name, self.client_seq_number, value) Messenger.broadcast_message(self.connection_sockets, self.msg) #Messenger.send_message(self.connection_socket, full_msg) printd("Client {} sent message to all replicas with value {}".format(self.client_name,str(value)))
description="Initialize a replica for paxos based chat service") parser.add_argument('-f', '--tolerated_faults', help='Total number of tolerated faults') parser.add_argument('-i', '--rep_id', help='Unique ID of this replica') parser.add_argument('-r', '--replicas', help='The pairs of all replicas already in the system') parser.add_argument('-t', '--tests', help="Message loss and other test cases to perform") args = parser.parse_args() if args.tolerated_faults: # use config file printd("tolerated_faults = " + args.tolerated_faults) tolerated_faults = int(args.tolerated_faults) if args.rep_id: printd("rep_id = " + args.rep_id) rep_id = int(args.rep_id) if args.replicas: config = Config(None, tolerated_faults, args.replicas, args.tests) rep_ip = config.server_pairs[rep_id][0] rep_port = int(config.server_pairs[rep_id][1]) else: # if no replicas or given config = Config(None, tolerated_faults, None, args.tests) rep_ip = "127.0.0.1" rep_port = 4003
def recv_message(self, origin_socket): if self.active: msg = Messenger.recv_message(origin_socket) printd("Message is " + str(msg)) cmd, info = msg.split(":", 1) args = info.split(",") if cmd != MessageType.HEARTBEAT.value: printd("Replica: {} received cmd = {}, info={}".format( self.idnum, MessageType(cmd).name, info)) if MessageType( cmd ).name == "REQUEST" and self.proposer and self.proposer.am_leader: printd("...and {} thinks its leader".format(self.idnum)) if cmd == MessageType.REQUEST.value: # from: Client # to: Proposer # args: client_name, client_seqnum, value # TODO: definite bug when there's multiple clients but for now we'll leave it if self.proposer: self.proposer.acceptRequest(origin_socket, args[0], args[1], args[2]) # printd("Received request message") elif cmd == MessageType.I_AM_LEADER.value: # from: Proposer # to: Acceptor # args: leaderNum self.acceptor.acceptLeader(args[0], origin_socket) elif cmd == MessageType.YOU_ARE_LEADER.value: # from: Acceptor # to: Proposer # args: prev_leaderNum, idnum, req_id, seq_number, current value #printd("Received You are Leader message") if not self.proposer: raise RuntimeError( "Non-proposer recieved YOU_ARE_LEADER msg") if self.proposer: self.proposer.newFollower(args[0], args[1], args[2], args[3], args[4]) elif cmd == MessageType.COMMAND.value: # acceptor should decide to accept leader command or not, then broadcast accept message to all learners # from: Proposer # to: Acceptor # args: leaderNum, req_id, seqNum, value self.acceptor.accept_value(args[0], args[1], args[2], args[3]) printd("Received command message to replica id " + str(self.idnum) + " has leader num " + str(int(self.acceptor.selected_leaderNum))) elif cmd == MessageType.ACCEPT.value: # Acceptor should now send message # from: Acceptor # to: Learner # info: leaderNum, idnum, req_id, sequence number, value #printd(str(self.idnum) + " sending accept message to learner with args " + str(args[0]) + " : " + str(args[1])) accepted = self.learner.acceptValue( args[0], args[1], args[2], args[3], args[4]) # True == majority achieved; False == no majority if self.proposer and self.proposer.am_leader and self.proposer.seq_number == int( args[3]) and int(args[3]) + 1 in self.kills: self.kill_next_round = True this_is_a_kill = (int(args[3]) in self.kills) and self.kill_next_round if ( accepted == True and self.proposer and self.proposer.am_leader and (int(args[3]) in self.kills or (int(args[3]) - 1 in self.skips)) ): #accepted == True and self.proposer and ( this_is_a_kill or (int(args[3])-1 in self.skips)) ): # This is just a test of killing the primary again and again if int(args[3]) in self.kills: self.kills.remove(int(args[3])) self.kill_next_round = False if int(args[3]) - 1 in self.skips: self.skips.remove(int(args[3]) - 1) print("\nMANUALLY KILLING REPLICA " + str(self.idnum) + ' at sequence number {}\n'.format(args[3])) self.active = False elif cmd == MessageType.NACK.value: # from: Acceptor # to: Proposer # info: highest_leader_num, idnum self.proposer.set_leader_num(args[0], args[1]) elif cmd == MessageType.CATCHUP.value: # from: Learner # to: Other learners # info: missing_seq_number self.acceptor.send_value_at_seq_number(origin_socket, args[0]) #self.learner.send_value_at_seq_number(origin_socket, args[0]) elif cmd == MessageType.MISSING_VALUE.value: # from: Other learners # to : Learner # info: seq_number_found, self.idnum, missing_req_id, missing_seq_number, missing_value self.learner.fill_missing_value(args[0], args[1], args[2], args[3], args[4]) if self.proposer: self.proposer.note_missing_value(args[0], args[1], args[3]) elif cmd == MessageType.HEARTBEAT.value: # Just a HEARTBEAT pass else: printd("The replica " + str(self.idnum) + " did not recognize the message " + str(cmd))