def acquire_direct(self, address): """ Acquire a connection to a given address from the pool. The address supplied should always be an IP address, not a host name. This method is thread safe. """ if self.closed(): raise ServiceUnavailable("Connection pool closed") with self.lock: try: connections = self.connections[address] except KeyError: connections = self.connections[address] = deque() connection_acquisition_start_timestamp = perf_counter() while True: # try to find a free connection in pool for connection in list(connections): if connection.closed() or connection.defunct( ) or connection.timedout(): connections.remove(connection) continue if not connection.in_use: connection.in_use = True return connection # all connections in pool are in-use can_create_new_connection = self._max_connection_pool_size == INFINITE or len( connections) < self._max_connection_pool_size if can_create_new_connection: try: connection = self.connector( address, error_handler=self.connection_error_handler) except ServiceUnavailable: self.remove(address) raise else: connection.pool = self connection.in_use = True connections.append(connection) return connection # failed to obtain a connection from pool because the pool is full and no free connection in the pool span_timeout = self._connection_acquisition_timeout - ( perf_counter() - connection_acquisition_start_timestamp) if span_timeout > 0: self.cond.wait(span_timeout) # if timed out, then we throw error. This time computation is needed, as with python 2.7, we cannot # tell if the condition is notified or timed out when we come to this line if self._connection_acquisition_timeout <= ( perf_counter() - connection_acquisition_start_timestamp): raise ClientError( "Failed to obtain a connection from pool within {!r}s" .format(self._connection_acquisition_timeout)) else: raise ClientError( "Failed to obtain a connection from pool within {!r}s". format(self._connection_acquisition_timeout))
def __init__(self, protocol_version, address, sock, **config): self.protocol_version = protocol_version self.address = address self.socket = sock self.error_handler = config.get("error_handler", ConnectionErrorHandler()) self.server = ServerInfo(SocketAddress.from_socket(sock), protocol_version) self.input_buffer = ChunkedInputBuffer() self.output_buffer = ChunkedOutputBuffer() self.packer = Packer(self.output_buffer) self.unpacker = Unpacker() self.responses = deque() self._max_connection_lifetime = config.get("max_connection_lifetime", DEFAULT_MAX_CONNECTION_LIFETIME) self._creation_timestamp = perf_counter() # Determine the user agent and ensure it is a Unicode value user_agent = config.get("user_agent", DEFAULT_USER_AGENT) if isinstance(user_agent, bytes): user_agent = user_agent.decode("UTF-8") self.user_agent = user_agent # Determine auth details auth = config.get("auth") if not auth: self.auth_dict = {} elif isinstance(auth, tuple) and 2 <= len(auth) <= 3: self.auth_dict = vars(AuthToken("basic", *auth)) else: try: self.auth_dict = vars(auth) except (KeyError, TypeError): raise TypeError("Cannot determine auth details from %r" % auth) # Pick up the server certificate, if any self.der_encoded_server_certificate = config.get("der_encoded_server_certificate")
def is_fresh(self, access_mode): """ Indicator for whether routing information is still usable. """ expired = self.last_updated_time + self.ttl <= perf_counter() has_server_for_mode = (access_mode == READ_ACCESS and self.readers) or (access_mode == WRITE_ACCESS and self.writers) return not expired and self.routers and has_server_for_mode
def update(self, new_routing_table): """ Update the current routing table with new routing information from a replacement table. """ self.routers.replace(new_routing_table.routers) self.readers.replace(new_routing_table.readers) self.writers.replace(new_routing_table.writers) self.last_updated_time = perf_counter() self.ttl = new_routing_table.ttl
def timedout(self): return 0 <= self._max_connection_lifetime <= perf_counter( ) - self._creation_timestamp
def __init__(self, routers=(), readers=(), writers=(), ttl=0): self.routers = OrderedSet(routers) self.readers = OrderedSet(readers) self.writers = OrderedSet(writers) self.last_updated_time = perf_counter() self.ttl = ttl