def evaluate_leaderboard(follower_service):
        """
        Starts/changes/stops the time follower service according to
        who the current clock master is.
        """
        if not leaderboard:
            logger.debug("nobody on the leader board.")
            if follower_service is not None:
                follower_service.terminate()
            return None

        current_leader = leaderboard[0]
        leader_ep = discovery.peer_address(current_leader.uuid)
        leader_addr = urlparse(leader_ep).netloc.split(':')[0]
        logger.info('Following <{}>'.format(current_leader))
        if follower_service is None:
            # make new follower
            follower_service = Clock_Sync_Follower(leader_addr,
                                                   port=current_leader.port,
                                                   interval=10,
                                                   time_fn=time_fn,
                                                   jump_fn=jump_fn,
                                                   slew_fn=slew_fn)
        else:
            # update follower_service
            follower_service.host = leader_addr
            follower_service.port = current_leader.port

        return follower_service
예제 #2
0
    def evaluate_leaderboard(self):
        if not self.leaderboard:
            logger.debug("nobody on the leader board.")
            return

        current_leader = self.leaderboard[0]
        if self.discovery.uuid() != current_leader.uuid:
            # we are not the leader!
            leader_ep = self.discovery.peer_address(current_leader.uuid)
            leader_addr = urlparse(leader_ep).netloc.split(':')[0]
            if self.follower_service is None:
                # make new follower
                self.follower_service = Clock_Sync_Follower(leader_addr,
                                                            port=current_leader.port,
                                                            interval=10,
                                                            time_fn=self.get_time,
                                                            jump_fn=self.jump_time,
                                                            slew_fn=self.slew_time)
            else:
                # update follower_service
                self.follower_service.host = leader_addr
                self.follower_service.port = current_leader.port
            return

        # we are the leader
        logger.debug("we are the leader")
        if self.follower_service is not None:
            self.follower_service.terminate()
            self.follower_service = None

        if not self.has_been_master:
            self.has_been_master = 1.
            logger.debug('Become clock master with rank {}'.format(self.rank))
            self.announce_clock_master_info()
예제 #3
0
    def _handle_msg(self, uuid, name, msg, node):

        #Clock Sync master announce logic
        if SYNC_TIME_MASTER_ANNOUNCE in msg:

            self.last_master_announce = self.get_unadjusted_time()

            worthiness, port = msg.replace(SYNC_TIME_MASTER_ANNOUNCE,
                                           '').split(msg_delimeter)
            foreign_master_worthiness = float(worthiness)
            foreign_master_port = int(port)
            forein_master_uuid = UUID(bytes=uuid)
            foreign_master_address = node.peer_address(forein_master_uuid)
            foreign_master_ip = foreign_master_address.split('//')[-1].split(
                ':')[0]  # tcp://10.0.1.68:59149

            if isinstance(self.time_sync_node, Clock_Sync_Master):
                # who should yield?
                if self.clock_master_worthiness() == foreign_master_worthiness:
                    should_yield = node.uuid().int < forein_master_uuid.int
                else:
                    should_yield = self.clock_master_worthiness(
                    ) < foreign_master_worthiness

                if should_yield:
                    logger.warning("Yield Clock_Sync_Master to %s@%s" %
                                   (name, foreign_master_ip))
                    self.time_sync_node.stop()
                    self.time_sync_node = Clock_Sync_Follower(
                        foreign_master_ip,
                        port=foreign_master_port,
                        interval=10,
                        time_fn=self.get_time,
                        jump_fn=self.jump_time,
                        slew_fn=self.set_time)
                else:
                    logger.warning("Dominate as Clock_Sync_Master")
                    node.shouts(
                        self.group, SYNC_TIME_MASTER_ANNOUNCE +
                        "%s" % self.clock_master_worthiness() + msg_delimeter +
                        '%s' % self.time_sync_node.port)

            elif isinstance(self.time_sync_node, Clock_Sync_Follower):
                self.time_sync_node.host = foreign_master_ip
                self.time_sync_node.port = foreign_master_port
            else:
                self.time_sync_node = Clock_Sync_Follower(
                    foreign_master_ip,
                    port=foreign_master_port,
                    interval=10,
                    time_fn=self.get_time,
                    jump_fn=self.jump_time,
                    slew_fn=self.set_time)
                logger.debug("Clock synced with %s" % foreign_master_ip)

        elif TIMESTAMP_REQ in msg:
            node.whisper(UUID(bytes=uuid), TIMESTAMP + '%s' % self.get_time())

        elif NOTIFICATION in msg:
            notification_str = msg.replace(NOTIFICATION, '')
            try:
                notification = eval(notification_str)
            except Exception as e:
                logger.error(
                    'Recevied mal-formed remote notification. Payload:"%s"' %
                    notification_str)
            else:
                # This remote notification does not need to be network propagated again.
                notification['network_propagate'] = False
                # We also add some info on where it came from.
                notification['source'] = 'pupil_sync'
                notification['sync_node_name'] = name
                notification['sync_node_uuid'] = uuid
                # Finally we fire it.
                self.notify_all(notification)
        else:
            logger.warning('Received unknown message pattern. Payload:"%s"' %
                           msg)
