Esempio n. 1
0
def findSuccessor(key, target, msg=None):
    global successor

    # If key is somewhere between self and self.successor, then self.successor directly succeeds key
    if successor != None and keyInRange(
            key, me.chord_id, successor.chord_id, inc_end=True):
        # Build and send response
        if msg is None:
            msg = newMsgDict()
        msg['suc_ip'] = successor.ip
        sendCtrlMsg(target, c_msg.RETURN_SUCCESSOR, msg)
    # Otherwise, send request to successor
    else:
        # Get node to send request to
        if successor == None:
            dst = tracker
        elif using_finger_table:
            dst = closestPreceedingNode(
                key)  # TODO: if dst == me, we might have a problem
        else:
            dst = successor

        # Build and send request
        if msg is None:
            msg = newMsgDict()
        msg['key'] = key
        msg['target'] = target
        sendCtrlMsg(dst.ip, c_msg.FIND_SUCCESSOR, msg)
Esempio n. 2
0
def leave():
    global inNetwork, predecessor, successor

    inNetwork = False
    myLogger.mnPrint("Leaving the network...")

    # Send all of our current files to our successor
    if successor is not None:
        msg = newMsgDict()
        for f in list(entries.keys()):
            msg['filename'] = f
            sendFile(successor.ip, msg, readFromFile=True, rmEntry=True)

    if successor is not None and predecessor is not None:
        # Tell our successor we are leaving and pass them our predecessor
        msg = newMsgDict()
        msg['pred_ip'] = predecessor.ip
        sendCtrlMsg(successor.ip, c_msg.LEAVING, msg)

        # Tell our predecessor we are leaving and pass them our successor
        msg = newMsgDict()
        msg['suc_ip'] = successor.ip
        sendCtrlMsg(predecessor.ip, c_msg.LEAVING, msg)

    successor = None
    predecessor = None
Esempio n. 3
0
def refresh():
    global successor, predecessor, refresh_rate, inNetwork

    while True:
        if successor != None:
            # If we were waiting on a response from our successor and never got one, assume they died
            if waitingForAlive(successor.ip):
                # Inform the tracker that this node is dead so we can recover any files it was hosting
                msg = newMsgDict()
                msg['dead_node'] = successor.ip
                msg['pred_ip'] = me.ip
                sendCtrlMsg(tracker.ip, c_msg.SOMEONE_DIED, msg)

                myLogger.mnPrint(
                    "Our successor {0} has died!".format(successor))
                waiting_for_alive_resp[successor.ip] = False
                successor = None
                findSuccessor(me.chord_id, me.ip)
                successor = me
            # Will get our successor's predecessor and call stabilize on return
            else:
                waiting_for_alive_resp[successor.ip] = True
                sendCtrlMsg(successor.ip, c_msg.GET_PREDECESSOR, newMsgDict())

        # Update our finger table
        if using_finger_table and inNetwork:
            fixFingers()

        # Handle predecessor death
        if predecessor != None:
            # If we were waiting on a response from our predecessor and never got one, assume they died
            if waitingForAlive(
                    predecessor.ip) and predecessor.ip is not successor.ip:
                myLogger.mnPrint(
                    "Our predecessor {0} has died!".format(predecessor))
                waiting_for_alive_resp[predecessor.ip] = False
                predecessor = None
            else:
                # Check to see if the predecessor is still alive
                waiting_for_alive_resp[predecessor.ip] = True
                sendCtrlMsg(predecessor.ip, c_msg.CHECK_ALIVE, newMsgDict())
                # Send any files that shouldn't be here to the predecessor
                sendFilesToPred()

        # Nodes should randomly leave/join the network or fail outright
        if not is_tracker:
            if bernoulli(leave_join_prob):
                if inNetwork:
                    leave()
                else:
                    join()
            if bernoulli(fail_prob):
                fail()

        # Wait for short time
        time.sleep(refresh_rate)
Esempio n. 4
0
 def get_file_list(self):
     '''Request available files
     '''
     self.last_request = [c_msg.GET_FILE_LIST]
     msg = newMsgDict()
     msg["client_ip"] = self.ip
     msg["hops"] = 0
     self.sendMessage(c_msg.GET_FILE_LIST, msg)
Esempio n. 5
0
 def entries(self):
     '''Tell server to write entries to log
     '''
     self.last_request = [c_msg.ENTRIES]
     msg = newMsgDict()
     msg["client_ip"] = self.ip
     msg["hops"] = 0
     self.sendMessage(c_msg.ENTRIES, msg)
