Exemple #1
0
def setr_deny(svrs, key):
    """setr not successful."""
    deny = {'cmd': 'setr_deny', 'key': key}
    for svr in svrs:
        svr_addr, svr_port = svr.split(':')
        common.send_receive(svr_addr, svr_port, deny)
    return {'status': 'setr not successful'}
def sync(replica_list, log, msg):
    quorom = (len(replica_list) / 2) + 1
    replicas_that_responded = {}
    for replica in replica_list:
        if replica != config["endpoint"]:
            host = replica.partition(":")[0]
            port = replica.partition(":")[2]
            res = common.send_receive(host, port, {
                "cmd": "prepare", 
                "new_log_entry": msg, 
                "proposal_num": len(log)})
            if "error" in res:
                print("Couldn't connect to %s:%s for a prepare msg" % (host, port))
                continue
            else:
                replicas_that_responded[replica] = res
                if res["missing_logs_to_vl"] != None:
                    replay(res["missing_logs_to_vl"], None)
        else:
            # if you are contacting yourself, just vote yes.
            replicas_that_responded[config["endpoint"]] = {
            "vote": "yes", 
            "current_log_length": len(log), 
            "missing_logs_to_vl": None, 
            "missing_logs_to_replica": None}


    # this counts the "yes" votes and puts them in the list
    if len([1 for rep in replicas_that_responded if replicas_that_responded[rep]["vote"] == "yes"]) >= quorom:
        log[len(log)] = msg
        missing_logs = {}
        for replica in replicas_that_responded:
            if replica != config["endpoint"]:
                host = replica.partition(":")[0]
                port = replica.partition(":")[2]
                # the LAST value represents the replicas last log entry
                # i have to compare this value with the length of my log
                # it will be less most likely
                if replicas_that_responded[replica]["missing_logs_to_replica"] != None:
                    last = replicas_that_responded[replica]["missing_logs_to_replica"]
                    while last <= len(log):
                        missing_logs[last] = log[last] 
                        last = last + 1
                    #now missing_logs should hold all of the commands that the replica did not have yet. 
                res = common.send_receive(host, port, {
                    "cmd": "accept", 
                    "new_log_entry": msg, 
                    "proposal_num": len(log), 
                    "missing_logs_to_replica": missing_logs})
                print res
                if "error" in res:
                    print("couldn't connect to %s:%s for an accept msg" % (host, port))
                    continue
                else:
                    print("successfully sent new_entry to %s:%s" % (host, port))
    else:
        return {"error": "failed to sync due to lack of quorom"}
    return {"ok": "something went wrong"}
