def sendGetMessageStats(self): """ Sends DhtNetwork sub process statistics request about nodes messages sent. @return: A list [num_nodes, ping, find, get, put, listen]. @rtype : list """ stats = [] def cb(answer): """ Callback fed to getlinesUntilNotify made to recover answer from the DhtNetwork sub process. :answer: the list of lines answered by the sub process. """ nonlocal stats if answer: stats = [int(v) for v in re.findall("[0-9]+", answer.pop())] self.send(DhtNetworkSubProcess.MESSAGE_STATS + b'\n') for line in self.getlinesUntilNotify(answer_cb=cb): DhtNetwork.log(line) return stats
def _dhtPut(self, producer, _hash, *values): for val in values: with PersistenceTest.lock: DhtNetwork.log('[PUT]: %s' % val) PersistenceTest.done += 1 producer.put(_hash, val, PersistenceTest.putDoneCb) while PersistenceTest.done > 0: PersistenceTest.lock.wait()
def sendShutdown(self): """ Shutdown the whole cluster. This does not terminate comunicating thread; use quit(). """ self.send(DhtNetworkSubProcess.SHUTDOWN_CLUSTER_REQ + b'\n') for line in self.getlinesUntilNotify(): DhtNetwork.log(line)
def sendDumpStorage(self, ids): """ Dumps storage log from nodes with id in `ids`. """ serialized_req = DhtNetworkSubProcess.DUMP_STORAGE_REQ + b' ' + \ b' '.join(map(bytes, ids)) self.send(serialized_req + b'\n') for line in self.getlinesUntilNotify(): DhtNetwork.log(line)
def donecb(ok, nodes): nonlocal bootstrap, lock, done, times t = time.time()-start with lock: if not ok: DhtNetwork.log("failed !") times.append(t) done -= 1 lock.notify()
def donecb(ok, nodes): nonlocal bootstrap, lock, done, times t = time.time() - start with lock: if not ok: DhtNetwork.log("failed !") times.append(t) done -= 1 lock.notify()
def getDoneCb(ok, nodes): with PersistenceTest.lock: if not ok: DhtNetwork.log("[GET]: failed!") else: for node in nodes: if not node.getNode().isExpired(): PersistenceTest.foreign_nodes.append(node.getId().toString()) PersistenceTest.done -= 1 PersistenceTest.lock.notify()
def getDoneCb(ok, nodes): with PersistenceTest.lock: if not ok: DhtNetwork.log("[GET]: failed!") else: for node in nodes: if not node.getNode().isExpired(): PersistenceTest.foreign_nodes.append( node.getId().toString()) PersistenceTest.done -= 1 PersistenceTest.lock.notify()
def sendNodesRequest(self, request, ids): """ Shutsdown nodes on the DhtNetwork sub process. @param request: The request @type request: bytes @param ids: ids of nodes concerned by the request. @type ids: list """ serialized_req = request + b' ' + b' '.join(map(bytes, ids)) self.send(serialized_req + b'\n') for line in self.getlinesUntilNotify(): DhtNetwork.log(line)
def get_bootstrap(self): if not self.local_bootstrap: self.local_bootstrap = DhtNetwork( iface='br' + self.ifname, first_bootstrap=False if self.remote_bootstrap else True, bootstrap=[(self.remote_bootstrap, self.bs_port)] if self.remote_bootstrap else []) return self.local_bootstrap
def _resplaceClusterTest(self): """ It replaces all clusters one after the other. """ PersistenceTest.done = 0 PersistenceTest.lock = threading.Condition() PersistenceTest.foreign_nodes = [] PersistenceTest.foreign_values = [] clusters = opts['clusters'] if 'clusters' in opts else 5 bootstrap = PersistenceTest.bootstrap try: bootstrap.resize(3) consumer = bootstrap.get(1) producer = bootstrap.get(2) myhash = random_hash() local_values = [Value(b'foo'), Value(b'bar'), Value(b'foobar')] self._dhtPut(producer, myhash, *local_values) self._dhtGet(consumer, myhash) initial_nodes = PersistenceTest.foreign_nodes DhtNetwork.log('Replacing', clusters, 'random clusters successively...') for n in range(clusters): i = random.randint(0, len(self.wb.procs) - 1) proc = self.wb.procs[i] DhtNetwork.log('Replacing', proc) proc.sendShutdown() self.wb.stop_cluster(i) self.wb.start_cluster(i) DhtNetwork.log('[GET]: trying to fetch persistent values') self._dhtGet(consumer, myhash) new_nodes = set(PersistenceTest.foreign_nodes) - set(initial_nodes) self._result(local_values, new_nodes) except Exception as e: print(e) finally: bootstrap.resize(1)
def _resplaceClusterTest(self): """ It replaces all clusters one after the other. """ PersistenceTest.done = 0 PersistenceTest.lock = threading.Condition() PersistenceTest.foreign_nodes = [] PersistenceTest.foreign_values = [] clusters = opts['clusters'] if 'clusters' in opts else 5 bootstrap = PersistenceTest.bootstrap try: bootstrap.resize(3) consumer = bootstrap.get(1) producer = bootstrap.get(2) myhash = random_hash() local_values = [Value(b'foo'), Value(b'bar'), Value(b'foobar')] self._dhtPut(producer, myhash, *local_values) self._dhtGet(consumer, myhash) initial_nodes = PersistenceTest.foreign_nodes DhtNetwork.log('Replacing', clusters, 'random clusters successively...') for n in range(clusters): i = random.randint(0, len(self.wb.procs)-1) proc = self.wb.procs[i] DhtNetwork.log('Replacing', proc) proc.sendShutdown() self.wb.stop_cluster(i) self.wb.start_cluster(i) DhtNetwork.log('[GET]: trying to fetch persistent values') self._dhtGet(consumer, myhash) new_nodes = set(PersistenceTest.foreign_nodes) - set(initial_nodes) self._result(local_values, new_nodes) except Exception as e: print(e) finally: bootstrap.resize(1)
def _multTimeTest(self): """ Multiple put() calls are made from multiple nodes to multiple hashes after what a set of 8 nodes is created around each hashes in order to enable storage maintenance each nodes. Therefor, this tests will wait 10 minutes for the nodes to trigger storage maintenance. """ PersistenceTest.done = 0 PersistenceTest.lock = threading.Condition() PersistenceTest.foreign_nodes = [] PersistenceTest.foreign_values = [] bootstrap = PersistenceTest.bootstrap N_PRODUCERS = 16 hashes = [] values = [Value(b'foo')] nodes = set([]) # prevents garbage collecting of unused flood nodes during the test. flood_nodes = [] def gottaGetThemAllPokeNodes(nodes=None): nonlocal consumer, hashes for h in hashes: self._dhtGet(consumer, h) if nodes is not None: for n in PersistenceTest.foreign_nodes: nodes.add(n) def createNodesAroundHash(_hash, radius=4): nonlocal flood_nodes _hash_str = _hash.toString().decode() _hash_int = int(_hash_str, 16) for i in range(-radius, radius+1): _hash_str = '{:40x}'.format(_hash_int + i) config = DhtConfig() config.setNodeId(InfoHash(_hash_str.encode())) n = DhtRunner() n.run(config=config) n.bootstrap(PersistenceTest.bootstrap.ip4, str(PersistenceTest.bootstrap.port)) flood_nodes.append(n) try: bootstrap.resize(N_PRODUCERS+2) consumer = bootstrap.get(1) producers = (bootstrap.get(n) for n in range(2,N_PRODUCERS+2)) for p in producers: hashes.append(random_hash()) self._dhtPut(p, hashes[-1], *values) gottaGetThemAllPokeNodes(nodes=nodes) DhtNetwork.log("Values are found on:") for n in nodes: DhtNetwork.log(n) DhtNetwork.log("Creating 8 nodes around all of these nodes...") for _hash in hashes: createNodesAroundHash(_hash) DhtNetwork.log('Waiting 10 minutes for normal storage maintenance.') time.sleep(10*60) DhtNetwork.log('Deleting old nodes from previous search.') for proc in self.wb.procs: DhtNetwork.log('[REMOVE]: sending shutdown request to', proc) proc.sendNodesRequest( DhtNetworkSubProcess.REMOVE_NODE_REQ, nodes ) # new consumer (fresh cache) bootstrap.resize(N_PRODUCERS+3) consumer = bootstrap.get(N_PRODUCERS+2) nodes_after_time = set([]) gottaGetThemAllPokeNodes(nodes=nodes_after_time) self._result(values, nodes_after_time - nodes) except Exception as e: print(e) finally: bootstrap.resize(1)
def _deleteTest(self): """ It uses Dht shutdown call from the API to gracefuly finish the nodes one after the other. """ PersistenceTest.done = 0 PersistenceTest.lock = threading.Condition() PersistenceTest.foreign_nodes = [] PersistenceTest.foreign_values = [] bootstrap = PersistenceTest.bootstrap ops_count = [] try: bootstrap.resize(3) consumer = bootstrap.get(1) producer = bootstrap.get(2) myhash = random_hash() local_values = [Value(b'foo'), Value(b'bar'), Value(b'foobar')] self._dhtPut(producer, myhash, *local_values) #checking if values were transfered self._dhtGet(consumer, myhash) if not PersistenceTest.successfullTransfer(local_values, PersistenceTest.foreign_values): if PersistenceTest.foreign_values: DhtNetwork.log('[GET]: Only ', len(PersistenceTest.foreign_values) ,' on ', len(local_values), ' values successfully put.') else: DhtNetwork.log('[GET]: 0 values successfully put') if PersistenceTest.foreign_values and PersistenceTest.foreign_nodes: DhtNetwork.log('Values are found on :') for node in PersistenceTest.foreign_nodes: DhtNetwork.log(node) DhtNetwork.log("Waiting a minute for the network to settle down.") time.sleep(60) for _ in range(max(1, int(self.wb.node_num/32))): DhtNetwork.log('Removing all nodes hosting target values...') cluster_ops_count = 0 for proc in self.wb.procs: DhtNetwork.log('[REMOVE]: sending shutdown request to', proc) proc.sendNodesRequest( DhtNetworkSubProcess.SHUTDOWN_NODE_REQ, PersistenceTest.foreign_nodes ) DhtNetwork.log('sending message stats request') stats = proc.sendGetMessageStats() cluster_ops_count += sum(stats[1:]) DhtNetwork.log("Waiting 15 seconds for packets to work their way effectively.") time.sleep(15) ops_count.append(cluster_ops_count/self.wb.node_num) # checking if values were transfered to new nodes foreign_nodes_before_delete = PersistenceTest.foreign_nodes DhtNetwork.log('[GET]: trying to fetch persistent values') self._dhtGet(consumer, myhash) new_nodes = set(PersistenceTest.foreign_nodes) - set(foreign_nodes_before_delete) self._result(local_values, new_nodes) if self._plot: plt.plot(ops_count, color='blue') plt.draw() plt.ioff() plt.show() else: DhtNetwork.log("[GET]: either couldn't fetch values or nodes hosting values...") except Exception as e: print(e) finally: bootstrap.resize(1)
def _result(self, local_values, new_nodes): bootstrap = PersistenceTest.bootstrap if not PersistenceTest.successfullTransfer(local_values, PersistenceTest.foreign_values): DhtNetwork.log('[GET]: Only %s on %s values persisted.' % (len(PersistenceTest.foreign_values), len(local_values))) else: DhtNetwork.log('[GET]: All values successfully persisted.') if PersistenceTest.foreign_values: if new_nodes: DhtNetwork.log('Values are newly found on:') for node in new_nodes: DhtNetwork.log(node) if self._dump_storage: DhtNetwork.log('Dumping all storage log from '\ 'hosting nodes.') for proc in self.wb.procs: proc.sendDumpStorage(PersistenceTest.foreign_nodes) else: DhtNetwork.log("Values didn't reach new hosting nodes after shutdown.")
def putDoneCb(ok, nodes): if not ok: DhtNetwork.log("[PUT]: failed!") with PersistenceTest.lock: PersistenceTest.done -= 1 PersistenceTest.lock.notify()
def getcb(v): nonlocal bootstrap DhtNetwork.log("found", v) return True
def getcb(value): DhtNetwork.log('[GET]: %s' % value) PersistenceTest.foreign_values.append(value) return True
def _deleteTest(self): """ It uses Dht shutdown call from the API to gracefuly finish the nodes one after the other. """ PersistenceTest.done = 0 PersistenceTest.lock = threading.Condition() PersistenceTest.foreign_nodes = [] PersistenceTest.foreign_values = [] bootstrap = PersistenceTest.bootstrap ops_count = [] try: bootstrap.resize(3) consumer = bootstrap.get(1) producer = bootstrap.get(2) myhash = random_hash() local_values = [Value(b'foo'), Value(b'bar'), Value(b'foobar')] self._dhtPut(producer, myhash, *local_values) #checking if values were transfered self._dhtGet(consumer, myhash) if not PersistenceTest.successfullTransfer( local_values, PersistenceTest.foreign_values): if PersistenceTest.foreign_values: DhtNetwork.log('[GET]: Only ', len(PersistenceTest.foreign_values), ' on ', len(local_values), ' values successfully put.') else: DhtNetwork.log('[GET]: 0 values successfully put') if PersistenceTest.foreign_values and PersistenceTest.foreign_nodes: DhtNetwork.log('Values are found on :') for node in PersistenceTest.foreign_nodes: DhtNetwork.log(node) DhtNetwork.log( "Waiting a minute for the network to settle down.") time.sleep(60) for _ in range(max(1, int(self.wb.node_num / 32))): DhtNetwork.log( 'Removing all nodes hosting target values...') cluster_ops_count = 0 for proc in self.wb.procs: DhtNetwork.log('[REMOVE]: sending shutdown request to', proc) proc.sendNodesRequest( DhtNetworkSubProcess.SHUTDOWN_NODE_REQ, PersistenceTest.foreign_nodes) DhtNetwork.log('sending message stats request') stats = proc.sendGetMessageStats() cluster_ops_count += sum(stats[1:]) DhtNetwork.log( "Waiting 15 seconds for packets to work their way effectively." ) time.sleep(15) ops_count.append(cluster_ops_count / self.wb.node_num) # checking if values were transfered to new nodes foreign_nodes_before_delete = PersistenceTest.foreign_nodes DhtNetwork.log('[GET]: trying to fetch persistent values') self._dhtGet(consumer, myhash) new_nodes = set(PersistenceTest.foreign_nodes) - set( foreign_nodes_before_delete) self._result(local_values, new_nodes) if self._plot: plt.plot(ops_count, color='blue') plt.draw() plt.ioff() plt.show() else: DhtNetwork.log( "[GET]: either couldn't fetch values or nodes hosting values..." ) except Exception as e: print(e) finally: bootstrap.resize(1)
def _multTimeTest(self): """ Multiple put() calls are made from multiple nodes to multiple hashes after what a set of 8 nodes is created around each hashes in order to enable storage maintenance each nodes. Therefor, this tests will wait 10 minutes for the nodes to trigger storage maintenance. """ PersistenceTest.done = 0 PersistenceTest.lock = threading.Condition() PersistenceTest.foreign_nodes = [] PersistenceTest.foreign_values = [] bootstrap = PersistenceTest.bootstrap N_PRODUCERS = 16 hashes = [] values = [Value(b'foo')] nodes = set([]) # prevents garbage collecting of unused flood nodes during the test. flood_nodes = [] def gottaGetThemAllPokeNodes(nodes=None): nonlocal consumer, hashes for h in hashes: self._dhtGet(consumer, h) if nodes is not None: for n in PersistenceTest.foreign_nodes: nodes.add(n) def createNodesAroundHash(_hash, radius=4): nonlocal flood_nodes _hash_str = _hash.toString().decode() _hash_int = int(_hash_str, 16) for i in range(-radius, radius + 1): _hash_str = '{:40x}'.format(_hash_int + i) config = DhtConfig() config.setNodeId(InfoHash(_hash_str.encode())) n = DhtRunner() n.run(config=config) n.bootstrap(PersistenceTest.bootstrap.ip4, str(PersistenceTest.bootstrap.port)) flood_nodes.append(n) try: bootstrap.resize(N_PRODUCERS + 2) consumer = bootstrap.get(1) producers = (bootstrap.get(n) for n in range(2, N_PRODUCERS + 2)) for p in producers: hashes.append(random_hash()) self._dhtPut(p, hashes[-1], *values) gottaGetThemAllPokeNodes(nodes=nodes) DhtNetwork.log("Values are found on:") for n in nodes: DhtNetwork.log(n) DhtNetwork.log("Creating 8 nodes around all of these nodes...") for _hash in hashes: createNodesAroundHash(_hash) DhtNetwork.log( 'Waiting 10 minutes for normal storage maintenance.') time.sleep(10 * 60) DhtNetwork.log('Deleting old nodes from previous search.') for proc in self.wb.procs: DhtNetwork.log('[REMOVE]: sending shutdown request to', proc) proc.sendNodesRequest(DhtNetworkSubProcess.REMOVE_NODE_REQ, nodes) # new consumer (fresh cache) bootstrap.resize(N_PRODUCERS + 3) consumer = bootstrap.get(N_PRODUCERS + 2) nodes_after_time = set([]) gottaGetThemAllPokeNodes(nodes=nodes_after_time) self._result(values, nodes_after_time - nodes) except Exception as e: print(e) finally: bootstrap.resize(1)
def _getsTimesTest(self): """ Tests for performance of the DHT doing multiple get() operation. """ bootstrap = PerformanceTest.bootstrap plt.ion() fig, axes = plt.subplots(2, 1) fig.tight_layout() lax = axes[0] hax = axes[1] lines = None#ax.plot([]) #plt.ylabel('time (s)') hax.set_ylim(0, 2) # let the network stabilise plt.pause(60) #start = time.time() times = [] lock = threading.Condition() done = 0 def getcb(v): nonlocal bootstrap DhtNetwork.log("found", v) return True def donecb(ok, nodes): nonlocal bootstrap, lock, done, times t = time.time()-start with lock: if not ok: DhtNetwork.log("failed !") times.append(t) done -= 1 lock.notify() def update_plot(): nonlocal lines while lines: l = lines.pop() l.remove() del l lines = plt.plot(times, color='blue') plt.draw() def run_get(): nonlocal done done += 1 start = time.time() bootstrap.front().get(InfoHash.getRandom(), getcb, lambda ok, nodes: donecb(ok, nodes, start)) plt.pause(5) plt.show() update_plot() times = [] for n in range(10): self.wb.replace_cluster() plt.pause(2) DhtNetwork.log("Getting 50 random hashes succesively.") for i in range(50): with lock: done += 1 start = time.time() bootstrap.front().get(InfoHash.getRandom(), getcb, donecb) while done > 0: lock.wait() update_plot() update_plot() print("Took", np.sum(times), "mean", np.mean(times), "std", np.std(times), "min", np.min(times), "max", np.max(times)) print('GET calls timings benchmark test : DONE. ' \ 'Close Matplotlib window for terminating the program.') plt.ioff() plt.show()
def _result(self, local_values, new_nodes): bootstrap = PersistenceTest.bootstrap if not PersistenceTest.successfullTransfer( local_values, PersistenceTest.foreign_values): DhtNetwork.log( '[GET]: Only %s on %s values persisted.' % (len(PersistenceTest.foreign_values), len(local_values))) else: DhtNetwork.log('[GET]: All values successfully persisted.') if PersistenceTest.foreign_values: if new_nodes: DhtNetwork.log('Values are newly found on:') for node in new_nodes: DhtNetwork.log(node) if self._dump_storage: DhtNetwork.log('Dumping all storage log from '\ 'hosting nodes.') for proc in self.wb.procs: proc.sendDumpStorage(PersistenceTest.foreign_nodes) else: DhtNetwork.log( "Values didn't reach new hosting nodes after shutdown.")
node_per_loc = int(args.node_num / clusters) print("Launching", args.node_num, "nodes (", clusters, "clusters of", node_per_loc, "nodes)") if args.virtual_locs > 1: cmd = ["python3", "virtual_network_builder.py", "-i", args.ifname, "-n", str(clusters), '-l', str(args.loss), '-d', str(args.delay)] if not args.disable_ipv4: cmd.append('-4') if not args.disable_ipv6: cmd.append('-6') print(cmd) p = subprocess.Popen(cmd, stdout=subprocess.PIPE) output, err = p.communicate() print(output.decode()) bootstrap = DhtNetwork(iface='br'+args.ifname, first_bootstrap=False if args.bootstrap else True, bootstrap=[(args.bootstrap, "5000")] if args.bootstrap else []) bootstrap.resize(1) procs = [None for _ in range(clusters)] try: for i in range(clusters): start_cluster(i) if args.gets: getsTimesTest() except Exception as e: print(e) finally: for p in procs:
def _getsTimesTest(self): """ Tests for performance of the DHT doing multiple get() operation. """ bootstrap = PerformanceTest.bootstrap plt.ion() fig, axes = plt.subplots(2, 1) fig.tight_layout() lax = axes[0] hax = axes[1] lines = None #ax.plot([]) #plt.ylabel('time (s)') hax.set_ylim(0, 2) # let the network stabilise plt.pause(60) #start = time.time() times = [] lock = threading.Condition() done = 0 def getcb(v): nonlocal bootstrap DhtNetwork.log("found", v) return True def donecb(ok, nodes): nonlocal bootstrap, lock, done, times t = time.time() - start with lock: if not ok: DhtNetwork.log("failed !") times.append(t) done -= 1 lock.notify() def update_plot(): nonlocal lines while lines: l = lines.pop() l.remove() del l lines = plt.plot(times, color='blue') plt.draw() def run_get(): nonlocal done done += 1 start = time.time() bootstrap.front().get(InfoHash.getRandom(), getcb, lambda ok, nodes: donecb(ok, nodes, start)) plt.pause(5) plt.show() update_plot() times = [] for n in range(10): self.wb.replace_cluster() plt.pause(2) DhtNetwork.log("Getting 50 random hashes succesively.") for i in range(50): with lock: done += 1 start = time.time() bootstrap.front().get(PyInfoHash.getRandom(), getcb, donecb) while done > 0: lock.wait() update_plot() update_plot() print("Took", np.sum(times), "mean", np.mean(times), "std", np.std(times), "min", np.min(times), "max", np.max(times)) print('GET calls timings benchmark test : DONE. ' \ 'Close Matplotlib window for terminating the program.') plt.ioff() plt.show()