예제 #4
0
    def on_notify(self, notification):
        """Synchronize time of Actors across local network.

        The notification scheme is used to handle interal timing
        and to talk to remote pers via the `Pupil_Groups` plugin.

        Reacts to notifications:
            ``time_sync.master_announcement``: React accordingly to annouce notification from remote peer.
            ``time_sync.master_announce_interval``: Re-annouce clock masterhood.
            ``time_sync.master_announce_timeout``: React accordingly when no master announcement has appeard whithin timeout.


        Emits notifications:
            ``time_sync.master_announcement``: Announce masterhood to remote peers (remote notification).
            ``time_sync.master_announce_interval``: Re-announce masterhood reminder (delayed notification).
            ``time_sync.master_announce_timeout``:  Timeout for foreind master announcement (delayed notification).

        """
        if notification['subject'].startswith('time_sync.master_announcement'):
            if self.is_master:
                if notification['worthiness'] > self.clock_master_worthiness():
                    #We need to yield.
                    self.time_sync_node.stop()
                    self.time_sync_node = None
                else:
                    #Denounce the lesser competition.
                    n = {
                        'subject': 'time_sync.master_announcement',
                        'host': self.time_sync_node.host,
                        'port': self.time_sync_node.port,
                        'worthiness': self.clock_master_worthiness(),
                        'remote_notify': 'all'
                    }
                    self.notify_all(n)

            if self.is_follower:
                # update follower info
                self.time_sync_node.host = notification['host']
                self.time_sync_node.port = notification['port']

            if self.is_nothing:
                # Create follower.
                logger.debug("Clock will sync with {}".format(
                    notification['host']))
                self.time_sync_node = Clock_Sync_Follower(
                    notification['host'],
                    port=notification['port'],
                    interval=10,
                    time_fn=self.get_time,
                    jump_fn=self.jump_time,
                    slew_fn=self.slew_time)

            if not self.is_master:
                #(Re)set the timer.
                self.notify_all(self.master_announce_timeout_notification)

        elif notification['subject'].startswith(
                'time_sync.master_announce_timeout'):
            if self.is_master:
                pass
            else:
                #We have not heard from a master in too long.
                logger.info("Elevate self to clock master.")
                self.time_sync_node = Clock_Sync_Master(
                    self.g_pool.get_timestamp)
                n = {
                    'subject': 'time_sync.master_announcement',
                    'host': self.time_sync_node.host,
                    'port': self.time_sync_node.port,
                    'worthiness': self.clock_master_worthiness(),
                    'remote_notify': 'all'
                }
                self.notify_all(n)
                self.notify_all(self.master_announce_interval_notification)

        elif notification['subject'].startswith(
                'time_sync.master_announce_interval'):
            # The time has come to remind others of our master hood.
            if self.is_master:
                n = {
                    'subject': 'time_sync.master_announcement',
                    'host': self.time_sync_node.host,
                    'port': self.time_sync_node.port,
                    'worthiness': self.clock_master_worthiness(),
                    'remote_notify': 'all'
                }
                self.notify_all(n)
                # Set the next annouce timer.
                self.notify_all(self.master_announce_interval_notification)