Exemple #1
0
 def testDownloadFiles(self):
     """ For every file in upload/ download them
         from DHT to download/
     """
     for i,file in enumerate(glob.glob("upload/*")):
         with open(file.replace("upload","download"), "wb") as f:
             command = DHTCommand(DHTCommand.GET,file)
             self.dht.sendcommand(self.servers[i % len(self.ports)],command,f)
         command = DHTCommand(DHTCommand.GET,"key for:"+file)
         print self.dht.sendcommand(self.servers[i % len(self.ports)],command)
Exemple #2
0
 def testDeleteFiles(self):
     """ Open files in upload/ in binary mode
         and send them to dht
     """
     for i, file in enumerate(glob.glob("upload/*")):
         command = DHTCommand(DHTCommand.DEL, file)
         response = self.dht.sendcommand(self.servers[i % len(self.ports)],
                                         command)
         self.assertEquals(response, "DEL OK " + file)
         command = DHTCommand(DHTCommand.DEL, "key for:" + file,
                              "this is the key for:" + file)
         response = self.dht.sendcommand(self.servers[i % len(self.ports)],
                                         command)
         self.assertEquals(response, "DEL OK key for:" + file)
Exemple #3
0
    def initialise_hashring(self):
        """ Initialize the hash ring.
            If `self.remote_server` is not note, get it from remote_server
            or else just create a new one.
            Also set the hash_ring in `self.dht_table`
        """
        if self.remote_server:
            remote_host, remote_port = self.remote_server.split(":")
            remote_server = Server(remote_host, remote_port)
            # Send a join command to the existing server
            command = DHTCommand(DHTCommand.JOIN, self.this_server)
            ring = self.client.sendcommand(remote_server, command)
            logging.debug("got ring from server: %s", str(ring))
            # Get replicas
            if not ring:
                raise RuntimeError(
                    ("Could not reach server: %s" % str(remote_server)))
            nodes, replicas = ring.split(",")
            # Convert |-separated list to Server-instances
            nodes = map(
                lambda server_string: Server(
                    server_string.split(":")[0],
                    server_string.split(":")[1]), nodes.split("|"))
            # Initialize local hash ring
            self.hash_ring = HashRing(nodes, int(replicas))
            self.hash_ring.add_node(self.this_server)
        else:
            # First server so this server is added
            self.hash_ring = HashRing([self.this_server], self.replicas)

        # Initialize the hash map
        self.dht_table = MyDHTTable(self.this_server, self.hash_ring)
Exemple #4
0
    def server_thread(self, client_sock):
        """ Thread that handles a client
            `client_sock` is the socket where the client is connected
            perform the operation and connect to another server if necessary
        """
        rawcommand = self.client.read_from_socket(_block, client_sock)
        command = DHTCommand().parse(rawcommand)

        logging.debug("received command: %s", str(command))
        if command.action in [DHTCommand.PUT, DHTCommand.GET, DHTCommand.DEL]:
            # Perform the command and any replication
            status = self.handle_replica_command(command, client_sock)
        elif command.action == DHTCommand.JOIN:
            # A client wants to join the ring
            status = self.add_new_node(command.key)
        elif command.action == DHTCommand.ADDNODE:
            # A new client has joined and should be added to this servers ring
            self.hash_ring.add_node(command.key)
            status = "added by " + str(self.this_server)
        elif command.action == DHTCommand.LEAVE:
            self.hash_ring.remove_node(command.key)
            status = "removed: " + str(command.key)
        elif command.action == DHTCommand.REMOVE:
            # A server has left the ring without decommission
            status = self.remove_node(command.key, command.forwarded)
        elif command.action == DHTCommand.WHEREIS:
            # Just return the hostnames that holds a key
            status = ", ".join(
                map(lambda s: str(s),
                    self.hash_ring.get_replicas(command.key)))
        elif command.action == DHTCommand.BALANCE:
            # Load balance this node
            status = self.load_balance(command.forwarded)
        elif command.action == DHTCommand.UNKNOWN:
            # Just send error and close socket
            status = "UNKNOWN_COMMAND"
            client_sock.send(status)
            client_sock.close()
            return
        else:
            # All other commands ends up in the table
            status = self.dht_table.perform(command)

        # Send length to all clients except a web browser (it will end up in the HTML)
        if command.action != DHTCommand.HTTPGET and command.action != DHTCommand.HTTPGETKEY:
            self.client.send_length_to_socket(len(status), client_sock)

        # Send response to client
        self.client.send_to_socket(status, len(status), client_sock)

        # Shutdown write end of socket
        client_sock.shutdown(SHUT_WR)
        # Close socket
        client_sock.close()
Exemple #5
0
    def load_balance(self, forwarded):
        """ Load balance this node and then all other.
            if `forwarded` is False BALANCE will be sent to
            all other nodes.
        """
        status = self.internal_load_balance()

        if not forwarded:
            # And load balance the others
            command = DHTCommand(DHTCommand.BALANCE)
            self.forward_command(command)

        return status
