mirror of
https://github.com/home-assistant/core.git
synced 2025-07-15 17:27:10 +00:00
Ensure all recorder session executes use retries or the execute helper (#89888)
This commit is contained in:
parent
fd5b57ae6c
commit
377dff5ee4
@ -43,6 +43,12 @@ KEEPALIVE_TIME = 30
|
|||||||
EXCLUDE_ATTRIBUTES = f"{DOMAIN}_exclude_attributes_by_domain"
|
EXCLUDE_ATTRIBUTES = f"{DOMAIN}_exclude_attributes_by_domain"
|
||||||
|
|
||||||
|
|
||||||
|
STATISTICS_ROWS_SCHEMA_VERSION = 23
|
||||||
|
CONTEXT_ID_AS_BINARY_SCHEMA_VERSION = 36
|
||||||
|
EVENT_TYPE_IDS_SCHEMA_VERSION = 37
|
||||||
|
STATES_META_SCHEMA_VERSION = 38
|
||||||
|
|
||||||
|
|
||||||
class SupportedDialect(StrEnum):
|
class SupportedDialect(StrEnum):
|
||||||
"""Supported dialects."""
|
"""Supported dialects."""
|
||||||
|
|
||||||
|
@ -41,8 +41,10 @@ from homeassistant.util.enum import try_parse_enum
|
|||||||
|
|
||||||
from . import migration, statistics
|
from . import migration, statistics
|
||||||
from .const import (
|
from .const import (
|
||||||
|
CONTEXT_ID_AS_BINARY_SCHEMA_VERSION,
|
||||||
DB_WORKER_PREFIX,
|
DB_WORKER_PREFIX,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
EVENT_TYPE_IDS_SCHEMA_VERSION,
|
||||||
KEEPALIVE_TIME,
|
KEEPALIVE_TIME,
|
||||||
MARIADB_PYMYSQL_URL_PREFIX,
|
MARIADB_PYMYSQL_URL_PREFIX,
|
||||||
MARIADB_URL_PREFIX,
|
MARIADB_URL_PREFIX,
|
||||||
@ -50,6 +52,8 @@ from .const import (
|
|||||||
MYSQLDB_PYMYSQL_URL_PREFIX,
|
MYSQLDB_PYMYSQL_URL_PREFIX,
|
||||||
MYSQLDB_URL_PREFIX,
|
MYSQLDB_URL_PREFIX,
|
||||||
SQLITE_URL_PREFIX,
|
SQLITE_URL_PREFIX,
|
||||||
|
STATES_META_SCHEMA_VERSION,
|
||||||
|
STATISTICS_ROWS_SCHEMA_VERSION,
|
||||||
SupportedDialect,
|
SupportedDialect,
|
||||||
)
|
)
|
||||||
from .db_schema import (
|
from .db_schema import (
|
||||||
@ -108,6 +112,7 @@ from .util import (
|
|||||||
build_mysqldb_conv,
|
build_mysqldb_conv,
|
||||||
dburl_to_path,
|
dburl_to_path,
|
||||||
end_incomplete_runs,
|
end_incomplete_runs,
|
||||||
|
execute_stmt_lambda_element,
|
||||||
is_second_sunday,
|
is_second_sunday,
|
||||||
move_away_broken_database,
|
move_away_broken_database,
|
||||||
session_scope,
|
session_scope,
|
||||||
@ -688,24 +693,28 @@ class Recorder(threading.Thread):
|
|||||||
# since we want the frontend queries to avoid a thundering
|
# since we want the frontend queries to avoid a thundering
|
||||||
# herd of queries to find the statistics meta data if
|
# herd of queries to find the statistics meta data if
|
||||||
# there are a lot of statistics graphs on the frontend.
|
# there are a lot of statistics graphs on the frontend.
|
||||||
if self.schema_version >= 23:
|
if self.schema_version >= STATISTICS_ROWS_SCHEMA_VERSION:
|
||||||
self.statistics_meta_manager.load(session)
|
self.statistics_meta_manager.load(session)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
self.schema_version < 36
|
self.schema_version < CONTEXT_ID_AS_BINARY_SCHEMA_VERSION
|
||||||
or session.execute(has_events_context_ids_to_migrate()).scalar()
|
or execute_stmt_lambda_element(
|
||||||
|
session, has_events_context_ids_to_migrate()
|
||||||
|
)
|
||||||
):
|
):
|
||||||
self.queue_task(StatesContextIDMigrationTask())
|
self.queue_task(StatesContextIDMigrationTask())
|
||||||
|
|
||||||
if (
|
if (
|
||||||
self.schema_version < 36
|
self.schema_version < CONTEXT_ID_AS_BINARY_SCHEMA_VERSION
|
||||||
or session.execute(has_states_context_ids_to_migrate()).scalar()
|
or execute_stmt_lambda_element(
|
||||||
|
session, has_states_context_ids_to_migrate()
|
||||||
|
)
|
||||||
):
|
):
|
||||||
self.queue_task(EventsContextIDMigrationTask())
|
self.queue_task(EventsContextIDMigrationTask())
|
||||||
|
|
||||||
if (
|
if (
|
||||||
self.schema_version < 37
|
self.schema_version < EVENT_TYPE_IDS_SCHEMA_VERSION
|
||||||
or session.execute(has_event_type_to_migrate()).scalar()
|
or execute_stmt_lambda_element(session, has_event_type_to_migrate())
|
||||||
):
|
):
|
||||||
self.queue_task(EventTypeIDMigrationTask())
|
self.queue_task(EventTypeIDMigrationTask())
|
||||||
else:
|
else:
|
||||||
@ -713,8 +722,8 @@ class Recorder(threading.Thread):
|
|||||||
self.event_type_manager.active = True
|
self.event_type_manager.active = True
|
||||||
|
|
||||||
if (
|
if (
|
||||||
self.schema_version < 38
|
self.schema_version < STATES_META_SCHEMA_VERSION
|
||||||
or session.execute(has_entity_ids_to_migrate()).scalar()
|
or execute_stmt_lambda_element(session, has_entity_ids_to_migrate())
|
||||||
):
|
):
|
||||||
self.queue_task(EntityIDMigrationTask())
|
self.queue_task(EntityIDMigrationTask())
|
||||||
else:
|
else:
|
||||||
@ -1002,7 +1011,7 @@ class Recorder(threading.Thread):
|
|||||||
if states_meta_manager.active:
|
if states_meta_manager.active:
|
||||||
dbstate.entity_id = None
|
dbstate.entity_id = None
|
||||||
|
|
||||||
self.event_session.add(dbstate)
|
session.add(dbstate)
|
||||||
|
|
||||||
def _handle_database_error(self, err: Exception) -> bool:
|
def _handle_database_error(self, err: Exception) -> bool:
|
||||||
"""Handle a database error that may result in moving away the corrupt db."""
|
"""Handle a database error that may result in moving away the corrupt db."""
|
||||||
@ -1015,9 +1024,9 @@ class Recorder(threading.Thread):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def _event_session_has_pending_writes(self) -> bool:
|
def _event_session_has_pending_writes(self) -> bool:
|
||||||
return bool(
|
"""Return True if there are pending writes in the event session."""
|
||||||
self.event_session and (self.event_session.new or self.event_session.dirty)
|
session = self.event_session
|
||||||
)
|
return bool(session and (session.new or session.dirty))
|
||||||
|
|
||||||
def _commit_event_session_or_retry(self) -> None:
|
def _commit_event_session_or_retry(self) -> None:
|
||||||
"""Commit the event session if there is work to do."""
|
"""Commit the event session if there is work to do."""
|
||||||
@ -1043,9 +1052,10 @@ class Recorder(threading.Thread):
|
|||||||
|
|
||||||
def _commit_event_session(self) -> None:
|
def _commit_event_session(self) -> None:
|
||||||
assert self.event_session is not None
|
assert self.event_session is not None
|
||||||
|
session = self.event_session
|
||||||
self._commits_without_expire += 1
|
self._commits_without_expire += 1
|
||||||
|
|
||||||
self.event_session.commit()
|
session.commit()
|
||||||
# We just committed the state attributes to the database
|
# We just committed the state attributes to the database
|
||||||
# and we now know the attributes_ids. We can save
|
# and we now know the attributes_ids. We can save
|
||||||
# many selects for matching attributes by loading them
|
# many selects for matching attributes by loading them
|
||||||
@ -1061,7 +1071,7 @@ class Recorder(threading.Thread):
|
|||||||
# do it after EXPIRE_AFTER_COMMITS commits
|
# do it after EXPIRE_AFTER_COMMITS commits
|
||||||
if self._commits_without_expire >= EXPIRE_AFTER_COMMITS:
|
if self._commits_without_expire >= EXPIRE_AFTER_COMMITS:
|
||||||
self._commits_without_expire = 0
|
self._commits_without_expire = 0
|
||||||
self.event_session.expire_all()
|
session.expire_all()
|
||||||
|
|
||||||
def _handle_sqlite_corruption(self) -> None:
|
def _handle_sqlite_corruption(self) -> None:
|
||||||
"""Handle the sqlite3 database being corrupt."""
|
"""Handle the sqlite3 database being corrupt."""
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
"""Support managing StatesMeta."""
|
"""Support managing StatesMeta."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable, Sequence
|
||||||
from typing import TYPE_CHECKING, cast
|
from typing import TYPE_CHECKING, cast
|
||||||
|
|
||||||
from sqlalchemy.orm.session import Session
|
from sqlalchemy.orm.session import Session
|
||||||
@ -63,7 +63,14 @@ class StatesMetaManager(BaseLRUTableManager[StatesMeta]):
|
|||||||
This call is always thread-safe.
|
This call is always thread-safe.
|
||||||
"""
|
"""
|
||||||
with session.no_autoflush:
|
with session.no_autoflush:
|
||||||
return dict(tuple(session.execute(find_all_states_metadata_ids()))) # type: ignore[arg-type]
|
return dict(
|
||||||
|
cast(
|
||||||
|
Sequence[tuple[int, str]],
|
||||||
|
execute_stmt_lambda_element(
|
||||||
|
session, find_all_states_metadata_ids()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def get_many(
|
def get_many(
|
||||||
self, entity_ids: Iterable[str], session: Session, from_recorder: bool
|
self, entity_ids: Iterable[str], session: Session, from_recorder: bool
|
||||||
|
Loading…
x
Reference in New Issue
Block a user