Esempio n. 6
0
def fixFingers():
    '''Refresh the finger table entries periodicially'''
    global finger_table, finger_table_size

    for key in finger_table.keys():
        msg = newMsgDict()
        msg["finger"] = key
        findSuccessor(key, me.ip, msg)
Esempio n. 7
0
 def get_file(self, filename):
     '''Request a file
     '''
     self.last_request = [c_msg.GET_FILE, filename]
     msg = newMsgDict()
     msg['filename'] = filename
     msg["client_ip"] = self.ip
     msg["hops"] = 0
     self.sendMessage(c_msg.GET_FILE, msg)
Esempio n. 8
0
 def insert_file(self, filename):
     ''' Insert a file
     '''
     self.last_request = [c_msg.INSERT_FILE, filename]
     try:
         with open(self.file_dir_path + filename) as f_in:
             content = f_in.read()
             msg = newMsgDict()
             msg['filename'] = filename
             msg['content'] = content
             msg['client_ip'] = self.ip
             msg["hops"] = 0
             self.sendMessage(c_msg.INSERT_FILE, msg)
     except IOError as e:
         self.myLogger.mnPrint("Error: last request:{0} failed!".format(
             self.last_request))
         self.myLogger.mnPrint(e)
Esempio n. 9
0
def sendFilesToPred():
    for f, cn in list(entries.items()):
        # For each chord_id for this file
        k_count = 0
        for k in cn.chord_id:
            # Count if this key should belong to us
            if keyInRange(k, predecessor.chord_id, me.chord_id, inc_end=True):
                k_count += 1

        # Send file to predecessor if none of the keys were for us
        if k_count == 0:
            myLogger.mnPrint(
                "Transferring file ({0}) to predecessor ({1}) from file balancing"
                .format(cn, predecessor))
            msg = newMsgDict()
            msg['filename'] = f
            sendFile(predecessor.ip, msg, readFromFile=True, rmEntry=True)
Esempio n. 10
0
def stabilize(x):
    global successor

    if successor is None:
        return

    waiting_for_alive_resp[successor.ip] = False

    # If x is closer than our current successor, it is our new successor
    if x != None and keyInRange(x.chord_id, me.chord_id, successor.chord_id):
        successor = x
        waiting_for_alive_resp[successor.ip] = False
        myLogger.mnPrint("Successor updated by stabilize: " + str(successor))

    # Notify successor that we are its predecessor
    msg = newMsgDict()
    msg['pred_ip'] = me.ip
    sendCtrlMsg(successor.ip, c_msg.NOTIFY_PREDECESSOR, msg)
Esempio n. 11
0
def notify(node):
    global predecessor

    # If the given id is between our current predecessor and us (or if we had no predecessor)
    #   then set it to be our predecessor
    if predecessor == None or keyInRange(node.chord_id, predecessor.chord_id,
                                         me.chord_id):
        myLogger.mnPrint("Predecessor updated by notify: " + str(node))

        # Transfer all necessary files to predecessor
        for f, cn in list(entries.items()):
            # For each chord_id for this file
            k_count = 0
            for k in cn.chord_id:
                # Count if this key should move to the new predecessor
                if predecessor is None:
                    if keyInRange(k, me.chord_id, node.chord_id, inc_end=True):
                        k_count += 1
                elif keyInRange(k,
                                predecessor.chord_id,
                                node.chord_id,
                                inc_end=True):
                    k_count += 1

            # Send file to predecessor if necessary, rm this entry if all keys should go to predecessor
            if k_count > 0:
                myLogger.mnPrint(
                    "Transferring file ({0}) to new predecessor ({1}) from notify"
                    .format(cn, node))
                msg = newMsgDict()
                msg['filename'] = f
                sendFile(node.ip,
                         msg,
                         readFromFile=True,
                         rmEntry=(k_count == num_replicates))

        predecessor = node
        waiting_for_alive_resp[predecessor.ip] = False
