def update_holdback_queue_casual(self):
        """ Compare message timestamps to ensure casual ordering. """
        while True:
            new_holdback_queue = []
            removed_messages = []
            logging.debug("Holdback-queue size: %s" % (len(self.holdback_queue)))
            # check with vector timestamp, if ordering is correct or some messages are missing
            for sender, v, message in self.holdback_queue:
                should_remove = True
                for item in v:
                    if item == sender:
                        if v[item] != self.my_timestamp[item]:
                            should_remove = False
                        if v[item] > self.my_timestamp[item]:
                            should_remove = False
                if not should_remove:
                    new_holdback_queue.append((sender, v, message))
                else:
                    removed_messages.append((sender, v, message))

            # deliver the messages which are removed from holdback queue in this update cycle
            for sender, v, message in removed_messages:
                self.my_timestamp[sender] += 1  # update own vector_clock timestamp
                self.deliver(sender, message)

            self.holdback_queue = new_holdback_queue

            if not removed_messages:
                break
 def deliver(self, sender, message):
     """ Do something with the received message. """
     # TODO: save message to database
     if sender != self.hosts.current_member_ip:
         self.multicast_delivered(sender, message)
     else:
         logging.debug("received own message.")
         self.multicast_delivered(sender, message)
예제 #3
0
    def announce_service(self, timeout=1):
        data = "%s:%s" % ("SA", self.own_address)
        self.socket_sender.send_message(data, type="multicast")
        logging.debug("SA: service announcement...")

        time.sleep(timeout)

        logging.info("SA: service announcement finished.")
        logging.info("Discovered hosts: %s" % self.hosts.sorted_ring)
 def multicast_delivered(self, sender, message):
     """Callback function of ReliableSocketWorker on new message delivered"""
     parts = message.split(":")
     if parts[0] == "AA" and self.election.isLeader:
         data_set = self.database.get_range(start=-20)
         for msg in data_set:
             self.reliable_socket.unicast_send(sender, msg)
     else:
         logging.debug('Delivered "%s" from %s' % (message[:15], sender))
         self.database.insert(message)
 def message_queue_handler(self, running):
     """ Thread that actually sends out messages when send time <= current_time. """
     # TODO: if we have removed randomness in sending messages, can we simplify this?
     while running:
         (send_time, message, ip, port, msg_id) = self.queue.get(block=True)
         if send_time <= time.time():
             logging.debug("Send #%s to %s" % (msg_id, ip))
             self.sock.sendto(message, (ip, port))
         else:
             self.queue.put((send_time, message, ip, port, msg_id))
             time.sleep(0.01)
 def insert(self, item):
     existing = False
     for entry in self.database:
         item_parts = item.split(":")
         parts = entry.split(":")
         if item_parts[1] == parts[1]:
             existing = True
             break
     if existing is True:
         self.update(item)
     else:
         self.database.append(item)
     logging.debug("Inserted %s. DB Size: %s" % (item, len(self.database)))
    def __init__(self, election, reliable_socket, database):
        super(ContentProvider, self).__init__()
        self.election = election
        self.database = database
        self.server = WebsocketServer(config["content_websocket_port"],
                                      host="0.0.0.0")
        self.server.set_fn_new_client(self.new_client)
        self.server.set_fn_client_left(self.client_left)
        self.server.set_fn_message_received(self.message_received)
        self.quote_id = uuid.uuid4()

        # need reliable_socket for data replication
        self.reliable_socket = reliable_socket
        self.reliable_socket.set_fn_delivered(self.multicast_delivered)

        logging.debug("Starting ContentProvider")

        self._ask_for_initial_database()

        self.last_update = time.time()
    def unicast_receive(self):
        """ Receive UDP messages from other chat processes and store them in the holdback queue.
            Returns True if new message was received. """

        data, _ = self.sock.recvfrom(self.message_max_size)
        [sender, message_id, is_ack, message_timestamp, message] = self.unpack_message(
            data
        )

        logging.debug("Received #%s from %s" % (message_id, sender))

        # add sender to timestamps if not yet
        if sender not in self.my_timestamp:
            self.my_timestamp[sender] = message_timestamp[sender]

        # check if hosts in hold-back queue are up-to-date with ring
        new_timestamp = {}
        for host in self.my_timestamp:
            if host in self.hosts.members:
                new_timestamp[host] = self.my_timestamp[host]
        self.my_timestamp = new_timestamp
        
        logging.debug("Vector Clock: %s" % self.my_timestamp)

        # check if ack message type
        if is_ack:
            # save that ack was send
            self.has_acknowledged[(sender, message_id)] = True
        else:
            # if normal message, send acknowledgement to the sender
            self.unicast_send(sender, "ACK", msg_id=message_id, is_ack=True)
            # check if message was send more than once
            if (sender, message_id) not in self.has_received:
                self.has_received[(sender, message_id)] = True
                self.holdback_queue.append((sender, message_timestamp, message))
                self.update_holdback_queue_casual()
                return True
        return False
예제 #9
0
 def __init__(self, current_member_ip):
     logging.debug("Ring initialized")
     self.current_member_ip = current_member_ip
     self.add_host(self.current_member_ip)
예제 #10
0
 def add_client(self, host):
     if host not in self.clients:
         self.clients.append(host)
     else:
         logging.debug("Client %s was already added" % host)
예제 #11
0
 def remove_host(self, host):
     if host in self.members:
         self.members.remove(host)
         self.sorted_ring = self._form_ring(self.members)
     else:
         logging.debug("Host %s was already removed" % host)
예제 #12
0
 def add_host(self, host):
     if host not in self.members:
         self.members.append(host)
         self.sorted_ring = self._form_ring(self.members)
     else:
         logging.debug("Host %s was already discovered" % host)