Skip to content

Commit b9fce43

Browse files
authored
Merge pull request #391 from Mytherin/connectioncachelock
Avoid holding connection cache lock while doing Postgres operations
2 parents f683a8c + bd774ab commit b9fce43

File tree

2 files changed

+29
-17
lines changed

2 files changed

+29
-17
lines changed

src/include/storage/postgres_connection_pool.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class PostgresConnectionPool {
6161
vector<PostgresConnection> connection_cache;
6262

6363
private:
64-
PostgresPoolConnection GetConnectionInternal();
64+
PostgresPoolConnection GetConnectionInternal(unique_lock<mutex> &lock);
6565
};
6666

6767
} // namespace duckdb

src/storage/postgres_connection_pool.cpp

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -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

6161
PostgresPoolConnection 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

6666
bool 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

9292
void 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

Comments
 (0)