core/homeassistant/components/recorder/pool.py

61 lines
1.9 KiB
Python

"""A pool for sqlite connections."""
import threading
from sqlalchemy.pool import NullPool, SingletonThreadPool
from homeassistant.helpers.frame import report
from .const import DB_WORKER_PREFIX
POOL_SIZE = 5
class RecorderPool(SingletonThreadPool, NullPool):
"""A hybrid of NullPool and SingletonThreadPool.
When called from the creating thread or db executor acts like SingletonThreadPool
When called from any other thread, acts like NullPool
"""
def __init__(self, *args, **kw): # pylint: disable=super-init-not-called
"""Create the pool."""
kw["pool_size"] = POOL_SIZE
SingletonThreadPool.__init__(self, *args, **kw)
@property
def recorder_or_dbworker(self) -> bool:
"""Check if the thread is a recorder or dbworker thread."""
thread_name = threading.current_thread().name
return bool(
thread_name == "Recorder" or thread_name.startswith(DB_WORKER_PREFIX)
)
def _do_return_conn(self, conn):
if self.recorder_or_dbworker:
return super()._do_return_conn(conn)
conn.close()
def shutdown(self):
"""Close the connection."""
if self.recorder_or_dbworker and self._conn and (conn := self._conn.current()):
conn.close()
def dispose(self):
"""Dispose of the connection."""
if self.recorder_or_dbworker:
return super().dispose()
def _do_get(self):
if self.recorder_or_dbworker:
return super()._do_get()
report(
"accesses the database without the database executor; "
"Use homeassistant.components.recorder.get_instance(hass).async_add_executor_job() "
"for faster database operations",
exclude_integrations={"recorder"},
error_if_core=False,
)
return super( # pylint: disable=bad-super-call
NullPool, self
)._create_connection()