class NsServerNumConcurrentRequests(UserResourceTask): def __init__(self, user, node, streaminguri): super(NsServerNumConcurrentRequests, self).__init__(user, node) self.nconns = [] # Belongs exclusively to poll method self.thread = None self.httprq = get_http_request(self.node.ip, streaminguri, self.node.rest_username, self.node.rest_password) self.no_of_connections = AtomicInteger(0) self.no_of_open_connections = AtomicInteger(0) self.no_of_throughput_updates = AtomicInteger(0) self.rest = RestConnection(self.node) def on_throughput_increase(self, throughput): log.debug("Increasing throughput by {}".format(throughput - self.throughput)) # Record the last throughput update last_throughput_update = self.no_of_throughput_updates.get() # Update the throughput self.no_of_connections.set(throughput) # Launch the thread if self.thread is None: self.thread = Thread(target=self.poll) self.thread.start() # Block until the update has gone (TODO add a timeout) while self.no_of_throughput_updates.get() <= last_throughput_update: continue def on_throughput_decrease(self, throughput): log.debug("Decreasing throughput by {}".format(self.throughput - throughput)) # Record the last throughput update last_throughput_update = self.no_of_throughput_updates.get() # Update the throughput self.no_of_connections.set(throughput) if self.thread and throughput == 0: self.thread.join() self.thread = None # Block until the update has gone (TODO add a timeout) while self.no_of_throughput_updates.get() <= last_throughput_update: continue def get_throughput_success(self): return self.no_of_open_connections.get() def poll(self): """ Repeatedly poll each connection and attempt to keep them alive """ no_of_conns = self.no_of_connections.get() while no_of_conns > 0 or len(self.nconns) > 0: update_nconns = no_of_conns != len(self.nconns) if update_nconns: # Add any new connections for i in range(no_of_conns - len(self.nconns)): self.nconns.append( NonBlockingConnection(self.node.ip, 8091, self.httprq)) # Disconnect the connections that need to be closed for conn in self.nconns[no_of_conns:]: conn.disconnect() # Delete the disconnected connections del self.nconns[no_of_conns:] # Poll and count open connections open_count = 0 for conn in self.nconns: if conn.poll(): open_count += 1 # Update the number of open connections self.no_of_open_connections.set(open_count) # Notify the main thread that the connections have been updated if update_nconns: self.no_of_throughput_updates.incrementAndGet() no_of_conns = self.no_of_connections.get() def error(self): return self.rest._http_request(self.rest.baseUrl + "/pools/default")[1] def expected_error(self): return 'Limit(s) exceeded [num_concurrent_requests]'
class AbstractTimedThroughputWorker(object): """ Send throughput across a time period. """ def __init__(self, period=60, chunks=100, throughput=0): self.period = period # The time period over which to produce throughput self.chunks = chunks self.throughput = AtomicInteger(throughput) self.throughput_success = AtomicInteger(0) self.resume = AtomicBoolean(True) self.curr_tick = AtomicInteger(0) def stop(self): self.resume.set(False) self.thread.join() def start(self): self.thread = Thread(target=self.loop) self.thread.start() def loop(self): while self.resume.get(): self.throughput_success.set(self.tick(self.throughput.get())) def action(self, throughput): """ This method fires Args: throughput (int): The throughput in bytes Returns (bool): Indicating success. """ raise NotImplementedError("Please implement this method") def next_tick(self, period): """ Returns the next multiple of a time period """ curr_time = time.time() return curr_time + (period - curr_time % period) def tick(self, throughput): """ Fires throughput over this time period """ # The next 60 second time period next_tick = self.next_tick(self.period) # Every mini_tick, we will fire a thoughput of this size throughput_per_chunk = throughput / self.chunks # The size of a mini_tick (e.g. 0.6 seconds) mini_tick_period = self.period / float(self.chunks) chunks_sent, successes = 0, 0 while time.time() < next_tick and chunks_sent < self.chunks: if not self.resume.get(): break # Fire action and record time taken # time_taken, success = time_it(self.action, throughput_per_chunk) success = self.action(throughput_per_chunk) # Count successes if success: successes += 1 chunks_sent += 1 # The time remaining to reach the next mini tick time_till_next_mini_tick = max( 0, self.next_tick(mini_tick_period) - time.time()) # sleep to next mini tick to ensure actions happen evenly time.sleep(time_till_next_mini_tick) return successes * throughput_per_chunk