def rivalProposal(): print("rivalProposal") processes = ['alpha', 'beta', 'gamma'] um = UniversalMessenger() m1 = MockMessenger('alpha', processes, um) m2 = MockMessenger('beta', processes, um) m3 = MockMessenger('gamma', processes, um) p1 = Proposer('alpha', processes, m1) p2 = Proposer('beta', processes, m2) p3 = Proposer('gamma', processes, m3) a1 = Acceptor(processes, m1) a2 = Acceptor(processes, m2) a3 = Acceptor(processes, m3) l1 = Learner(processes, m1) l2 = Learner(processes, m2) l3 = Learner(processes, m3) p1.prepare('ABC', 0) a1.promise(um.lastMessageToSite('alpha', 'prepare')) p1.receivePromise(um.lastMessageToSite('alpha', 'promise')) a2.promise(um.lastMessageToSite('beta', 'prepare')) p1.receivePromise(um.lastMessageToSite('alpha', 'promise')) #a3.promise(um.lastMessageToSite('gamma', 'prepare')) #p1.receivePromise(um.lastMessageToSite('alpha', 'promise')) #a1.accept(um.lastMessageToSite('alpha', 'accept')) #a2.accept(um.lastMessageToSite('beta', 'accept')) #a3.accept(um.lastMessageToSite('gamma', 'accept')) p2.prepare( 'XYZ', 0) # A majority of these need to be uncommented for XYZ to be accepted #a1.promise(um.lastMessageToSite('alpha', 'prepare')) #p2.receivePromise(um.lastMessageToSite('beta', 'promise')) a2.promise(um.lastMessageToSite('beta', 'prepare')) p2.receivePromise(um.lastMessageToSite('beta', 'promise')) a3.promise(um.lastMessageToSite('gamma', 'prepare')) p2.receivePromise(um.lastMessageToSite('beta', 'promise')) a1.accept(um.lastMessageToSite('alpha', 'accept')) l1.receiveAccepted(um.lastMessageToSite('alpha', 'accepted')) l2.receiveAccepted(um.lastMessageToSite('beta', 'accepted')) l3.receiveAccepted(um.lastMessageToSite('gamma', 'accepted')) a2.accept(um.lastMessageToSite('beta', 'accept')) l1.receiveAccepted(um.lastMessageToSite('alpha', 'accepted')) l2.receiveAccepted(um.lastMessageToSite('beta', 'accepted')) l3.receiveAccepted(um.lastMessageToSite('gamma', 'accepted')) a3.accept(um.lastMessageToSite('gamma', 'accept')) l1.receiveAccepted(um.lastMessageToSite('alpha', 'accepted')) l2.receiveAccepted(um.lastMessageToSite('beta', 'accepted')) l3.receiveAccepted(um.lastMessageToSite('gamma', 'accepted')) um.printMessages()
def secondProposal(): print("secondProposal") processes = ['alpha', 'beta', 'gamma'] um = UniversalMessenger() m1 = MockMessenger('alpha', processes, um) m2 = MockMessenger('beta', processes, um) m3 = MockMessenger('gamma', processes, um) p1 = Proposer('alpha', processes, m1) p2 = Proposer('beta', processes, m2) p3 = Proposer('gamma', processes, m3) a1 = Acceptor(processes, m1) a2 = Acceptor(processes, m2) a3 = Acceptor(processes, m3) l1 = Learner(processes, m1) l2 = Learner(processes, m2) l3 = Learner(processes, m3) p1.prepare('ABC', 0) a1.promise(um.lastMessageToSite('alpha', 'prepare')) p1.receivePromise(um.lastMessageToSite('alpha', 'promise')) a2.promise(um.lastMessageToSite('beta', 'prepare')) p1.receivePromise(um.lastMessageToSite('alpha', 'promise')) a3.promise(um.lastMessageToSite('gamma', 'prepare')) p1.receivePromise(um.lastMessageToSite('alpha', 'promise')) a1.accept(um.lastMessageToSite('alpha', 'accept')) l1.receiveAccepted(um.lastMessageToSite('alpha', 'accepted')) l2.receiveAccepted(um.lastMessageToSite('beta', 'accepted')) l3.receiveAccepted(um.lastMessageToSite('gamma', 'accepted')) a2.accept(um.lastMessageToSite('beta', 'accept')) l1.receiveAccepted(um.lastMessageToSite('alpha', 'accepted')) l2.receiveAccepted(um.lastMessageToSite('beta', 'accepted')) l3.receiveAccepted(um.lastMessageToSite('gamma', 'accepted')) a3.accept(um.lastMessageToSite('gamma', 'accept')) l1.receiveAccepted(um.lastMessageToSite('alpha', 'accepted')) l2.receiveAccepted(um.lastMessageToSite('beta', 'accepted')) l3.receiveAccepted(um.lastMessageToSite('gamma', 'accepted')) p2.prepare('XYZ', 0) a1.promise(um.lastMessageToSite('alpha', 'prepare')) p2.receivePromise(um.lastMessageToSite('beta', 'promise')) a2.promise(um.lastMessageToSite('beta', 'prepare')) p2.receivePromise(um.lastMessageToSite('beta', 'promise')) a3.promise(um.lastMessageToSite('gamma', 'prepare')) p2.receivePromise(um.lastMessageToSite('beta', 'promise')) um.printMessages()
def server(server_id, config_file='../config/servers.yaml'): server_id = int(server_id) #load config file with open(config_file, 'r') as config_handler: config = yaml.load(config_handler) f = int(config['f']) #the number of failure that can be tolerated state_backup_folder = config['state_backup_folder'] if not os.path.exists(state_backup_folder): call(['mkdir', '-p', state_backup_folder]) num_server = 2 * f + 1 servers_list = { server_idx: config['servers_list'][server_idx] for server_idx in range(num_server) } quorum = num_server / 2 + 1 # load state state_backup = get_state_backup(server_id, state_backup_folder) if not os.path.exists(state_backup): state = dict(view=0, decided_log={}, promised_proposal_id=None, accepted_proposal_id={}, accepted_proposal_val={}, accepted_client_info={}) save_state(state_backup, state) else: MyLogging.info("Recovering server") state = load_state(state_backup) loss_rate = config['msg_drop_rate'] proposer = Proposer(server_id, servers_list, loss_rate) acceptor = Acceptor(server_id, servers_list, state['promised_proposal_id'], state['accepted_proposal_id'], state['accepted_proposal_val'], state['accepted_client_info'], state_backup, loss_rate) learner = Learner(server_id, quorum, state['decided_log'], state_backup, loss_rate) #initialize view. The view will be used for proposal_id for elected leader view = state['view'] num_acceptors = num_server HOST = servers_list[server_id]['host'] PORT = servers_list[server_id]['port'] s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((HOST, PORT)) s.listen(100) #for test case 4 to skip slot x if 'x' in config and config['x'] >= 0: x = int(config['x']) else: x = None if 'num_failed_primary' in config and config['num_failed_primary'] >= 0: num_failed_primary = int(config['num_failed_primary']) else: num_failed_primary = None #for test 4 to specify the server on which the skipped slot occurs server_skip = 0 request_val_queue = collections.deque() client_info_queue = collections.deque() while True: #try to crash if view % num_acceptors == server_id: server_crash(server_id, crash_rate) MyLogging.debug("wait for connection") conn, addr = s.accept() MyLogging.debug('Connection by ' + str(addr)) data = conn.recv(4096 * 2) msg = pickle.loads(data) MyLogging.debug('RCVD: ' + str(msg)) if msg['type'] == 'request': if msg['resend_idx'] != 0: #if this is an resent message, triger view change # save updated state first state = load_state(state_backup) state['view'] = view + 1 save_state(state_backup, state) view += 1 #new leader clears the request queue request_val_queue.clear() client_info_queue.clear() proposer.need_prepare = True MyLogging.debug("change to view %s" % (str(view))) if view % num_acceptors == server_id: #this is leader #testcase 2 and 3 if num_failed_primary is not None and server_id < num_failed_primary: MyLogging.info("force the primary %s to crash" % (str(server_id))) MyLogging.error("server id %s crashes" % (str(server_id))) exit() #testcase 4 if x is not None and x + 1 in learner.decided_log and server_skip == server_id: #server_skip = server_id MyLogging.info('server id %s has learned slot %s' % (str(server_id), str(x + 1))) MyLogging.error("server id %s crashes" % (str(server_id))) exit() request_val_queue.append(msg['request_val']) client_info_queue.append(msg['client_info']) if proposer.need_prepare is True: proposer.prepare(view) else: #directly propose without prepare stage proposal_pack = {} MyLogging.debug("no need to prepare") MyLogging.debug(request_val_queue) for _ in range(len(request_val_queue)): request_val = request_val_queue.popleft() client_info = client_info_queue.popleft() proposal_pack = proposer.addNewRequest( proposal_pack, request_val, client_info) #testcase 4 if x is not None and x in proposal_pack and server_skip == server_id: MyLogging.debug('At slot %s: %s' % (str(x), str(proposal_pack[x]))) MyLogging.debug( 'proposer %s skips slot %s for server_skip %s' % (str(server_id), str(x), str(server_skip))) del proposal_pack[x] proposer.propose(proposal_pack, without_prepare=True) elif msg['type'] == 'promise': proposer.addVote(msg) if proposer.checkQuorumSatisfied() is True: if proposer.need_prepare is True: proposal_pack = proposer.getProposalPack( learner.getDecidedLog()) MyLogging.debug("proposal pack for holes: %s" % (str(proposal_pack))) for _ in range(len(request_val_queue)): request_val = request_val_queue.popleft() client_info = client_info_queue.popleft() proposal_pack = proposer.addNewRequest( proposal_pack, request_val, client_info) #testcase 4 if x is not None and x in proposal_pack and server_skip == server_id: MyLogging.debug('At slot %s: %s' % (str(x), str(proposal_pack[x]))) MyLogging.debug( 'proposer %s skips slot %s for server_skip %s' % (str(server_id), str(x), str(server_skip))) del proposal_pack[x] proposer.propose(proposal_pack) proposer.need_prepare = False elif msg['type'] == 'prepare': # save updated state first state = load_state(state_backup) state['view'] = max(view, msg['proposal_id']) save_state(state_backup, state) view = max(view, msg['proposal_id'] ) # try to catch up with the most recent view MyLogging.debug("change to max view %s" % (str(view))) acceptor.promise(msg) elif msg['type'] == 'propose': acceptor.accept(msg) elif msg['type'] == 'accept': slot_idx = msg['slot_idx'] learner.addVote(msg, slot_idx) if learner.checkQuorumSatisfied(slot_idx) is True: learner.decide(slot_idx) conn.close()