def main(): # context and sockets ctx = zmq.Context() snapshot = ctx.socket(zmq.ROUTER) snapshot.bind("tcp://*:5556") publisher = ctx.socket(zmq.PUB) publisher.bind("tcp://*:5557") collector = ctx.socket(zmq.PULL) collector.bind("tcp://*:5558") sequence = 0 kvmap = {} poller = zmq.Poller() poller.register(collector, zmq.POLLIN) poller.register(snapshot, zmq.POLLIN) while True: try: items = dict(poller.poll(1000)) except: break # Interrupted # Apply state update sent from client if collector in items: kvmsg = KVMsg.recv(collector) sequence += 1 kvmsg.sequence = sequence kvmsg.send(publisher) kvmsg.store(kvmap) print(f"U: publishing update {sequence} {kvmap}") # Execute state snapshot request if snapshot in items: msg = snapshot.recv_multipart() identity = msg[0] request = msg[1] if request == b"ICANHAZ?": pass else: print("E: bad request, aborting\n") break # Send state snapshot to client route = Route(snapshot, identity) # For each entry in kvmap, send kvmsg to client for v in kvmap.values(): send_single(v, route) # Now send END message with sequence number print(f"S: sending snapshot {sequence} {kvmap}") snapshot.send(identity, zmq.SNDMORE) kvmsg = KVMsg(sequence) kvmsg.key = b"KTHXBAI" kvmsg.body = b"" kvmsg.send(snapshot) print("E: Interrupted\nE: %d messages handled" % sequence)
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)
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)
def clone_agent(ctx, pipe): agent = CloneAgent(ctx, pipe) server = None while True: poller = zmq.Poller() poller.register(agent.pipe, zmq.POLLIN) poll_timer = None server_socket = None if agent.state == STATE_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] logging.info("I: waiting for server at %s:%d...", server.address, server.port) if (server.requests < 2): server.snapshot.send_multipart(["ICANHAZ?", agent.subtree]) server.requests += 1 server.expiry = time.time() + SERVER_TTL agent.state = STATE_SYNCING server_socket = server.snapshot elif agent.state == STATE_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 == STATE_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()) # ------------------------------------------------------------ # Poll loop try: 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: kvmsg = KVMsg.recv(server_socket) # Anything from server resets its expiry time server.expiry = time.time() + SERVER_TTL if (agent.state == STATE_SYNCING): # Store in snapshot until we're finished server.requests = 0 if kvmsg.key == "KTHXBAI": agent.sequence = kvmsg.sequence agent.state = STATE_ACTIVE logging.info("I: received from %s:%d snapshot=%d", server.address, server.port, agent.sequence) else: kvmsg.store(agent.kvmap) elif (agent.state == STATE_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" logging.info("I: received from %s:%d %s=%d", server.address, server.port, action, agent.sequence) else: # Server has died, failover to next logging.info("I: server at %s:%d didn't give hugz", server.address, server.port) agent.cur_server = (agent.cur_server + 1) % len(agent.servers) agent.state = STATE_INITIAL
def main(): # Prepare our context and subscriber ctx = zmq.Context() snapshot = ctx.socket(zmq.DEALER) snapshot.linger = 0 snapshot.connect("tcp://localhost:5556") subscriber = ctx.socket(zmq.SUB) subscriber.linger = 0 subscriber.setsockopt(zmq.SUBSCRIBE, SUBTREE) subscriber.connect("tcp://localhost:5557") publisher = ctx.socket(zmq.PUB) publisher.linger = 0 publisher.connect("tcp://localhost:5558") random.seed(time.time()) kvmap = {} # Get state snapshot sequence = 0 snapshot.send_multipart(["ICANHAZ?", SUBTREE]) while True: try: kvmsg = KVMsg.recv(snapshot) except: raise return # Interrupted if kvmsg.key == "KTHXBAI": sequence = kvmsg.sequence print "I: Received snapshot=%d" % sequence break # Done kvmsg.store(kvmap) poller = zmq.Poller() poller.register(subscriber, zmq.POLLIN) alarm = time.time()+1. while True: tickless = 1000*max(0, alarm - time.time()) try: items = dict(poller.poll(tickless)) except: break # Interrupted if subscriber in items: kvmsg = KVMsg.recv(subscriber) # Discard out-of-sequence kvmsgs, incl. heartbeats if kvmsg.sequence > sequence: sequence = kvmsg.sequence kvmsg.store(kvmap) action = "update" if kvmsg.body else "delete" print "I: received %s=%d" % (action, sequence) # If we timed-out, generate a random kvmsg if time.time() >= alarm: kvmsg = KVMsg(0) kvmsg.key = SUBTREE + "%d" % random.randint(1,10000) kvmsg.body = "%d" % random.randint(1,1000000) kvmsg['ttl'] = random.randint(0,30) kvmsg.send(publisher) kvmsg.store(kvmap) alarm = time.time() + 1. print " Interrupted\n%d messages in" % sequence
def clone_agent(ctx, pipe): agent = CloneAgent(ctx, pipe) server = None while True: poller = zmq.Poller() poller.register(agent.pipe, zmq.POLLIN) poll_timer = None server_socket = None if agent.state == STATE_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] logging.info ("I: waiting for server at %s:%d...", server.address, server.port) if (server.requests < 2): server.snapshot.send_multipart(["ICANHAZ?", agent.subtree]) server.requests += 1 server.expiry = time.time() + SERVER_TTL agent.state = STATE_SYNCING server_socket = server.snapshot elif agent.state == STATE_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 == STATE_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()) # ------------------------------------------------------------ # Poll loop try: 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: kvmsg = KVMsg.recv(server_socket) # Anything from server resets its expiry time server.expiry = time.time() + SERVER_TTL if (agent.state == STATE_SYNCING): # Store in snapshot until we're finished server.requests = 0 if kvmsg.key == "KTHXBAI": agent.sequence = kvmsg.sequence agent.state = STATE_ACTIVE logging.info ("I: received from %s:%d snapshot=%d", server.address, server.port, agent.sequence) else: kvmsg.store(agent.kvmap) elif (agent.state == STATE_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" logging.info ("I: received from %s:%d %s=%d", server.address, server.port, action, agent.sequence) else: # Server has died, failover to next logging.info ("I: server at %s:%d didn't give hugz", server.address, server.port) agent.cur_server = (agent.cur_server + 1) % len(agent.servers) agent.state = STATE_INITIAL
def main(): # Prepare our context and subscriber ctx = zmq.Context() snapshot = ctx.socket(zmq.DEALER) snapshot.linger = 0 snapshot.connect("tcp://localhost:5556") subscriber = ctx.socket(zmq.SUB) subscriber.linger = 0 subscriber.setsockopt(zmq.SUBSCRIBE, SUBTREE) subscriber.connect("tcp://localhost:5557") publisher = ctx.socket(zmq.PUB) publisher.linger = 0 publisher.connect("tcp://localhost:5558") random.seed(time.time()) kvmap = {} # Get state snapshot sequence = 0 snapshot.send_multipart(["ICANHAZ?", SUBTREE]) while True: try: kvmsg = KVMsg.recv(snapshot) except: raise return # Interrupted if kvmsg.key == "KTHXBAI": sequence = kvmsg.sequence print "I: Received snapshot=%d" % sequence break # Done kvmsg.store(kvmap) poller = zmq.Poller() poller.register(subscriber, zmq.POLLIN) alarm = time.time() + 1. while True: tickless = 1000 * max(0, alarm - time.time()) try: items = dict(poller.poll(tickless)) except: break # Interrupted if subscriber in items: kvmsg = KVMsg.recv(subscriber) # Discard out-of-sequence kvmsgs, incl. heartbeats if kvmsg.sequence > sequence: sequence = kvmsg.sequence kvmsg.store(kvmap) action = "update" if kvmsg.body else "delete" print "I: received %s=%d" % (action, sequence) # If we timed-out, generate a random kvmsg if time.time() >= alarm: kvmsg = KVMsg(0) kvmsg.key = SUBTREE + "%d" % random.randint(1, 10000) kvmsg.body = "%d" % random.randint(1, 1000000) kvmsg['ttl'] = random.randint(0, 30) kvmsg.send(publisher) kvmsg.store(kvmap) alarm = time.time() + 1. print " Interrupted\n%d messages in" % sequence
def main(): # Prepare our context and subscriber ctx = zmq.Context() snapshot = ctx.socket(zmq.DEALER) snapshot.linger = 0 snapshot.connect("tcp://localhost:5556") subscriber = ctx.socket(zmq.SUB) subscriber.linger = 0 subscriber.setsockopt_string(zmq.SUBSCRIBE, "") subscriber.connect("tcp://localhost:5557") publisher = ctx.socket(zmq.PUSH) publisher.linger = 0 publisher.connect("tcp://localhost:5558") random.seed(time.time()) kvmap = {} # Get state snapshot sequence = 0 snapshot.send_string("ICANHAZ?") while True: try: kvmsg = KVMsg.recv(snapshot) except: return # Interrupted if kvmsg.key == b"KTHXBAI": sequence = kvmsg.sequence print(f"S: Received snapshot {sequence} {kvmap}") break # Done kvmsg.store(kvmap) poller = zmq.Poller() poller.register(subscriber, zmq.POLLIN) alarm = time.time() + 1.0 while True: tickless = 1000 * max(0, alarm - time.time()) try: items = dict(poller.poll(tickless)) except: break # Interrupted if subscriber in items: kvmsg = KVMsg.recv(subscriber) # Discard out-of-sequence kvmsgs, incl. heartbeats if kvmsg.sequence > sequence: sequence = kvmsg.sequence kvmsg.store(kvmap) print(f"U: received {sequence} {kvmap}") # If we timed-out, generate a random kvmsg if time.time() >= alarm: kvmsg = KVMsg(0) kvmsg.key = ("%d" % random.randint(1, 10000)).encode() kvmsg.body = ("%d" % random.randint(1, 1000000)).encode() kvmsg.send(publisher) kvmsg.store(kvmap) alarm = time.time() + 1.0 print(f"E: Interrupted\nE: {sequence} messages handled")