def read_repair(r_val, rr_list, k_pl, key): #print('======= inside read repair============') for _ in cur_replica.preference_list[k_pl]: if cur_replica.name != _.name: #create a new connection so that a new thread is created at that replica and won't interfere h_socket = _sock.create_connection((_.ip, _.port)) h_msg = replica_pb2.ReplicaMessage() h_msg.put_key.from_rep = cur_replica.name h_msg.put_key.from_client = 0 h_msg.put_key.key = key h_msg.put_key.value = r_val[0] h_msg.put_key.timestamp = r_val[1] result = rm_str_send(h_msg, h_socket) h_res = recv_fun(h_socket) # put request is succesful unless replica goes down again if h_res.replica_response.is_updated == 1: pass else: with cur_replica.kv_lock: try: cur_replica.kv_store[key][0] = r_val[0] cur_replica.kv_store[key][1] = r_val[1] except KeyError: cur_replica.kv_store[key] = [r_val[0]] cur_replica.kv_store[key].append(r_val[1])
def cord_client_res(init_msg, n_acks, n_nacks, client, ret_value=[], neg_acks=None, mode='w'): """ """ c_res = replica_pb2.ReplicaMessage() # use if mode == 'w' or == 'r' for put_key and get_key if mode == 'w': # == 2 should be (REP_FACTOR//2)+1 in other cases NUM_REPLICAS != 4 if ((init_msg.put_key.consistency_level == 'QUORUM' and n_acks == 2) or (init_msg.put_key.consistency_level == 'ONE' and n_acks == 1)): c_res.cord_response.ack = 1 return rm_str_send(c_res, client) # >= 2 should be (REP_FACTOR//2)+1 in other cases NUM_REPLICAS != 4 elif ((init_msg.put_key.consistency_level == 'QUORUM' and n_nacks >= 2) or (init_msg.put_key.consistency_level == 'ONE' and n_nacks == 3)): c_res.cord_response.ack = 0 return rm_str_send(c_res, client) # for get_key response to the client from cordinator elif mode == 'r': #print('Inside cord_client_res neg_acks: {}, acks: {}, nacks: {} at {}'.format(neg_acks, n_acks, # n_nacks, cur_replica.name)) # == 2 should be (REP_FACTOR//2)+1 in other cases NUM_REPLICAS != 4 if ((init_msg.get_key.consistency_level == 'QUORUM' and n_acks == 2) or (init_msg.get_key.consistency_level == 'ONE' and n_acks == 1)): c_res.cord_response.value_present = 1 c_res.cord_response.value = ret_value[0] return rm_str_send(c_res, client) # >= 2 should be (REP_FACTOR//2)+1 in other cases NUM_REPLICAS != 4 elif ((init_msg.get_key.consistency_level == 'QUORUM' and n_nacks >= 2) or (init_msg.get_key.consistency_level == 'ONE' and n_nacks == 3 and n_acks == 0)): c_res.cord_response.value_present = 0 return rm_str_send(c_res, client) # if value present in replicas less than consistency_level client should receive an exception elif ( (init_msg.get_key.consistency_level == 'QUORUM' and neg_acks >= 2) or (init_msg.get_key.consistency_level == 'ONE' and neg_acks == 3 and n_acks == 0)): c_res.cord_response.value_present = 2 return rm_str_send(c_res, client) return (0)
def hinted_handoff(r_name): #create a new connection so that a new thread is created at that replica and won't interfere h_socket = _sock.create_connection((cur_replica.all_replicas[r_name].ip, cur_replica.all_replicas[r_name].port)) h_msg = replica_pb2.ReplicaMessage() h_msg.put_key.from_rep = cur_replica.name h_msg.put_key.from_client = 0 with cur_replica.h_lock: # getting keys and values from cur_replica hint and sending it to the cordinator invoking this for _ in cur_replica.hint[r_name]: h_msg.put_key.key = _ h_msg.put_key.value = cur_replica.hint[r_name][_][0] h_msg.put_key.timestamp = cur_replica.hint[r_name][_][1] result = rm_str_send(h_msg, h_socket) h_res = recv_fun(h_socket) # put request is succesful unless replica goes down again if h_res.replica_response.is_updated == 1: pass # remove this replicas name from the cur_replica's hint del cur_replica.hint[r_name]
def recv_fun(client): data = b'' while True: try: data += client.recv(1) size = decode_varint(data) break except IndexError: pass # if recv keeps throughing error. use data=[], in loop append to data received msg. Then ''.join(data) data = [] while True: try: msg = client.recv(size) data.append(msg) msg = ''.join(data) init_msg = replica_pb2.ReplicaMessage() init_msg.ParseFromString(msg) break except: pass return init_msg
def handle_cord(cord_socket): while True: cmd = raw_input( '\nEnter your command. For ex. GetKey / PutKey / exit(to stop the client) : ' ) if cmd.lower() == 'getkey': key = int( raw_input( 'Please enter the key(should be between 0 and 255) : ')) c_lev = raw_input( 'Please enter the consistency level (Quorum or one) : ') # take consistancy level as input too. later client_msg = replica_pb2.ReplicaMessage() client_msg.get_key.key = key client_msg.get_key.from_client = 1 client_msg.get_key.consistency_level = c_lev.upper() serialized_client_msg = client_msg.SerializeToString() # sending this msg to the cordinator size = encode_varint(len(serialized_client_msg)) cord_socket.sendall(size + serialized_client_msg) cord_res = recv_fun(cord_socket) c_response = cord_res # See what to do with == 2 and 0 later if c_response.cord_response.value_present == 0: print( 'The value for your key : {} is not present on any of the replicas!' .format(key)) elif c_response.cord_response.value_present == 1: print('The value corresponding to the key {} is : {}'.format( key, c_response.cord_response.value)) # value present on less than 3 servers. Through an error. Raise() elif c_response.cord_response.value_present == 2: print( 'The value for given key {} is present on less than recquired replicas' .format(key)) elif cmd.lower() == 'putkey': key = int( raw_input( 'Please enter the key(should be between 0 and 255) : ')) value = raw_input( 'Please enter the value associated with this key : ') c_lev = raw_input( 'Please enter the consistency level (Quorum or one) : ') # take consistancy level as input too. later client_msg = replica_pb2.ReplicaMessage() client_msg.put_key.key = key client_msg.put_key.value = value client_msg.put_key.from_client = 1 client_msg.put_key.consistency_level = c_lev.upper() serialized_client_msg = client_msg.SerializeToString() size = encode_varint(len(serialized_client_msg)) # sending this msg to the cordinator cord_socket.sendall(size + serialized_client_msg) # use try cath block here in case the cordinator goes down before replying cord_res = recv_fun(cord_socket) c_response = cord_res # See what to do with this later if c_response.cord_response.ack == 0: print('Your write request was unsuccessful !') # raise error??????????? elif c_response.cord_response.ack == 1: print( 'Your write request has been prosessed successfully with consistency level {}!' .format(c_lev.upper())) elif cmd.lower() == 'exit': print('Client shutting down ......') sys.exit(1) else: print('Not a valid choice. please try again!')
def handle_msgs(client, addr): """ """ t_exit_loop = 0 while True: try: init_msg = recv_fun(client) except: t_exit_loop = 1 # if client terminated kill the thread if t_exit_loop == 1: break if init_msg.HasField('put_key'): # might need to use a lock, see later ("%d/%m/%y %H:%M:%S:%f") key = init_msg.put_key.key if init_msg.put_key.from_client == 1: # for corinator section # connect to all other replicas res for this key k_pl = res_rep(key) # put_key msg to be sent by cordinator to all the responsible replicas c_msg = replica_pb2.ReplicaMessage() c_msg.CopyFrom(init_msg) # timestamp in string can be compared well c_msg.put_key.timestamp = _dt.now().strftime( "%d/%m/%y %H:%M:%S:%f") c_msg.put_key.from_client = 0 c_msg.put_key.from_rep = cur_replica.name sc_msg = c_msg.SerializeToString() size = encode_varint(len(sc_msg)) n_nacks, n_acks, res_sent = 0, 0, 0 # nacks when replicas are down for replica in cur_replica.preference_list[k_pl]: if replica.name != cur_replica.name: # check if the replica is up. if not see if consistancy level is achieved if yes send # ...ack otherwise send nack try: c_socket = _sock.create_connection( (replica.ip, replica.port)) c_socket.sendall(size + sc_msg) sr_res = recv_fun(c_socket) r_res = sr_res #################################################### # hints at this cordinator can also be checked and sent if present # ...make a function #################################################### # don't even need to do this if statement c_socket.close() #print('----------received rep res : {}'.format(client)) if r_res.replica_response.is_updated == 1: n_acks += 1 if res_sent == 0: # fun to prepare cord resp based on acks and nacks use in GetKey as well res_sent = cord_client_res( init_msg, n_acks, n_nacks, client) except _sock.error: # Store this in the hinted handoff data structure if cur_replica.read_repair == 0: with cur_replica.h_lock: if replica.name in cur_replica.hint: try: if cur_replica.hint[ replica.name][key][ 1] < c_msg.put_key.timestamp: cur_replica.hint[ replica.name][key][ 1] = c_msg.put_key.timestamp cur_replica.hint[ replica.name][key][ 0] = c_msg.put_key.value except KeyError: cur_replica.hint[ replica.name][key] = [ c_msg.put_key.value, c_msg.put_key.timestamp ] else: cur_replica.hint[replica.name] = { key: [ c_msg.put_key.value, c_msg.put_key.timestamp ] } n_nacks += 1 # if consistency_level requirements are met send the acknowledgement if res_sent == 0: res_sent = cord_client_res( init_msg, n_acks, n_nacks, client) elif replica.name == cur_replica.name: ord_rep_write(c_msg) n_acks += 1 # if consistency_level requirements are met send the acknowledgement if res_sent == 0: res_sent = cord_client_res(init_msg, n_acks, n_nacks, client) else: # should check if there are any hints in cur_replica for the coming cordinatormsg #......if yes send this value else pass (see carefully) if cur_replica.read_repair == 0: if init_msg.put_key.from_rep in cur_replica.hint: name = init_msg.put_key.from_rep th = _thr.Thread(target=hinted_handoff, args=(name, ), name=('hh_' + cur_replica.name)) th.daemon = False th.start() # for ordinary replica ord_rep_write(init_msg) # After write operation is done prepare ReplicaMessage to the cordinator r_msg = replica_pb2.ReplicaMessage() r_msg.replica_response.is_updated = 1 sr_msg = r_msg.SerializeToString() size = encode_varint(len(sr_msg)) client.sendall(size + sr_msg) # kill the connection from cordinator, only client-cordinator con should be alive break elif init_msg.HasField('get_key'): # check if this msg is from client or other replica and work accordingly change for more replicas key = init_msg.get_key.key if init_msg.get_key.from_client == 1: # for corinator section # connect to all other replicas res for this key k_pl = res_rep(key) # get_key msg to be sent by cordinator to all the responsible replicas c_msg = replica_pb2.ReplicaMessage() c_msg.CopyFrom(init_msg) # timestamp in string can be compared well c_msg.get_key.from_client = 0 c_msg.get_key.from_rep = cur_replica.name sc_msg = c_msg.SerializeToString() size = encode_varint(len(sc_msg)) # acks:if present ; nacks : not present ; neg_acks : replica down ; ret_value[val, time]:return val # rr_list stores replica names with consistent and inconsistent data n_nacks, n_acks, neg_acks, res_sent, ret_value, rr1, rr2 = 0, 0, 0, 0, [], [], [] for replica in cur_replica.preference_list[k_pl]: if replica.name != cur_replica.name: # check if the replica is up. if not see if consistancy level is achieved if yes send # ...ack otherwise send nack try: c_socket = _sock.create_connection( (replica.ip, replica.port)) c_socket.sendall(size + sc_msg) r_res = recv_fun(c_socket) c_socket.close() #print('----------received rep res : {}'.format(client)) if r_res.replica_response.value_present == 1: n_acks += 1 if ret_value == []: ret_value.append( r_res.replica_response.value) ret_value.append( r_res.replica_response.timestamp) rr1.append(r_res.replica_response.from_rep) else: if ret_value[ 1] < r_res.replica_response.timestamp: ret_value[ 0] = r_res.replica_response.value ret_value[ 1] = r_res.replica_response.timestamp # add to rr2 since rr1 replicas are inconsistent for _ in rr1: rr2.append(_) # flush rr1 since inconsistent rr1 = [r_res.replica_response.from_rep] elif ret_value[ 1] > r_res.replica_response.timestamp: rr2.append( r_res.replica_response.from_rep) elif ret_value[ 1] == r_res.replica_response.timestamp: # for == append rep_name to rr_list rr1.append( r_res.replica_response.from_rep) elif r_res.replica_response.value_present == 0: n_nacks += 1 rr2.append(r_res.replica_response.from_rep) # prepare for cordinator response on meeting recquirements if res_sent == 0: # fun to prepare cord resp based on acks and nacks use in GetKey as well cord_client_res(init_msg, n_acks, n_nacks, client, ret_value=ret_value, neg_acks=neg_acks, mode='r') except _sock.error: neg_acks += 1 # if consistency_level requirements are met send the acknowledgement if res_sent == 0: res_sent = cord_client_res(init_msg, n_acks, n_nacks, client, ret_value=ret_value, neg_acks=neg_acks, mode='r') elif replica.name == cur_replica.name: #print('==== key {} requested at {} and kv_store'.format(key, cur_replica.name, # cur_replica.kv_store)) t_val = ord_rep_read(c_msg) if t_val == []: n_nacks += 1 rr2.append(cur_replica.name) # value not present here and other replicas are down neg_acks += 1 else: n_acks += 1 if ret_value == []: ret_value.append(t_val[0]) ret_value.append(t_val[1]) rr1.append(cur_replica.name) else: if ret_value[1] < t_val[1]: ret_value[0] = t_val[0] ret_value[1] = t_val[1] # add to rr2 since rr1 replicas are inconsistent for _ in rr1: rr2.append(_) # flush rr1 since inconsistent rr1 = [] # for >= and < append rep_name to rr_list rr1.append(cur_replica.name) # if consistency_level requirements are met send the acknowledgement if res_sent == 0: res_sent = cord_client_res(init_msg, n_acks, n_nacks, client, ret_value=ret_value, neg_acks=neg_acks, mode='r') ######################check here for read repair #print("rr1 : {}, rr2 : {}, ret_value : {}".format(rr1, rr2, ret_value)) if (cur_replica.read_repair == 1 and ret_value != [] and rr2 != []): th = _thr.Thread(target=read_repair, args=(ret_value, rr2, k_pl, key), name=('rr_' + cur_replica.name)) th.start() else: #should check if there are any hints in cur_replica for the coming cordinatormsg #......if yes send those hints else pass (see carefully) if cur_replica.read_repair == 0: if init_msg.get_key.from_rep in cur_replica.hint: name = init_msg.get_key.from_rep th = _thr.Thread(target=hinted_handoff, args=(name, ), name=('hh_' + cur_replica.name)) th.daemon = False th.start() # for ordinary replica r_msg = replica_pb2.ReplicaMessage() t_val = ord_rep_read(init_msg) # After read operation is done prepare ReplicaMessage to the cordinator if t_val == []: r_msg.replica_response.value_present = 0 else: r_msg.replica_response.value_present = 1 r_msg.replica_response.from_rep = cur_replica.name r_msg.replica_response.value = t_val[0] r_msg.replica_response.timestamp = t_val[1] sr_msg = r_msg.SerializeToString() size = encode_varint(len(sr_msg)) client.sendall(size + sr_msg) # kill the connection from cordinator, only client-cordinator con should be alive break
def str_rm(r_str): """ str to ReplicaMessage """ temp = replica_pb2.ReplicaMessage() temp.ParseFromString(r_str) return temp