예제 #1
0
 def handle_collect(self, msg):
     """Collect updates from clients"""
     kvmsg = KVMsg.from_msg(msg)
     self.sequence += 1
     kvmsg.sequence = self.sequence
     kvmsg.send(self.publisher)
     ttl = float(kvmsg.get(b'ttl', 0))
     if ttl:
         kvmsg[b'ttl'] = b'%f' % (time.time() + ttl)
     kvmsg.store(self.kvmap)
     logging.info(f"I: publishing update={self.sequence:d}")
예제 #2
0
 def handle_collect(self, msg):
     """Collect updates from clients"""
     kvmsg = KVMsg.from_msg(msg)
     self.sequence += 1
     kvmsg.sequence = self.sequence
     kvmsg.send(self.publisher)
     ttl = float(kvmsg.get('ttl', 0))
     if ttl:
         kvmsg['ttl'] = time.time() + ttl
     kvmsg.store(self.kvmap)
     logging.info("I: publishing update=%d", self.sequence)
예제 #3
0
 def handle_collect(self, msg):
     """Collect updates from clients"""
     kvmsg = KVMsg.from_msg(msg)
     self.sequence += 1
     kvmsg.sequence = self.sequence
     kvmsg.send(self.publisher)
     ttl = kvmsg.get('ttl')
     if ttl is not None:
         kvmsg['ttl'] = time.time() + ttl
     kvmsg.store(self.kvmap)
     logging.info("I: publishing update=%d", self.sequence)
예제 #4
0
 def handle_collect(self, msg):
     """Collect updates from clients"""
     kvmsg = KVMsg.from_msg(msg)
     logging.info("I: received state update on collector: %s" % kvmsg)
     self.sequence += 1
     kvmsg.sequence = self.sequence
     logging.info("I: publishing update: %s", kvmsg)
     kvmsg.send(self.publisher)
     ttl = kvmsg.get('ttl')
     if ttl is not None:
         kvmsg['ttl'] = time.time() + int(ttl)
     kvmsg.store(self.kvmap)
예제 #5
0
    def handle_subscriber(self, msg):
        """Collect updates from peer (master)
        We're always slave when we get these updates
        """
        if self.master:
            logging.warn("received subscriber message, but we are master %s",
                         msg)
            return

        # Get state snapshot if necessary
        if self.kvmap is None:
            self.kvmap = {}
            snapshot = self.ctx.socket(zmq.DEALER)
            snapshot.linger = 0
            snapshot.connect("tcp://localhost:%i" % self.peer)

            logging.info("I: asking for snapshot from: tcp://localhost:%d",
                         self.peer)
            snapshot.send_multipart([b"ICANHAZ?", b''])
            while True:
                try:
                    kvmsg = KVMsg.recv(snapshot)
                except KeyboardInterrupt:
                    # Interrupted
                    self.bstar.loop.stop()
                    return
                if kvmsg.key == b"KTHXBAI":
                    self.sequence = kvmsg.sequence
                    break  # Done
                kvmsg.store(self.kvmap)

            logging.info("I: received snapshot=%d", self.sequence)

        # Find and remove update off pending list
        kvmsg = KVMsg.from_msg(msg)
        # update float ttl -> timestamp
        ttl = float(kvmsg.get(b'ttl', 0))
        if ttl:
            kvmsg[b'ttl'] = b'%f' % (time.time() + ttl)

        if kvmsg.key != b"HUGZ":
            if not self.was_pending(kvmsg):
                # If master update came before client update, flip it
                # around, store master update (with sequence) on pending
                # list and use to clear client update when it comes later
                self.pending.append(kvmsg)

            # If update is more recent than our kvmap, apply it
            if (kvmsg.sequence > self.sequence):
                self.sequence = kvmsg.sequence
                kvmsg.store(self.kvmap)
                logging.info("I: received update=%d", self.sequence)
예제 #6
0
 def handle_subscriber(self, msg):
     """Collect updates from peer (master)
     We're always slave when we get these updates
     """
     if self.master:
         logging.warn("received subscriber message, but we are master %s", msg)
         return
     
     # Get state snapshot if necessary
     if self.kvmap is None:
         self.kvmap = {}
         snapshot = self.ctx.socket(zmq.DEALER)
         snapshot.linger = 0
         snapshot.connect("tcp://localhost:%i" % self.peer)
         
         logging.info ("I: asking for snapshot from: tcp://localhost:%d",
                     self.peer)
         snapshot.send_multipart(["ICANHAZ?", ''])
         while True:
             try:
                 kvmsg = KVMsg.recv(snapshot)
             except KeyboardInterrupt:
                 # Interrupted
                 self.bstar.loop.stop()
                 return
             if kvmsg.key == "KTHXBAI":
                 self.sequence = kvmsg.sequence
                 break          # Done
             kvmsg.store(self.kvmap)
     
         logging.info ("I: received snapshot=%d", self.sequence)
     
     # Find and remove update off pending list
     kvmsg = KVMsg.from_msg(msg)
     # update integer ttl -> timestamp
     ttl = kvmsg.get('ttl')
     if ttl is not None:
         kvmsg['ttl'] = time.time() + ttl
     
     if kvmsg.key != "HUGZ":
         if not self.was_pending(kvmsg):
             # If master update came before client update, flip it
             # around, store master update (with sequence) on pending
             # list and use to clear client update when it comes later
             self.pending.append(kvmsg)
     
         # If update is more recent than our kvmap, apply it
         if (kvmsg.sequence > self.sequence):
             self.sequence = kvmsg.sequence
             kvmsg.store(self.kvmap)
             logging.info ("I: received update=%d", self.sequence)
