def Put(self, request, context): key = request.key value = request.value flag = request.flag print("Putting key.." + key) print("Putting value.." + value) self.map[key] = value if flag == "user": for host in host_list: #don't send it to yourself if host == self.ip: continue #broadcast host = host + PORT with grpc.insecure_channel(host) as channel: stub = kvstore_pb2_grpc.KeyValueStoreStub(channel) print("Trying to replicate put...") #TODO add try catch here response = stub.Put( kvstore_pb2.PutRequest(key=key, value=value, flag="server")) return kvstore_pb2.PutResponse(ret=kvstore_pb2.SUCCESS)
def read_chunk(self, chunk_id, stub=None): if not stub: with grpc.insecure_channel("{}:{}".format( self.KV_STORE_HOST, KV_STORE_PORT)) as channel: stub = kvstore_pb2_grpc.KeyValueStoreStub(channel) return self.__readchunk(chunk_id, stub) else: return self.__readchunk(chunk_id, stub)
def download_file(self, dir_id, doc_id, root, flatten=False, stub=None): if not stub: with grpc.insecure_channel("{}:{}".format( self.KV_STORE_HOST, KV_STORE_PORT)) as channel: stub = kvstore_pb2_grpc.KeyValueStoreStub(channel) self.__downloadfile(dir_id, doc_id, root, flatten, stub) else: self.__downloadfile(dir_id, doc_id, root, flatten, stub)
def upload_file_str(self, dir_id, doc_id, string, stub=None): if not stub: with grpc.insecure_channel("{}:{}".format( self.KV_STORE_HOST, KV_STORE_PORT)) as channel: stub = kvstore_pb2_grpc.KeyValueStoreStub(channel) self.__uploadfilestr(dir_id, doc_id, string, stub) channel.unsubscribe(self.close) else: self.__uploadfilestr(dir_id, doc_id, string, stub)
def read_bytes(self, dir_id, doc_id, stub=None): if not stub: with grpc.insecure_channel("{}:{}".format( self.KV_STORE_HOST, KV_STORE_PORT)) as channel: stub = kvstore_pb2_grpc.KeyValueStoreStub(channel) bytez = self.__readbytes(dir_id, doc_id, stub) channel.unsubscribe(self.close) else: bytez = self.__readbytes(dir_id, doc_id, stub) return bytez
def run(): #One server test cases with grpc.insecure_channel(get_host()) as channel: stub = kvstore_pb2_grpc.KeyValueStoreStub(channel) print("Trying...") response = stub.Put( kvstore_pb2.PutRequest(key='a', value='b', flag='user')) print("Put response code: " + str(response.ret)) response = stub.Get(kvstore_pb2.GetRequest(key='c', flag='user')) print("Get received code: " + str(response.ret)) print("Get received value: " + str(response.value))
def download_directory(self, dir_id, save_path, flatten=False, stub=None): log.info("Downloading directory {} at {}".format(dir_id, save_path)) if not stub: with grpc.insecure_channel("{}:{}".format( self.KV_STORE_HOST, KV_STORE_PORT)) as channel: stub = kvstore_pb2_grpc.KeyValueStoreStub(channel) self.__downloaddirectory(dir_id, save_path, flatten, stub) channel.unsubscribe(self.close) else: self.__downloaddirectory(dir_id, save_path, flatten, stub) log.info("Downloading directory {} at {} is successful".format( dir_id, save_path))
def upload_directory(self, dirpath, stub=None): log.info("Uploading directory {}".format(dirpath)) if not stub: with grpc.insecure_channel("{}:{}".format( self.KV_STORE_HOST, KV_STORE_PORT)) as channel: stub = kvstore_pb2_grpc.KeyValueStoreStub(channel) dir_id = self.__uploaddirectory(dirpath, stub) channel.unsubscribe(self.close) else: dir_id = self.__uploaddirectory(dirpath, stub) log.info("Uploading directory {} is successful. dir_id: {}".format( dirpath, dir_id)) return dir_id
def thread_election(self, idx, addr, req_term): try: # Todo: shouldn't always increment term here ??? vote_request = kvstore_pb2.VoteRequest( term=self.currentTerm, candidateID=self.id, lastLogIndex=self.lastLogIndex, lastLogTerm=req_term) # with grpc.insecure_channel(addr) as channel: channel = grpc.insecure_channel(addr) grpc.channel_ready_future(channel).result() stub = kvstore_pb2_grpc.KeyValueStoreStub(channel) # self.logger.debug(f'Send vote request to server: <{idx}>') req_vote_resp = stub.requestVote( vote_request, timeout=self.requestTimeout) # timeout keyword ok? # Todo: mcip, does this improve? # Todo: Add lock here to consider concurrency if req_vote_resp.voteGranted: self.logger.info( f'[Vote]: received from <{idx}>, vote count: <{self.numVotes}>' ) if self.role == KVServer.candidate: self.numVotes += 1 if self.numVotes >= self.majority: self.role = KVServer.leader with self.candidateCond: # self.logger.critical(f"thread_election, larger than majority") self.candidateCond.notify_all() else: self.logger.info( f'[Vote]: rejected from <{idx}> its term: {req_vote_resp.term}' ) # Todo: added by mcip, does this actually improve? if self.role == KVServer.follower and req_vote_resp.term > self.currentTerm: self.save(current_term=req_vote_resp.term, voted_for=-1) # Todo: All servers: If RPC request or response contains term T> currentTerm, set current term = T, # convert to follower self.convToFollowerIfHigherTerm(req_vote_resp.term, voted_for=-1) # self.role = KVServer.follower # with self.candidateCond: # self.candidateCond.notify_all() # elif num_rej_votes > self.majority: # self.save(current_term=self.currentTerm, votedFor=-1) except Exception as e: self.logger.error("[Vote]: f() thread_election:") self.logger.error(e)
def download_chunk(self, chunk_id, save_path, stub=None): if not stub: with grpc.insecure_channel("{}:{}".format( self.KV_STORE_HOST, KV_STORE_PORT)) as channel: stub = kvstore_pb2_grpc.KeyValueStoreStub(channel) data = self.__readchunk(chunk_id, stub) else: data = self.__readchunk(chunk_id, stub) if data: if not os.path.exists(os.path.dirname(save_path)): os.makedirs(os.path.dirname(save_path)) data = data.decode(KV_STORE_ENCODING) with open(save_path, 'w') as f: f.write(data)
def Get(self, request, context): key = request.key flag = request.flag print("Getting..." + key) value = "" found_value = False if key in self.map: value = self.map[key] found_value = True elif flag == "user": print("Not in this server, broadcast to all the other servers...") for host in host_list: #don't send it to yourself if host == self.ip: continue #broadcast host = host + PORT with grpc.insecure_channel(host) as channel: stub = kvstore_pb2_grpc.KeyValueStoreStub(channel) print("Trying to broadcast get...") #TODO add try catch here response = stub.Get( kvstore_pb2.GetRequest(key=key, flag="server")) if response.ret == kvstore_pb2.SUCCESS: print("Get received: " + str(response.value)) value = response.value found_value = True break if found_value: return kvstore_pb2.GetResponse(value=value, ret=kvstore_pb2.SUCCESS) else: return kvstore_pb2.GetResponse(value="", ret=kvstore_pb2.FAILURE)
def run(): addresses = readAddress("remote-server.csv") print(addresses) start = time.time() leaderID = 0 try: while True: if leaderID == -1: leaderID = 0 channel = grpc.insecure_channel(addresses[leaderID]) stub = kvstore_pb2_grpc.KeyValueStoreStub(channel) print(f'Send RegisterClient RPC to server <{leaderID}>') response = stub.registerClient(kvstore_pb2.RegisterRequest()) if response.status == kvstore_pb2.OK2CLIENT: clientID = response.clientID print(f"Register client as <{clientID}>") break else: leaderID = response.leaderHint # time.sleep(0.1) except Exception as e: print(e) print(time.time() - start) # TODO: Implement PUT and GET myKey = "1" * 1024 myValue = "1" * 1024 start = time.time() seq_num = 1 for i in range(100): try: while True: channel = grpc.insecure_channel(addresses[leaderID]) stub = kvstore_pb2_grpc.KeyValueStoreStub(channel) # print("Try to put") response = stub.Put( kvstore_pb2.PutRequest(key=myKey, value=myValue, clientID=clientID, sequenceNum=seq_num)) if response.status == kvstore_pb2.NOT_LEADER: leaderID = response.leaderHint elif response.status == kvstore_pb2.SESSION_EXPIRED: print("Session Expired") elif response.status == kvstore_pb2.OK2CLIENT: print("PUT OK") break else: print("PUT Error") except Exception as e: print(e) seq_num += 1 print(time.time() - start) start = time.time() try: while True: channel = grpc.insecure_channel(addresses[leaderID]) stub = kvstore_pb2_grpc.KeyValueStoreStub(channel) print("Try to get") response = stub.Get(kvstore_pb2.GetRequest(key=myKey)) if response.status == kvstore_pb2.NOT_LEADER: leaderID = response.leaderHint elif response.status == kvstore_pb2.SESSION_EXPIRED: print("Session Expired") elif response.status == kvstore_pb2.OK2CLIENT: print(f'GET OK: ') #<{response.value}>') break else: print("GET Error") except Exception as e: print(e) print(time.time() - start)
def thread_append_entry(self, idx, addr, app_ent_term): try: append_request = kvstore_pb2.AppendRequest() append_request.term = app_ent_term # int32 term = 1; append_request.leaderID = self.id # int32 leaderID = 2; append_request.prevLogIndex = self.nextIndex[ idx] # int32 prevLogIndex = 3; # int32 prevLogTerm = 4; if 0 <= self.nextIndex[idx] < len(self.log): append_request.prevLogTerm = self.log[self.nextIndex[idx]][0] else: append_request.prevLogTerm = 0 append_request.leaderCommit = self.commitIndex # int32 leaderCommit = 6; last_req_log_idx = self.lastLogIndex self.logger.info( f"[AP_En]: thread_append_entry to <{idx}> prevLogInd <{append_request.prevLogIndex}> " f"prevLogTerm <{append_request.prevLogTerm}>") if self.nextIndex[idx] < len(self.log): for row in self.log[ self. nextIndex[idx]:]: # repeated LogEntry entries = 5; entry = append_request.entries.add() entry.term = row[0] entry.key = row[1] entry.val = row[2] self.nextIndex[ idx] = self.lastLogIndex + 1 # Todo: should inc to +1 here? # with grpc.insecure_channel(addr) as channel: channel = grpc.insecure_channel(addr) grpc.channel_ready_future(channel).result() # int32 term = 1; # bool success = 2; stub = kvstore_pb2_grpc.KeyValueStoreStub(channel) if random.uniform( 0, 1) < self.cmserver.fail_mat[self.leaderID][self.id]: self.logger.warning( f'[ABORTED]: we will not receive from <{self.leaderID}> ' f'because of ChaosMonkey') else: # self.logger.info(f'[AP_En]: thread_append_entry to <{idx}>, ' # f'req last log <{last_req_log_idx}>') # f'req entries \n<{append_request.entries}>') append_entry_response = stub.appendEntries( append_request, timeout=self.requestTimeout) if not append_entry_response.success: self.logger.info( f"[AP_En]: thread_append_entry to <{idx}> failed, " f"its term <{append_entry_response.term}>, leader's <{self.currentTerm}>" ) # Failed because of log inconsistency, decrement nextIndex and retry if append_entry_response.term <= self.currentTerm: self.logger.info( f"[AP_En]: log inconsistency, nextIndex for <{idx}> dec from " f"<{self.nextIndex[idx]}> to <{max(append_request.prevLogIndex - 1, 0) }>" ) # Todo: how to decrement correctly self.nextIndex[idx] = max( append_request.prevLogIndex - 1, 0) else: # Todo: All servers: If RPC request or response contains term T> currentTerm, # set current term = T, convert to follower self.convToFollowerIfHigherTerm( append_entry_response.term, voted_for=-1) # Success else: self.logger.info( f"[AP_En]: thread_append_entry to <{idx}> success") self.matchIndex[idx] = last_req_log_idx self.logger.debug( f'[KVStore]: matchIndex: <{self.matchIndex}>') n_list = sorted(self.matchIndex) # TODO: write to disk upon majority # if there exists such N that N> commitIndex and majority of matchIndex[i] >= N # and log[N].term ==currentTerm, set commitIndex = N N = n_list[int(len(n_list) / 2)] if N >= 0 and N > self.commitIndex and self.log[N][ 0] == self.currentTerm: self.commitIndex = N self.logger.info( f"RAFT: Commit index on leader updates to: {N}") disk_write_kth = KThread( target=self.applyToStateMachine, args=(self.lastApplied, )) disk_write_kth.start() except Exception as e: self.logger.error( "[Vote]: f() thread_append_entry, most likely name resolution error" ) self.logger.error(e) # Todo: Name resolution error