def setUp(self): self.node1 = Node(uuid.uuid4()) self.node2 = Node(uuid.uuid4()) # Create a GCounter self.gc1 = GCounter(uuid.uuid4()) # Add nodes to gc1 self.gc1.add_new_node(self.node1.id) self.gc1.add_new_node(self.node2.id) # Create another GCounter self.gc2 = GCounter(uuid.uuid4()) # Add nodes to gc2 self.gc2.add_new_node(self.node1.id) self.gc2.add_new_node(self.node2.id) # Increment gc1 values for each node self.gc1.inc(self.node1.id) self.gc1.inc(self.node1.id) self.gc1.inc(self.node2.id) # Increment gc2 values for each node self.gc2.inc(self.node1.id) self.gc2.inc(self.node2.id) self.gc2.inc(self.node2.id) self.gc2.inc(self.node2.id)
def __init__(self, port, peers): self.socket = socket.socket(type=socket.SOCK_DGRAM) #self.host = socket.gethostname() self.host = "localhost" self.port = port self.socket.bind((self.host, self.port)) self.state = b"ack" self.peers = peers self.counter = GCounter(port, peers) self.lock = threading.Lock() logger.debug(peers)
def latency_demo(): '''Demo gCRDT with latency''' ps = CloudyPubSub(CloudyException) nodes = [GCounter(idx, ps) for idx in range(3)] for i in range(10): node = random.choice(nodes) node.increment() for n in nodes: print("Node %d says %d" % (n.idx, n.value()))
def demo(): '''Demo gCRDT''' ps = PubSub() nodes = [GCounter(idx, ps) for idx in range(3)] for i in range(10): node = random.choice(nodes) node.increment() for n in nodes: print("Node %d says %d" % (n.idx, n.value()))
def test_integrated(self): '''Test some nodes hooked up with a pub/sub''' pubsub = PubSub() nodes = [GCounter(idx, pubsub) for idx in range(3)] for i in range(100): # Pick a random node and increment it node = random.choice(nodes) node.increment() # All .value() checks should have the same result self.assertTrue(all(n.value() == node.value() for n in nodes))
class TestGCounter(unittest.TestCase): def setUp(self): self.node1 = Node(uuid.uuid4()) self.node2 = Node(uuid.uuid4()) # Create a GCounter self.gc1 = GCounter(uuid.uuid4()) # Add nodes to gc1 self.gc1.add_new_node(self.node1.id) self.gc1.add_new_node(self.node2.id) # Create another GCounter self.gc2 = GCounter(uuid.uuid4()) # Add nodes to gc2 self.gc2.add_new_node(self.node1.id) self.gc2.add_new_node(self.node2.id) # Increment gc1 values for each node self.gc1.inc(self.node1.id) self.gc1.inc(self.node1.id) self.gc1.inc(self.node2.id) # Increment gc2 values for each node self.gc2.inc(self.node1.id) self.gc2.inc(self.node2.id) self.gc2.inc(self.node2.id) self.gc2.inc(self.node2.id) def test_check_increment(self): self.assertEqual(self.gc1.payload[self.node1.id], 2) self.assertEqual(self.gc1.payload[self.node2.id], 1) self.assertEqual(self.gc2.payload[self.node1.id], 1) self.assertEqual(self.gc2.payload[self.node2.id], 3) def test_merging_gcounters(self): # Check gc2 merging self.gc2.merge(self.gc1) self.assertEqual(self.gc2.payload[self.node1.id], 2) self.assertEqual(self.gc2.payload[self.node2.id], 3) # Check gc1 merging self.gc1.merge(self.gc2) self.assertEqual(self.gc1.payload[self.node1.id], 2) self.assertEqual(self.gc1.payload[self.node2.id], 3) # Check if they are both equal self.assertEqual(self.gc1.payload, self.gc2.payload)
return wrapper class CloudyGCounter(GCounter): '''A subclass of GCounter that randomly becomes unresponsive.''' CHANCE_OF_CRASH = 0.05 def __init__(self, *args, **kwargs): self.crashed = False super().__init__(*args, **kwargs) def random_crash(self): if chance(self.CHANCE_OF_CRASH): self.crashed = True wrap_some_fns_on_cls(CloudyGCounter, randomly_crash_inst_fn, lambda name: name in ["increment", "value", "_join"]) if __name__ == "__main__": '''Demo some nodes incrementing and publishing to each other''' ps = CloudyPubSub() nodes = [GCounter(idx, ps) for idx in range(3)] for i in range(10): node = random.choice(nodes) node.increment() for n in nodes: print("Node %d says %d" % (n.idx, n.value()))
def __init__(self, id): self.P = GCounter(id) self.N = GCounter(id) self.id = id
class PNCounter: def __init__(self, id): self.P = GCounter(id) self.N = GCounter(id) self.id = id def add_new_node(self, key): self.P.add_new_node(key) self.N.add_new_node(key) def inc(self, key): self.P.inc(key) def dec(self, key): self.N.inc(key) def query(self): return self.P.query() - self.N.query() def compare(self, gc2): return self.P.compare(gc2.P) and self.N.compare(gc2.N) def merge(self, gc2): self.P.merge(gc2.P) self.N.merge(gc2.N) # self.display() def display(self, name): print("{}.P: ".format(name), end="") self.P.display() print("{}.N: ".format(name), end="") self.N.display()
class Node: def __init__(self, port, peers): self.socket = socket.socket(type=socket.SOCK_DGRAM) #self.host = socket.gethostname() self.host = "localhost" self.port = port self.socket.bind((self.host, self.port)) self.state = b"ack" self.peers = peers self.counter = GCounter(port, peers) self.lock = threading.Lock() logger.debug(peers) def add(self, x): self.counter.add(x) data = pickle.dumps(self.counter) self.infect(data) def query(self): return self.counter.query() def recv(self): logger.info("Node {} listen on {}"\ .format(self.host, self.port)) while True: msg, address = self.socket.recvfrom(1024) remote_counter = pickle.loads(msg) self.lock.acquire() try: self.counter.merge(remote_counter) logger.info("Counter now: {}".format(self.counter.query())) data = pickle.dumps(self.counter) self.infect(data, address) finally: self.lock.release() # self.state = int(msg) logger.debug("address: {}".format(address)) logger.debug("msg: {}".format(msg)) def send(self, msg, port): try: self.socket.sendto(msg, (self.host, port)) logger.debug("sent to {}".format(port)) except OSError: logger.debug("Failed to connecto to {}".format(port)) def random_ports(self): tmp = self.peers.copy() port1 = random.choice(tmp) _idx = tmp.index(port1) del (tmp[_idx]) port2 = random.choice(tmp) return port1, port2 def choice_port(self, origin=None): tmp = self.peers.copy() if origin: _idx = tmp.index(origin) del (tmp[_idx]) port1 = random.choice(tmp) _idx2 = tmp.index(port1) del (tmp[_idx2]) port2 = random.choice(tmp) return port1, port2 def infect(self, data, origin=None): if origin: port1, port2 = self.choice_port(origin[1]) else: port1, port2 = self.choice_port() logger.debug("port1 {}".format(port1)) self.send(data, port1) self.send(data, port2) #time.sleep(WAIT) time.sleep(random.uniform(0, 1) * 2) def listen(self): recv = threading.Thread(target=self.recv) rumor = threading.Thread(target=self.infect) recv.start()
def run(): a = GCounter(0, 2, 2000) b = GCounter(1, 2, 3000) print(f"a-GCounter:query={a.query()}") a.add(1) print(f"a-GCounter:query={a.query()}") print(f"b-GCounter:query={b.query()}") b.add(2) print(f"b-GCounter:query={b.query()}") print(f"a-GCounter:{a.to_dict()}") print(f"b-GCounter:{b.to_dict()}") b.sync_to_peer(a.zmq_port) print(f"a-GCounter:{a.to_dict()}") print(f"b-GCounter:{b.to_dict()}") print(f"a-GCounter:query={a.query()}") b.add(4) print(f"b-GCounter:query={b.query()}") print(f"a-GCounter:{a.to_dict()}") print(f"b-GCounter:{b.to_dict()}") a.sync_to_peer(b.zmq_port) print(f"a-GCounter:{a.to_dict()}") print(f"b-GCounter:{b.to_dict()}") print(f"b-GCounter:query={b.query()}")