@@ -44,31 +44,31 @@ PostgresConnectionPool::PostgresConnectionPool(PostgresCatalog &postgres_catalog
4444 : postgres_catalog(postgres_catalog), active_connections(0 ), maximum_connections(maximum_connections_p) {
4545}
4646
47- PostgresPoolConnection PostgresConnectionPool::GetConnectionInternal () {
47+ PostgresPoolConnection PostgresConnectionPool::GetConnectionInternal (unique_lock<mutex> &lock ) {
4848 active_connections++;
4949 // check if we have any cached connections left
5050 if (!connection_cache.empty ()) {
5151 auto connection = PostgresPoolConnection (this , std::move (connection_cache.back ()));
5252 connection_cache.pop_back ();
5353 return connection;
5454 }
55-
56- // no cached connections left but there is space to open a new one - open it
55+ // no cached connections left but there is space to open a new one - open it after releasing the cache lock
56+ lock. unlock ();
5757 return PostgresPoolConnection (
5858 this , PostgresConnection::Open (postgres_catalog.connection_string , postgres_catalog.attach_path ));
5959}
6060
6161PostgresPoolConnection PostgresConnectionPool::ForceGetConnection () {
62- lock_guard <mutex> l (connection_lock);
63- return GetConnectionInternal ();
62+ unique_lock <mutex> l (connection_lock);
63+ return GetConnectionInternal (l );
6464}
6565
6666bool PostgresConnectionPool::TryGetConnection (PostgresPoolConnection &connection) {
67- lock_guard <mutex> l (connection_lock);
67+ unique_lock <mutex> l (connection_lock);
6868 if (active_connections >= maximum_connections) {
6969 return false ;
7070 }
71- connection = GetConnectionInternal ();
71+ connection = GetConnectionInternal (l );
7272 return true ;
7373}
7474
@@ -90,30 +90,42 @@ PostgresPoolConnection PostgresConnectionPool::GetConnection() {
9090}
9191
9292void PostgresConnectionPool::ReturnConnection (PostgresConnection connection) {
93- lock_guard <mutex> l (connection_lock);
93+ unique_lock <mutex> l (connection_lock);
9494 if (active_connections <= 0 ) {
9595 throw InternalException (" PostgresConnectionPool::ReturnConnection called but active_connections is 0" );
9696 }
97- active_connections--;
98- if (active_connections >= maximum_connections) {
99- // if the maximum number of connections has been decreased by the user we might need to reclaim the connection
100- // immediately
101- return ;
102- }
10397 if (!pg_use_connection_cache) {
98+ // not caching - just return
99+ active_connections--;
104100 return ;
105101 }
102+ // we want to cache the connection
106103 // check if the underlying connection is still usable
104+ // avoid holding the lock while doing this
105+ l.unlock ();
106+ bool connection_is_bad = false ;
107107 auto pg_con = connection.GetConn ();
108108 if (PQstatus (connection.GetConn ()) != CONNECTION_OK) {
109109 // CONNECTION_BAD! try to reset it
110110 PQreset (pg_con);
111111 if (PQstatus (connection.GetConn ()) != CONNECTION_OK) {
112112 // still bad - just abandon this one
113- return ;
113+ connection_is_bad = true ;
114114 }
115115 }
116- if (PQtransactionStatus (pg_con) != PQTRANS_IDLE) {
116+ if (!connection_is_bad && PQtransactionStatus (pg_con) != PQTRANS_IDLE) {
117+ connection_is_bad = true ;
118+ }
119+ // lock and return the connection
120+ l.lock ();
121+ active_connections--;
122+ if (connection_is_bad) {
123+ // if the connection is bad we cannot cache it
124+ return ;
125+ }
126+ if (active_connections >= maximum_connections) {
127+ // if the maximum number of connections has been decreased by the user we might need to reclaim the connection
128+ // immediately
117129 return ;
118130 }
119131 connection_cache.push_back (std::move (connection));
0 commit comments