def AppendEntries(command, cluster_node): # AppendEntries(<index>, !<var>) or AppendEntries(<index>, <var>, <value>) log = open("log.txt", 'r+') params = command.getParams() # Need to make sure that the commit index is the same as the leader if cluster_node.commit_index != int(params[0]): # Replicate log and set commit_index return parse.Command("print", ["Failed!"]) # Copy file contents into a string contents = "" for line in log: contents = contents + line # If it should return a value at a specific <var> if command.shouldReturnVal(): # Find start and end indexes for <value> if params[1] not in contents: return parse.Command("print", ["Failed!"]) index = contents.find(params[1]) var = contents[index:index + len(params[1])] start_index = index + len(params[1]) + 1 temp = contents[start_index:len(contents)] end_index = temp.index('\n') + start_index val = contents[start_index:end_index] return parse.Command("print", [val]) else: # New value to be added to the beginning of the file # Edit string and write to the file cluster_node.commit_index += 1 new_contents = params[1] + ':' + params[2] + '\n' for i in range(0, len(contents)): new_contents = new_contents + contents[i] try: log.truncate(0) log.write(new_contents) log.close() except IOError: if command.getCommand() == "LeaderAppend": return parse.Command("print", ["Failed!"]) if command.getCommand() == "LeaderAppend": return parse.Command("print", ["Success!"])
def receiveFromClient(self, conn, addr): threading.Thread(target=self.quitThread, args=(conn,)).start() while not self.shouldEnd: # Get command from follower/client command = parse.Command(None, None, None) try: data = conn.recv(self.cluster_node.BUFFER_SIZE) if not data: continue command = pickle.loads(data) except: break # Returns something to be printed on both leader and followers ret_cmd = process.processCommand(command, self.cluster_node, addr) if ret_cmd: print(ret_cmd.getParams()[0]) conn.send(pickle.dumps(ret_cmd)) # Once leader has finished the operation, all followers must do the same (as long as it is not a retrieval) if not command.shouldReturnVal(): self.cluster_node.broadcast(command) conn.close() self.cluster_node.followers.remove(conn)
def dumpLog(command, cluster_node): # dumpLog(<id>) id = command.getParams()[0] original_id = "" if len(command.getParams()) == 1: command.addParam(cluster_node.IP) original_id = cluster_node.IP else: original_id = command.getParams()[1] if id == cluster_node.IP: log = open("log.txt", 'r') contents = "\n\tMOST RECENT INDEX (TOP)\n" for line in log: contents += line contents += "\n\tOLDEST INDEX (BOTTOM)\n" return parse.Command("print", [contents, original_id]) elif cluster_node.isLeader(): isFollower = False for ip in cluster_node.follower_ips: if ip == id: isFollower = True if isFollower: logRequest = parse.Command("LogRequest", [id, original_id]) cluster_node.broadcast(logRequest) return None else: return parse.Command("print", ["Failed!"]) else: return None
def ClientCommit(command, cluster_node): # ClienCommit(!<var>) or ClientCommit(<var>, <value>) # Process parameters params = command.getParams() if command.shouldReturnVal(): # Broadcast read_entry = parse.Command("AppendEntries", [cluster_node.commit_index, params[0]], True) return AppendEntries(read_entry, cluster_node) elif cluster_node.isLeader(): new_entry = parse.Command( "AppendEntries", [cluster_node.commit_index, params[0], params[1]]) cluster_node.broadcast(new_entry) new_entry = parse.Command( "LeaderAppend", [cluster_node.commit_index, params[0], params[1]]) return AppendEntries(new_entry, cluster_node) else: return None
def run(self): # Initialize incoming TCP connections self.s.bind((self.cluster_node.IP, self.cluster_node.port)) self.cluster_node.port = self.s.getsockname()[1] self.s.listen(5) # number of connections to server print("Connection IP address: ", self.cluster_node.IP) print("Connection opened on port: ", self.s.getsockname()[1]) # Handles new connections until it should end while not self.shouldEnd: # Accept connection conn, addr = self.s.accept() print("Connection from address:", addr) # Log replication for new followers log = open("log.txt", 'r') contents = "" for line in log: contents += line log.close() conn.send(pickle.dumps(parse.Command("log", [contents, str(self.cluster_node.commit_index)]))) # Append new follower to followers self.cluster_node.followers.append(conn) # Handles adding clients and receiving messages add_client_thread = threading.Thread(target=self.receiveFromClient, args=(conn, addr)) add_client_thread.start() add_client_thread.join() conn.close() print("Connection closed")
def run(self): print("gets here") self.s.bind((self.cluster_node.IP, self.cluster_node.port)) election_cmd = parse.Command("election", self.IP, False) self.cluster_node.broadcast(election_cmd)
def write_init(self): self.f.write(BOOTSTRAP_SP) init_cmd = parse.Command("call Sys.init 0") self.write_call(init_cmd)
def heartbeatTimer(self): heartbeat_cmd = parse.Command("heartbeat", self.cluster_node.follower_ips) while not self.shouldEnd: time.sleep(30) # should be 30 seconds self.cluster_node.broadcast(heartbeat_cmd)