Skip to content

Commit ec7cefe

Browse files
committed
Merge branch 'main' of https://github.com/microsoft/mssql-python into release/0.7.0
2 parents b305d47 + 6961abb commit ec7cefe

File tree

6 files changed

+66
-4
lines changed

6 files changed

+66
-4
lines changed

mssql_python/__init__.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,21 @@
5454
threadsafety = 1
5555

5656
from .pooling import PoolingManager
57-
def pooling(max_size=100, idle_timeout=600):
57+
def pooling(max_size=100, idle_timeout=600, enabled=True):
5858
# """
5959
# Enable connection pooling with the specified parameters.
60-
60+
# By default:
61+
# - If not explicitly called, pooling will be auto-enabled with default values.
62+
6163
# Args:
6264
# max_size (int): Maximum number of connections in the pool.
6365
# idle_timeout (int): Time in seconds before idle connections are closed.
6466

6567
# Returns:
6668
# None
6769
# """
68-
PoolingManager.enable(max_size, idle_timeout)
70+
if not enabled:
71+
PoolingManager.disable()
72+
else:
73+
PoolingManager.enable(max_size, idle_timeout)
6974

mssql_python/connection.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ def __init__(self, connection_str: str = "", autocommit: bool = False, attrs_bef
5858
connection_str, **kwargs
5959
)
6060
self._attrs_before = attrs_before or {}
61+
# Auto-enable pooling if user never called
62+
if not PoolingManager.is_initialized():
63+
PoolingManager.enable()
6164
self._pooling = PoolingManager.is_enabled()
6265
self._conn = ddbc_bindings.Connection(self.connection_str, self._pooling, self._attrs_before)
6366
self.setautocommit(autocommit)

mssql_python/pooling.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
# mssql_python/pooling.py
2+
import atexit
23
from mssql_python import ddbc_bindings
34
import threading
45

56
class PoolingManager:
67
_enabled = False
8+
_initialized = False
79
_lock = threading.Lock()
810
_config = {
911
"max_size": 100,
@@ -23,7 +25,23 @@ def enable(cls, max_size=100, idle_timeout=600):
2325
cls._config["max_size"] = max_size
2426
cls._config["idle_timeout"] = idle_timeout
2527
cls._enabled = True
28+
cls._initialized = True
29+
30+
@classmethod
31+
def disable(cls):
32+
with cls._lock:
33+
cls._enabled = False
34+
cls._initialized = True
2635

2736
@classmethod
2837
def is_enabled(cls):
2938
return cls._enabled
39+
40+
@classmethod
41+
def is_initialized(cls):
42+
return cls._initialized
43+
44+
@atexit.register
45+
def shutdown_pooling():
46+
if PoolingManager.is_enabled():
47+
ddbc_bindings.close_pooling()

mssql_python/pybind/connection/connection_pool.cpp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,25 @@ void ConnectionPool::release(std::shared_ptr<Connection> conn) {
8383
}
8484
}
8585

86+
void ConnectionPool::close() {
87+
std::vector<std::shared_ptr<Connection>> to_close;
88+
{
89+
std::lock_guard<std::mutex> lock(_mutex);
90+
while (!_pool.empty()) {
91+
to_close.push_back(_pool.front());
92+
_pool.pop_front();
93+
}
94+
_current_size = 0;
95+
}
96+
for (auto& conn : to_close) {
97+
try {
98+
conn->disconnect();
99+
} catch (const std::exception& ex) {
100+
LOG("ConnectionPool::close: disconnect failed: {}", ex.what());
101+
}
102+
}
103+
}
104+
86105
ConnectionPoolManager& ConnectionPoolManager::getInstance() {
87106
static ConnectionPoolManager manager;
88107
return manager;
@@ -110,4 +129,14 @@ void ConnectionPoolManager::configure(int max_size, int idle_timeout_secs) {
110129
std::lock_guard<std::mutex> lock(_manager_mutex);
111130
_default_max_size = max_size;
112131
_default_idle_secs = idle_timeout_secs;
113-
}
132+
}
133+
134+
void ConnectionPoolManager::closePools() {
135+
std::lock_guard<std::mutex> lock(_manager_mutex);
136+
for (auto& [conn_str, pool] : _pools) {
137+
if (pool) {
138+
pool->close();
139+
}
140+
}
141+
_pools.clear();
142+
}

mssql_python/pybind/connection/connection_pool.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ class ConnectionPool {
2424
// Returns a connection to the pool for reuse
2525
void release(std::shared_ptr<Connection> conn);
2626

27+
// Closes all connections in the pool, releasing resources
28+
void close();
29+
2730
private:
2831
size_t _max_size; // Maximum number of connections allowed
2932
int _idle_timeout_secs; // Idle time before connections are considered stale
@@ -46,6 +49,9 @@ class ConnectionPoolManager {
4649
// Returns a connection to its original pool
4750
void returnConnection(const std::wstring& conn_str, std::shared_ptr<Connection> conn);
4851

52+
// Closes all pools and their connections
53+
void closePools();
54+
4955
private:
5056
ConnectionPoolManager() = default;
5157
~ConnectionPoolManager() = default;

mssql_python/pybind/ddbc_bindings.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2109,6 +2109,7 @@ PYBIND11_MODULE(ddbc_bindings, m) {
21092109
.def("get_autocommit", &ConnectionHandle::getAutocommit)
21102110
.def("alloc_statement_handle", &ConnectionHandle::allocStatementHandle);
21112111
m.def("enable_pooling", &enable_pooling, "Enable global connection pooling");
2112+
m.def("close_pooling", []() {ConnectionPoolManager::getInstance().closePools();});
21122113
m.def("DDBCSQLExecDirect", &SQLExecDirect_wrap, "Execute a SQL query directly");
21132114
m.def("DDBCSQLExecute", &SQLExecute_wrap, "Prepare and execute T-SQL statements");
21142115
m.def("DDBCSQLRowCount", &SQLRowCount_wrap,

0 commit comments

Comments
 (0)