Пример #1
0
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])
Пример #2
0
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)
Пример #3
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]
Пример #4
0
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
Пример #5
0
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!')
Пример #6
0
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
Пример #7
0
def str_rm(r_str):
    """ str to ReplicaMessage """
    temp = replica_pb2.ReplicaMessage()
    temp.ParseFromString(r_str)
    return temp