Exemple #3
0
def prepare_accept_rpc(msg, addr):
    global log
    the_time = time.time()
    prep_msg = {
        "cmd": "prepare",
        "prop_no": len(log),
        "to_commit": {
            "msg": msg,
            "addr": addr,
            "time": the_time
        }
    }

    # collect responses to prep_msg from replicas
    responses = []
    for host_port in reversed(config["view_addr"]):
        host, port = host_port.split(':')
        if (host, port) != (config["my_addr"], config["my_port"]):
            resp = common.send_receive(host, port, prep_msg, timeout=1)
            if "status" in resp and resp["status"] == "ok":
                # remember the host:port of the response
                resp["host"] = host
                resp["port"] = port
                responses.append(resp)

    # use longest log of all replicas to update global log
    if responses != []:
        log_missing = (max(responses,
                           key=lambda resp: resp["log_len"]))["log_missing"]
        for log_entry in log_missing:
            result = commit_log_entry(log_entry)

    has_quarum = len(responses) + 1 > (len(config["view_addr"]) // 2)
    if has_quarum:
        # accept message is essentially the same as prep_msg
        # just change "cmd", "prop_no", and append missing log entries
        # in particular, the_time (line 159) remains the same
        accept_msg = prep_msg
        accept_msg["cmd"] = "accept"
        accept_msg["prop_no"] = len(log)

        accept_responses = []
        for resp in responses:
            host, port = resp["host"], resp["port"]
            accept_msg["log_missing"] = log[resp["log_len"]:]
            resp = common.send_receive(host, port, accept_msg)
            accept_responses.append(resp)

        for resp in accept_responses:
            if "error" in resp: print resp

        return commit_log_entry(accept_msg["to_commit"])
    else:
        return {"status": "denied", "info": "too few view replicas for quarum"}
Exemple #4
0
def send_cancel(k,v,aloc, serverdata):
    responses=[]
    i=0
    for sid in aloc:
        host=serverdata[sid]["host"]
        port=serverdata[sid]["port"]
        responses.insert( i,
        common.send_receive(host,port, 
            {"key":k,"value": v, "cmd":"cancel"}))
Exemple #5
0
def rebalancing_lost(lost_lease_index_hash):
    """Rebalance the keys and values when a server is lost."""
    print 'Rebalancing...'
    lost_lease_index, lost_lease_hash = lost_lease_index_hash
    count = collections.defaultdict(list)
    # index1 = (lost_lease_index - 3) % len_
    # index2 = (lost_lease_index + 2) % len_
    # if index1 < index2:
    #     adjacent_leases = leases[index1:index2+1]
    # else:
    #     adjacent_leases = leases[index1:] + leases[:index2+1]
    adjacent_leases = arc(lost_lease_index, 3, 2, leases)
    print adjacent_leases
    for lease in adjacent_leases:
        host, port = lease['lockid'].split(':')
        res = common.send_receive(host, port, {'cmd': 'query_all_keys'})
        print 'res'
        print res
        for key in res['result']:
            count[key].append(lease['hash'])
    print count
    # We only need to update a server if there are 2 of a key in
    # adjacent_leases
    to_add = {
        key: value
        for (key, value) in count.iteritems() if len(value) == 2
    }
    print to_add
    # These are the keys we need to add to the next server, the one after
    # that, and the last one, respectively. Could probably be own function.
    to_add_1 = []
    to_add_2 = []
    to_add_3 = []
    for (key, hashes) in to_add.iteritems():
        if hashes[0] < lost_lease_hash:
            if hashes[1] < lost_lease_hash:
                to_add_1.append(key)
            else:
                to_add_2.append(key)
        else:
            to_add_3.append(key)
    print 'ready to rebalance'
    svrs_for_1 = arc(lost_lease_index, 2, -1, leases)
    print svrs_for_1
    assert len(svrs_for_1) == 2
    rebalance_request(to_add_1, svrs_for_1, adjacent_leases[4])
    svrs_for_2 = arc(lost_lease_index, 1, 1, leases)
    print svrs_for_2
    rebalance_request(to_add_2, svrs_for_2, adjacent_leases[5])
    svrs_for_3 = arc(lost_lease_index, -1, 2, leases)
    print svrs_for_3
    rebalance_request(to_add_3, svrs_for_3, adjacent_leases[6])
    print 'Rebalancing complete'
Exemple #6
0
def rebalance_request(keys, origin, dests):
    """Request to send keys from servers to a server."""
    success = False
    for svr in origin:
        host, port = svr.split(':')
        res = common.send_receive(host, port, {
            'cmd': rebalance_request,
            'keys': keys,
            'dest': dests
        })
        if res['reply'] == 'ok':
            success = True
            break
        # # Try to send the key to both servers from the last server.
        # elif res['reply'] == 'KeyError':
        #     dests.append(svr)
    return {'reply': 'ok'} if success else {'reply': 'fail'}
def heartbeat_rpc():

    for host_port in reversed(common.lexi_sort(config["view_addr"])):
        host, port = host_port.split(':')
        msg = {
            "cmd": "heartbeat",
            "server_id": config["server_id"],
            "port": config["port"]
        }
        response = common.send_receive(host, port, msg)
        if "status" in response and response["status"] == "ok":
            break
        if "status" in response and response["status"] == "denied":
            print response
            break

    if "error" in response: print response
    config["hb_time"] = time.time()
Exemple #8
0
def main():
    """Client entry point."""
    parser = argparse.ArgumentParser()
    parser.add_argument('--server', default='localhost')
    parser.add_argument('--viewleader', default='localhost')

    subparsers = parser.add_subparsers(dest='cmd')

    parser_set = subparsers.add_parser('set')
    parser_set.add_argument('key', type=str)
    parser_set.add_argument('val', type=str)

    parser_get = subparsers.add_parser('get')
    parser_get.add_argument('key', type=str)

    parser_print = subparsers.add_parser('print')
    parser_print.add_argument('text', nargs="*")

    parser_query = subparsers.add_parser('query_all_keys')
    parser_server_query = subparsers.add_parser('query_servers')

    parser_lock_get = subparsers.add_parser('lock_get')
    parser_lock_get.add_argument('lockid', type=str)
    parser_lock_get.add_argument('requestor', type=str)

    parser_lock_get = subparsers.add_parser('lock_release')
    parser_lock_get.add_argument('lockid', type=str)
    parser_lock_get.add_argument('requestor', type=str)

    parser_setr = subparsers.add_parser('setr')
    parser_setr.add_argument('key', type=str)
    parser_setr.add_argument('val', type=str)

    parser_getr = subparsers.add_parser('getr')
    parser_getr.add_argument('key', type=str)

    args = parser.parse_args()

    if args.cmd in ['query_servers', 'lock_get', 'lock_release']:
        while True:
            response = common.send_receive_range(args.viewleader,
                                                 common2.VIEWLEADER_LOW,
                                                 common2.VIEWLEADER_HIGH,
                                                 vars(args))
            if response.get("status") == "retry":
                print "Waiting on lock %s..." % args.lockid
                time.sleep(5)
                continue
            else:
                break
        print response

    elif args.cmd == 'setr':
        key, val = args.key, args.val
        print 'Trying to setr %s to %s' % (key, val)
        msg = common.send_receive_range(args.viewleader,
                                        common2.VIEWLEADER_LOW,
                                        common2.VIEWLEADER_HIGH,
                                        {'cmd': 'query_servers'})
        # results are lockid, hash
        hashes = [(entry[1], entry[0]) for entry in msg['result']]
        # list just the lockids
        svrs = [svr[1] for svr in find_svrs(key, hashes)]
        ress = [setr_request(svr, key) for svr in svrs]
        # we iterate through ress twice, which is a bit inefficient, but ress
        # should only be around 3 items, so it should be ok.
        if 'no' in [res['reply'] for res in ress]:
            res = setr_deny(svrs, key)
            print 'key already being set'
        elif any([res['epoch'] != msg['epoch'] for res in ress]):
            res = setr_deny(svrs, key)
            print 'server with wrong epoch'
        else:
            res = setr_accept(svrs, key, val)
        return res
    elif args.cmd == 'getr':
        key = args.key
        msg = common.send_receive_range(args.viewleader,
                                        common2.VIEWLEADER_LOW,
                                        common2.VIEWLEADER_HIGH,
                                        {'cmd': 'query_servers'})
        # results are lockid, hash
        hashes = [(entry[1], entry[0]) for entry in msg['result']]
        # list the lockids
        svrs = [svr[1] for svr in find_svrs(key, hashes)]
        for svr in svrs:
            host, port = svr.split(':')
            new_msg = {'cmd': 'get', 'key': key}
            try:
                print common.send_receive(host, port, new_msg)
                break
            except socket.Timeouterror:
                pass
                print {'status': 'unable to retrieve %s from any server' % key}
    else:
        response = common.send_receive_range(args.server, common2.SERVER_LOW,
                                             common2.SERVER_HIGH, vars(args))
        print response
Exemple #9
0
def setr_request(lockid, key):
    """Request votes from servers."""
    svr_addr, svr_port = map(str, lockid.split(':'))
    msg = {'cmd': 'setr_request', 'key': key}
    return common.send_receive(svr_addr, svr_port, msg)
Exemple #10
0
def set_val(lockid, key, val):
    """set value on a server."""
    svr_addr, svr_port = lockid.split(':')
    msg = {'cmd': 'setr', 'key': key, 'val': val}
    print 'set %s to %s' % (key, val)
    return common.send_receive(svr_addr, svr_port, msg)
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--server', default='localhost')

    subparsers = parser.add_subparsers(dest='cmd')

    parser_set = subparsers.add_parser('set')
    parser_set.add_argument('key', type=str)
    parser_set.add_argument('val', type=str)

    parser_get = subparsers.add_parser('get')
    parser_get.add_argument('key', type=str)

    parser_print = subparsers.add_parser('print')
    parser_print.add_argument('text', nargs="*")

    parser_query = subparsers.add_parser('query_all_keys')

    # --------- new for hw2 (below) ---------- #

    parser.add_argument('--viewleader', default=common.default_vl())

    parser_query_servers = subparsers.add_parser('query_servers')

    parser_lock_get = subparsers.add_parser('lock_get')
    parser_lock_get.add_argument('name', type=str)
    parser_lock_get.add_argument('req_id', type=str)

    parser_lock_release = subparsers.add_parser('lock_release')
    parser_lock_release.add_argument('name', type=str)
    parser_lock_release.add_argument('req_id', type=str)

    # --------- new for hw2 (above) ---------- #

    args = parser.parse_args()

    msg = vars(args)
    if msg['cmd'] in {'set', 'get', 'print', 'query_all_keys'}:

        for port in range(common2.SERVER_LOW, common2.SERVER_HIGH):
            print "Trying to connect to %s:%s..." % (args.server, port)
            response = common.send_receive(args.server, port, msg)
            if "error" in response:
                continue
            print response
            break
        else:
            print "Can't connect on any port, giving up"

    else:

        for host_port in reversed(common.lexi_sort(args.viewleader)):
            host, port = host_port.split(':')
            print "Trying to connect to %s:%s..." % (host, port)

            if msg['cmd'] == "lock_get":
                success = False
                next_port = False

                while (not success) and (not next_port):
                    response = common.send_receive(host, port, msg)
                    if "error" in response:
                        next_port = True
                    elif response["status"] == 'granted':
                        success = True
                        print response
                    else:
                        success = False
                        next_port = False
                        print response
                        time.sleep(5)

                if success: break

            else:
                response = common.send_receive(host, port, msg)
                if "error" in response:
                    continue
                print response
                break

        else:
            print "Can't connect on any port, giving up"
Exemple #12
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--server', default='localhost')
    parser.add_argument('--viewleader', default='localhost')

    subparsers = parser.add_subparsers(dest='cmd')

    parser_set = subparsers.add_parser('set')
    parser_set.add_argument('key', type=str)
    parser_set.add_argument('val', type=str)

    parser_get = subparsers.add_parser('get')
    parser_get.add_argument('key', type=str)

    parser_print = subparsers.add_parser('print')
    parser_print.add_argument('text', nargs="*")

    parser_query = subparsers.add_parser('query_all_keys')
    parser_server_query = subparsers.add_parser('query_servers')

    parser_lock_get = subparsers.add_parser('lock_get')
    parser_lock_get.add_argument('lockid', type=str)    
    parser_lock_get.add_argument('requestor', type=str)    

    parser_lock_get = subparsers.add_parser('lock_release')
    parser_lock_get.add_argument('lockid', type=str)    
    parser_lock_get.add_argument('requestor', type=str) 

    parser_setr = subparsers.add_parser('setr')
    parser_setr.add_argument('key', type=str)
    parser_setr.add_argument('val', type=str)

    parser_getr = subparsers.add_parser('getr')
    parser_getr.add_argument('key', type=str)

    args = parser.parse_args()

    if args.cmd in ['query_servers', 'lock_get', 'lock_release']:
        while True:
            response = common.send_receive_range(args.viewleader, common2.VIEWLEADER_LOW, common2.VIEWLEADER_HIGH, vars(args))
            if response.get("status") == "retry":
                print "Waiting on lock %s..." % args.lockid
                time.sleep(5)
                continue
            else:
                break
        print response
    elif args.cmd in ['setr', 'getr']:
        query={'viewleader' : args.viewleader, 'cmd' : 'query_servers', 'server' : args.server}
        view=common.send_receive_range(args.viewleader, common2.VIEWLEADER_LOW, common2.VIEWLEADER_HIGH, query)
        if "error" in view:
            print "Viewleader failure:", view
            return()
        else:
            servers=view['result']
        if servers==[]:
            print "No servers available"
        else:
            server_ids=[]
            serverdata={}
            for server in servers:
                (h,p)=common.formatHP(server["location"])
                server["host"]=h
                server["port"]=p
                del server["location"]
                n=int(server["name"])
                server_ids.append(n)
                serverdata[n]=server
            h=common.hash_key(args.key)
            aloc=common.bucket_allocator(args.key, server_ids)
            #list of destination server ids
            if args.cmd=="getr":
                responses=[]
                i=0
                for sid in aloc:
                    responses.insert( i,
                    common.send_receive(serverdata[sid]["host"],serverdata[sid]["port"], vars(args)))
                    if "status" in responses[i] and responses[i]["status"]=="ok":
                        print responses[i]
                        break
                    i+=1
                else: print "No such key found in our system"
            elif args.cmd=="setr":
                responses=common.broadcast_receive(aloc,serverdata,vars(args))
                for r in responses:
                    if "epoch" in r:
                        epoch=r["epoch"]
                for r in responses:
                    if "error" in r:
                        print "Set failed: server connection error"
                        send_cancel(args.key,args.val,aloc,serverdata)
                        break
                    elif r["vote"]=="no":
                        print "Set failed: server voted no"
                        send_cancel(args.key,args.val,aloc,serverdata)
                        break
                    elif r["epoch"]!=epoch:
                        print "Set failed: epoch inconsistency"
                        send_cancel(args.key,args.val,aloc,serverdata)
                        break
                else:
                    send_commit(args.key,args.val,aloc,serverdata)
                    return


    else:
        response = common.send_receive_range(args.server, common2.SERVER_LOW, common2.SERVER_HIGH, vars(args))
        print response