Esempio n. 12
0
def ctrlMsgReceived():
    global successor, predecessor, entries, outstanding_file_reqs, finger_table, tracker_node_ip, inNetwork

    # Get data from socket
    try:
        data, addr = control_sock.recvfrom(1024)
    except socket.error as e:
        print(e)
        return

    # Drop all packets if we are not participating in the network
    if not inNetwork:
        return

    # Parse message type, update hops, and respond accordingly
    msg = json.loads(str(data))
    msg_type = msg['msg_type']
    msg["hops"] += 1
    myLogger.mnPrint("msg type:{0} rcvd from {1}: msg:{2}".format(
        msg_type, addr[0], myLogger.pretty_msg(msg)),
                     debug=False)

    # We are supposed to find target's successor
    if msg_type == c_msg.FIND_SUCCESSOR:
        key = msg['key']
        target = msg['target']
        #filename = msg['filename']
        findSuccessor(key, target, msg)

    # Someone returned our find successor query
    elif msg_type == c_msg.RETURN_SUCCESSOR:
        suc_ip = msg['suc_ip']
        filename = msg['filename']
        finger = msg['finger']
        # No filename indicates we wanted to find our successor
        if filename is None:
            # Finger update
            if finger is not None:
                finger_table[finger] = ChordNode(suc_ip)
                #myLogger.mnPrint(me.print_finger_table(finger_table))
            # Successor update
            else:
                successor = ChordNode(suc_ip)
                myLogger.mnPrint(
                    "Successor updated by find successor: {0}".format(
                        successor))
        # Filename indicates we wanted to find a file's location
        else:
            fileNode = ChordNode(filename, isFile=True)
            myLogger.mnPrint("Found file ({0}) ({1}) at ({2})".format(
                fileNode, msg['key'], ChordNode(suc_ip)))
            if outstanding_file_reqs[filename] == c_msg.OP_SEND_FILE:
                # When we get to this point, assume that file content is already present in msg
                sendFile(suc_ip, msg)
            elif outstanding_file_reqs[filename] == c_msg.OP_REQ_FILE:
                sendCtrlMsg(suc_ip, c_msg.REQUEST_FILE, msg)
            elif outstanding_file_reqs[filename] == c_msg.OP_INSERT_FILE:
                sendCtrlMsg(suc_ip, c_msg.INSERT_FILE, msg)

    # Someone wants to know who our predecessor is
    elif msg_type == c_msg.GET_PREDECESSOR:
        msg = newMsgDict()
        msg['pred_ip'] = None if predecessor is None else predecessor.ip
        sendCtrlMsg(addr[0], c_msg.RETURN_PREDECESSOR, msg)

    # Our successor told us who their predecessor is
    elif msg_type == c_msg.RETURN_PREDECESSOR:
        pred_ip = msg['pred_ip']
        stabilize(None if pred_ip == None else ChordNode(pred_ip))

    # Someone told us that they are our predecessor
    elif msg_type == c_msg.NOTIFY_PREDECESSOR:
        pred_ip = msg['pred_ip']
        if pred_ip is not None:
            notify(ChordNode(pred_ip))

    # Someone wants to know we are alive
    elif msg_type == c_msg.CHECK_ALIVE:
        sendCtrlMsg(addr[0], c_msg.AM_ALIVE, msg)

    # Someone told us they were alive
    elif msg_type == c_msg.AM_ALIVE:
        waiting_for_alive_resp[addr[0]] = False

    # Someone sent us a file
    elif msg_type == c_msg.SEND_FILE:
        filename = msg['filename']
        fileNode = ChordNode(filename, isFile=True)
        content = msg['content']
        '''
        # If this file was for a recovery, make sure it was meant for us, otherwise reinsert
        lost_key = msg['hash']
        if lost_key is not None and predecessor is not None:
            if not keyInRange(lost_key, predecessor.ip, me.ip, inc_end=True):
                myLogger.mnPrint("Received {0} to recover at {1}, but this doesn't belong to us".format(fileNode, lost_key))
                # Wait, and then restart request to recover file
                t = threading.Timer(2 * refresh_rate, lambda: sendCtrlMsg(tracker.ip, c_msg.SOMEONE_DIED, msg))
                t.start()
                return
        '''

        # Save this file
        with open("{0}/{1}".format(file_dir_path, filename), "w") as newFile:
            newFile.write(content)
        entries[filename] = fileNode
        myLogger.mnPrint("Received file " + filename + " from " + str(addr[0]))

        # If file from the client -> tell them insertion was successful
        if msg["client_ip"] != None:
            sendCtrlMsg(msg["client_ip"], c_msg.INSERT_FILE, msg)
        # Current responsible entries
        myLogger.mnPrint("entry keys: {0}".format(entries.keys()))

    # Someone wants a file from us
    elif msg_type == c_msg.REQUEST_FILE:
        # Send directly to client
        if msg["client_ip"] is not None:
            myLogger.mnPrint(msg['filename'] + " requested from " +
                             msg["client_ip"])
            sendFile(msg["client_ip"], msg, readFromFile=True)
        # Send to node who requested it
        # TODO: don't think this should happen
        else:
            sendFile(addr[0], msg, readFromFile=True, rmEntry=True)
            myLogger.mnPrint(msg['filename'] + " requested from " + addr[0])

    # We were informed of the death of a node
    elif msg_type == c_msg.SOMEONE_DIED:
        dead_node = ChordNode(msg['dead_node'])
        dn_pred = ChordNode(msg['pred_ip'])
        myLogger.mnPrint("Heard that {0} died".format(dead_node))

        # For every file in the network...
        for f, cn in allFiles.items():
            # See if a copy of it should have been in dn
            keys_not_in_dn = []
            dn_fkey = 0
            for k in cn.chord_id:
                if keyInRange(k,
                              dn_pred.chord_id,
                              dead_node.chord_id,
                              inc_end=True):
                    dn_fkey = k
                else:
                    keys_not_in_dn.append(k)

            # If all copies were there, there is no chance of recovery and the file is lost
            if len(keys_not_in_dn) == 0:
                pass  # TODO: mark file as lost
            # If at least one copy was there, find another node that is hosting the file
            elif len(keys_not_in_dn) < num_replicates:
                myLogger.mnPrint(
                    "Attempting to re-insert {0} ({1}) from {2}".format(
                        f, dn_fkey, keys_not_in_dn[0]))
                outstanding_file_reqs[f] = c_msg.OP_INSERT_FILE
                msg['filename'] = f
                msg['hash'] = dn_fkey
                findSuccessor(keys_not_in_dn[0], me.ip, msg)

    # We were informed that a node is leaving
    elif msg_type == c_msg.LEAVING:
        suc_ip = msg['suc_ip']
        pred_ip = msg['pred_ip']
        if suc_ip is not None:
            successor = ChordNode(suc_ip)
            myLogger.mnPrint(
                "Successor updated by prev leaving: {0}".format(successor))
        elif pred_ip is not None:
            predecessor = ChordNode(pred_ip)
            myLogger.mnPrint(
                "Predecessor updated by prev leaving: {0}".format(predecessor))

    # We are supposed to insert a file into the network
    elif msg_type == c_msg.INSERT_FILE:
        filename = msg['filename']
        outstanding_file_reqs[filename] = c_msg.OP_SEND_FILE
        fileNode = ChordNode(filename, isFile=True)

        # If from client, we are inserting a file for the first time
        if msg['client_ip'] is not None:
            myLogger.mnPrint("Inserting " + str(fileNode) +
                             " into the network")
            allFiles[
                filename] = fileNode  # TODO: only set on confirm? or should we assume this always succeeds?
            for chord_id in fileNode.chord_id:
                findSuccessor(chord_id, me.ip, msg)
        # Otherwise, we are reinserting a file that we think was partially lost
        else:
            # Find the new location of the lost key for reinsertion
            if filename in entries:
                lost_key = msg['hash']
                myLogger.mnPrint(
                    "Reinserting {0} ({1}) into the network".format(
                        fileNode, lost_key))
                with open(file_dir_path + filename) as f:
                    msg['content'] = f.read()
                findSuccessor(lost_key, me.ip, msg)
            # If our network hasn't stabilized yet, we may have falsely received this request
            else:
                # Wait, and then restart request to recover file
                t = threading.Timer(
                    2 * refresh_rate,
                    lambda: sendCtrlMsg(tracker.ip, c_msg.SOMEONE_DIED, msg))
                t.start()

    # We are supposed to retrieve a file from the network
    elif msg_type == c_msg.GET_FILE:
        filename = msg['filename']
        outstanding_file_reqs[filename] = c_msg.OP_REQ_FILE
        fileNode = ChordNode(filename, isFile=True)
        myLogger.mnPrint("Retrieving " + str(fileNode))
        for k in fileNode.chord_id:
            findSuccessor(k, me.ip, msg)

    # send all known entries back to client if tracker
    elif msg_type == c_msg.GET_FILE_LIST:
        if me.ip == tracker_node_ip:
            msg["file_list"] = allFiles.keys()
            sendCtrlMsg(msg["client_ip"], c_msg.GET_FILE_LIST, msg)
    # avgs keys per node
    elif msg_type == c_msg.ENTRIES:
        # log entries and pass request along
        myLogger.mnPrint("entries: {0}".format(print_entries()))
        # we've come full circle -> tell client about success
        if successor.ip == tracker_node_ip or\
           (successor.ip == tracker_node_ip and successor.ip == me.ip):
            sendCtrlMsg(msg["client_ip"], c_msg.ENTRIES, msg)
        else:
            myLogger.mnPrint("Sending entries request forward: {0}".format(
                successor.ip))
            sendCtrlMsg(successor.ip, c_msg.ENTRIES, msg)

    # TODO: when will this happen?
    elif msg_type == c_msg.ERR:
        pass