Exemple #6
0
    def cmdlinestart(self):
        """ Parse command line parameters and start client
        """
        try:
            port = int( self.getarg("-p") or self.getarg("--port",50140))
            host = self.getarg("-h") or self.getarg("--hostname","localhost")
            key = self.getarg("-k") or self.getarg("--key")
            server = Server(host,port)
            command = self.getarg('-c') or self.getarg('--command')
            value = self.getarg("-val") or self.getarg("--value")
            file = self.getarg("-f") or self.getarg("--file")
            outfile = self.getarg("-o") or self.getarg("--outfile")

            logging.debug("command: %s %s %s %s", str(server), command, key, value)
            if command is None or server is None or file and value:
                self.help()
                
            command = self.get_command(command)
            if file:
                f = open(file, "rb")
                command = DHTCommand(command,key,f)
            else:
                command = DHTCommand(command,key,value)

            if outfile:
                # File was an argument, supply it
                with open(outfile, "wb") as out:
                    print self.sendcommand(server,command,out)
            else:
                # Print output
                data = self.sendcommand(server,command)
                if data and len(data) < 1024:
                    print data
                elif data:
                    print "Return data is over 1K, please use the -o option to redirect it to a file"
            if file:
                f.close()
        except TypeError:
            self.help()
Exemple #7
0
    def decommission(self):
        """ Remove self from hash_ring and move all existing data
            to new nodes.
        """
        self.ring_lock.acquire()
        self.hash_ring.remove_node(self.this_server)

        # First remove this server from all other servers
        command = DHTCommand(DHTCommand.LEAVE, self.this_server)
        self.forward_command(command)

        # Load balance only on this node
        self.load_balance(True)
        self.ring_lock.release()
Exemple #8
0
    def internal_load_balance(self):
        """ Go through all keys in map and check with all replica server
            if they have an older version of the key, send the value.
            if they have a newer version, get the value.
        """

        # For all keys in this map
        for key in self.dht_table.get_keys():
            key_is_at = self.hash_ring.get_replicas(key, self.this_server)
            for server in key_is_at:
                command = DHTCommand(DHTCommand.HASKEY, key)
                status = self.client.sendcommand(server, command)
                if not status:
                    # None was returned, servers is probably down
                    logging.error("Got no timestamp from %s, could be dead",
                                  str(server))
                    continue
                remote_time = float(status)
                local_timestamp = float(self.dht_table.perform(command))
                if remote_time < local_timestamp:
                    # Key is missing or old
                    logging.debug("Copying: %s to %s", key, server)
                    value = self.dht_table.perform(
                        DHTCommand(DHTCommand.GET, key))
                    command = DHTCommand(DHTCommand.PUT, key, value,
                                         local_timestamp)
                    status = self.client.sendcommand(server, command)
                    logging.debug("status: %s", status)
                elif remote_time > local_timestamp:
                    # Remote object is newer, get it
                    logging.debug("Copying: %s from %s", key, server)
                    command = DHTCommand(DHTCommand.GET, key)
                    value = self.client.sendcommand(server, command)
                    status = self.dht_table.perform(
                        DHTCommand(DHTCommand.PUT, key, value, remote_time))
                    logging.debug(status)
        return "BALANCE ok"
Exemple #9
0
    def remove_node(self, node, forwarded):
        """ Remove `node` from ring
            If not `forwarder` tell all other nodes
            This usually happens if a node dies without being
            able to do a decommission.
        """
        self.ring_lock.acquire()
        self.hash_ring.remove_node(node)

        if not forwarded:
            # Add the new server to all existing nodes
            command = DHTCommand(DHTCommand.REMOVE, node)
            self.forward_command(command)

            # Rebalance all nodes
            self.load_balance(False)

        self.ring_lock.release()
        return "REMOVE ok"
Exemple #10
0
    def add_new_node(self, new_node):
        """ Adds a new server to all existing nodes and
            returns a |-separated list of the current ring
            ","  the number of replicas used.
            Example:
            localhost:50140|localhost:50141,3
        """
        self.ring_lock.acquire()
        logging.debug("adding: %s", new_node)
        host, port = new_node.split(":")
        newserver = Server(host, port)
        self.hash_ring.remove_node(newserver)

        # Add the new server to all existing nodes
        command = DHTCommand(DHTCommand.ADDNODE, newserver)
        self.forward_command(command)

        # Convert to a string list
        ring = map(lambda serv: str(serv), self.hash_ring.get_nodelist())
        # Add new server to this ring
        self.hash_ring.add_node(newserver)
        # Return |-separated list of nodes
        self.ring_lock.release()
        return "|".join(ring) + "," + str(self.hash_ring.replicas)
Exemple #11
0
 def get_command(self, string):
     for i,command in DHTCommand().allcommands.iteritems():
         if command == string.upper():
             return i
     else:
         return 0