pudo / dataset

Easy-to-use data handling for SQL data stores with support for implicit table creation, bulk loading, and transactions.
https://dataset.readthedocs.org/
MIT License
4.76k stars 297 forks source link

Database connection is not released when dataset.Database.close() function is called. #363

Closed branchjoshua closed 3 years ago

branchjoshua commented 3 years ago

Issue

Database connection is not released when dataset.Database.close() function is called. Was found when trying to create, use, and delete sqlite databases when unit testing some of my own code.

Example to Reproduce Issue

import os
import dataset

# Connect to a database and perform an action that will invoke dataset.Database.executable() function
db = dataset.connect('sqlite:///test.db')
table = db['user']
table.insert(dict(name='John Doe', age=46, country='China'))
db.close()

# Attempting to delete database file will fail with the file still being locked.
os.remove('test.db')

Research

Dug into the issue a little. Calling dispose on a sqlalchemy engine will not close connections that have been checked out and not returned to the connection pool. The connections opened in the dataset.Database.executable() function and stored in self.local.conn are never returned to the connection pool, and thusly are not closed by self.engine.dispose(). Here is the relevant text from sqlalchemy docs: https://docs.sqlalchemy.org/en/13/core/connections.html#engine-disposal

A Possible Fix

I got something working by moving away from using threading.local() for storing the connectoins in dataset.Database. Instead, I added a self.connections = {} dictionary, where the key is the current thread identifier and the value being the sqlalchemy connection. Threw the lock around checking/modifying that dictionary, and in the dataset.Database.close() function I iterate over the dictionary, close all the connections, and finally clear the dictionary (again inside the lock). It seems to work. If I get a chance this week, I'll throw together a PR for it.

Thank you!

Thank you for this wonderful library!