From 81464050ddb95cfe62b086f575715c74f753f240 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 10 Mar 2023 08:54:40 -1000 Subject: [PATCH] tweak --- homeassistant/components/recorder/core.py | 6 +++++ .../components/recorder/migration.py | 1 + homeassistant/components/recorder/purge.py | 19 +++++++++++++++ homeassistant/components/recorder/queries.py | 23 +++++++++++++++++++ 4 files changed, 49 insertions(+) diff --git a/homeassistant/components/recorder/core.py b/homeassistant/components/recorder/core.py index ec726bf88fc..2c982fda7aa 100644 --- a/homeassistant/components/recorder/core.py +++ b/homeassistant/components/recorder/core.py @@ -164,6 +164,7 @@ class EventTypeManager: """Initialize the event manager.""" self._id_map: dict[str, int] = LRU(EVENT_DATA_ID_CACHE_SIZE) self._pending: dict[str, EventTypes] = {} + self.active = False def load(self, events: list[Event], session: Session) -> None: """Load the event types into memory.""" @@ -222,6 +223,11 @@ class EventTypeManager: self._id_map.clear() self._pending.clear() + def evict_purged(self, event_types: Iterable[str]) -> None: + """Evict purged event types.""" + for event_type in event_types: + self._id_map.pop(event_type, None) + class Recorder(threading.Thread): """A threaded recorder class.""" diff --git a/homeassistant/components/recorder/migration.py b/homeassistant/components/recorder/migration.py index 4022c6df053..cb36955ea43 100644 --- a/homeassistant/components/recorder/migration.py +++ b/homeassistant/components/recorder/migration.py @@ -1341,6 +1341,7 @@ def migrate_event_type_ids(instance: Recorder) -> bool: _drop_index( session_maker, "events", "ix_events_event_type_timed_fired_ts", quiet=True ) + instance.event_type_manager.active = True _LOGGER.debug("Migrating event_types done=%s", is_done) return is_done diff --git a/homeassistant/components/recorder/purge.py b/homeassistant/components/recorder/purge.py index 7ae63ef026b..91f6e11a099 100644 --- a/homeassistant/components/recorder/purge.py +++ b/homeassistant/components/recorder/purge.py @@ -24,12 +24,14 @@ from .queries import ( data_ids_exist_in_events_with_fast_in_distinct, delete_event_data_rows, delete_event_rows, + delete_event_types_rows, delete_recorder_runs_rows, delete_states_attributes_rows, delete_states_rows, delete_statistics_runs_rows, delete_statistics_short_term_rows, disconnect_states_rows, + find_event_types_to_purge, find_events_to_purge, find_latest_statistics_runs_run_id, find_legacy_event_state_and_attributes_and_data_ids_to_purge, @@ -110,6 +112,7 @@ def purge_old_data( return False _purge_old_recorder_runs(instance, session, purge_before) + _purge_old_event_types(instance, session) if repack: repack_database(instance) return True @@ -564,6 +567,22 @@ def _purge_old_recorder_runs( _LOGGER.debug("Deleted %s recorder_runs", deleted_rows) +def _purge_old_event_types(instance: Recorder, session: Session) -> None: + """Purge all old event types.""" + # Event types is small, no need to batch run it + purged_event_types = set() + event_type_ids = set() + for event_type_id, event_type in session.execute(find_event_types_to_purge()): + purged_event_types.add(event_type) + event_type_ids.add(event_type_id) + + deleted_rows = session.execute(delete_event_types_rows(event_type_ids)) + _LOGGER.debug("Deleted %s event types", deleted_rows) + + # Evict any entries in the event_type cache referring to a purged state + instance.event_type_manager.evict_purged(purged_event_types) + + def _purge_filtered_data(instance: Recorder, session: Session) -> bool: """Remove filtered states and events that shouldn't be in the database.""" _LOGGER.debug("Cleanup filtered data") diff --git a/homeassistant/components/recorder/queries.py b/homeassistant/components/recorder/queries.py index 700f733115f..b0e0e7a8900 100644 --- a/homeassistant/components/recorder/queries.py +++ b/homeassistant/components/recorder/queries.py @@ -737,3 +737,26 @@ def find_states_context_ids_to_migrate() -> StatementLambdaElement: .filter(States.context_id_bin.is_(None)) .limit(SQLITE_MAX_BIND_VARS) ) + + +def find_event_types_to_purge() -> StatementLambdaElement: + """Find event_type_ids to purge.""" + return lambda_stmt( + lambda: select(EventTypes.event_type_id, EventTypes.event_type).where( + EventTypes.event_type_id + == ( + select( + distinct(Events.event_type_id).label("unused_event_type_id") + ).filter(Events.event_type_id.not_in(select(EventTypes.event_type_id))) + ).c.unused_event_type_id + ) + ) + + +def delete_event_types_rows(event_type_ids: Iterable[int]) -> StatementLambdaElement: + """Delete EventTypes rows.""" + return lambda_stmt( + lambda: delete(EventTypes) + .where(EventTypes.event_type_id.in_(event_type_ids)) + .execution_options(synchronize_session=False) + )