Esempio n. 1
0
 def _run_transaction(self, access_mode, unit_of_work, *args, **kwargs):
     if not callable(unit_of_work):
         raise TypeError("Unit of work is not callable")
     retry_delay = retry_delay_generator(INITIAL_RETRY_DELAY,
                                         RETRY_DELAY_MULTIPLIER,
                                         RETRY_DELAY_JITTER_FACTOR)
     last_error = None
     t0 = perf_counter()
     while True:
         try:
             self._connect(access_mode)
             self._create_transaction()
             self.__begin__()
             with self._transaction as tx:
                 return unit_of_work(tx, *args, **kwargs)
         except (ServiceUnavailable, SessionExpired) as error:
             last_error = error
         except TransientError as error:
             if is_retriable_transient_error(error):
                 last_error = error
             else:
                 raise error
         t1 = perf_counter()
         if t1 - t0 > self._max_retry_time:
             break
         sleep(next(retry_delay))
     raise last_error
Esempio n. 2
0
    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, 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))
Esempio n. 3
0
    def __init__(self, address, sock, protocol_version, error_handler, **config):
        self.address = address
        self.socket = sock
        self.protocol_version = protocol_version
        self.error_handler = error_handler
        self.server = ServerInfo(SocketAddress.from_socket(sock))
        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_config["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_config["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:
            from neo4j.v1 import basic_auth
            self.auth_dict = vars(basic_auth(*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")
Esempio n. 4
0
 def _run_transaction(self, access_mode, unit_of_work, *args, **kwargs):
     if not callable(unit_of_work):
         raise TypeError("Unit of work is not callable")
     retry_delay = retry_delay_generator(INITIAL_RETRY_DELAY,
                                         RETRY_DELAY_MULTIPLIER,
                                         RETRY_DELAY_JITTER_FACTOR)
     errors = []
     t0 = perf_counter()
     while True:
         try:
             self._create_transaction()
             self._connect(access_mode)
             self.__begin__()
             tx = self._transaction
             try:
                 result = unit_of_work(tx, *args, **kwargs)
             except:
                 if tx.success is None:
                     tx.success = False
                 raise
             else:
                 if tx.success is None:
                     tx.success = True
             finally:
                 tx.close()
         except (ServiceUnavailable, SessionExpired) as error:
             errors.append(error)
         except TransientError as error:
             if is_retriable_transient_error(error):
                 errors.append(error)
             else:
                 raise
         else:
             return result
         t1 = perf_counter()
         if t1 - t0 > self._max_retry_time:
             break
         sleep(next(retry_delay))
     if errors:
         raise errors[-1]
     else:
         raise ServiceUnavailable("Transaction failed")
Esempio n. 5
0
 def timedout(self):
     return 0 <= self._max_connection_lifetime <= perf_counter(
     ) - self._creation_timestamp