예제 #7
0
 def handle_collect(self, msg):
     """Collect updates from clients
     
     If we're master, we apply these to the kvmap
     If we're slave, or unsure, we queue them on our pending list
     """
     kvmsg = KVMsg.from_msg(msg)
     if self.master:
         self.sequence += 1
         kvmsg.sequence = self.sequence
         kvmsg.send(self.publisher)
         ttl = kvmsg.get('ttl')
         if ttl is not None:
             kvmsg['ttl'] = time.time() + ttl
         kvmsg.store(self.kvmap)
         logging.info("I: publishing update=%d", self.sequence)
     else:
         # If we already got message from master, drop it, else
         # hold on pending list
         if not self.was_pending(kvmsg):
             self.pending.append(kvmsg)
예제 #8
0
def dkv_agent(ctx, pipe, connected_event):
    """ Asynchronous agent manages server pool and handles request/reply
    dialog when the application asks for it. """

    agent = DkvAgent(ctx, pipe, connected_event)
    server = None

    while True:
        poller = zmq.Poller()
        poller.register(agent.pipe, zmq.POLLIN)
        poll_timer = None
        server_socket = None

        if agent.state == agent.STATES.INITIAL:
            """In this state we ask the server for a snapshot,
            if we have a server to talk to..."""
            if agent.servers:
                server = agent.servers[agent.cur_server]

                logger.debug("Asking for snapshot from %s attempt=%d..", server.address, server.requests)

                if (server.requests < 2):
                    server.snapshot.send_multipart(["ICANHAZ?", agent.subtree])
                    server.requests += 1

                server.expiry = time.time() + SERVER_TTL
                agent.state = agent.STATES.SYNCING
                server_socket = server.snapshot

        elif agent.state == agent.STATES.SYNCING:
            """In this state we read from snapshot and we expect
            the server to respond, else we fail over."""
            server_socket = server.snapshot

        elif agent.state == agent.STATES.ACTIVE:
            """In this state we read from subscriber and we expect
            the server to give hugz, else we fail over."""
            server_socket = server.subscriber

        if server_socket:
            """we have a second socket to poll"""
            poller.register(server_socket, zmq.POLLIN)

        if server is not None:
            poll_timer = 1e3 * max(0, server.expiry - time.time())

        try:
            # Poll loop
            items = dict(poller.poll(poll_timer))
        except:
            raise  # DEBUG
            break  # Context has been shut down

        if agent.pipe in items:
            agent.control_message()

        elif server_socket in items:
            msg = server_socket.recv_multipart()
            #logger.debug('server_socket=%s, msg=%s', server_socket, msg)
            #logger.debug('msg=%s', msg)
            #kvmsg = KVMsg.recv(server_socket)
            kvmsg = KVMsg.from_msg(msg)
            #pp(kvmsg.__dict__)

            server.expiry = time.time() + SERVER_TTL    # Anything from server resets its expiry time

            if agent.state == agent.STATES.SYNCING:
                """Store in snapshot until we're finished"""
                server.requests = 0
                #logger.debug('Syncing state msg=%s', msg)
                if kvmsg.key == "KTHXBAI":
                    agent.sequence = kvmsg.sequence
                    agent.state = agent.STATES.ACTIVE
                    logger.info("Synced snapshot=%s from %s", agent.sequence, server.address)
                    logger.info("Connected to %s", server.address)
                    connected_event.set()
                else:
                    logger.debug("Syncing update=%s from %s", kvmsg.sequence, server.address)
                    kvmsg.store(agent.kvmap)

            elif agent.state == agent.STATES.ACTIVE:
                """Discard out-of-sequence updates, incl. hugz"""
                if kvmsg.sequence > agent.sequence:
                    agent.sequence = kvmsg.sequence
                    kvmsg.store(agent.kvmap)
                    action = "update" if kvmsg.body else "delete"

                    logger.debug("Received %s=%d from %s", action, agent.sequence, server.address)

                    """ Signal """
                    if kvmsg.key != 'HUGZ':  # Don't send signals if it's just hugz
                        Dkv.signals.on_sub.send(kvmsg, key=kvmsg.key, value=kvmsg.body, props=kvmsg.properties)

        else:
            """Server has died, failover to next"""
            if agent.state == agent.STATES.ACTIVE:
                level = logging.ERROR
                server_state = 'active'
            else:
                level = logging.WARNING
                server_state = 'non-active'
            logger.log(level, "Did not receive heartbeat from %s server at %s; failing over.",
                       server_state, server.address)
            agent.cur_server = (agent.cur_server + 1) % len(agent.servers)
            agent.state = agent.STATES.INITIAL