Reduce recorder overhead when entity filter is empty (#119631)

This commit is contained in:
J. Nick Koston 2024-06-14 01:43:51 -05:00 committed by GitHub
parent 9f41133bbc
commit 9082dc2a79
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 19 additions and 12 deletions

View File

@ -127,15 +127,15 @@ def is_entity_recorded(hass: HomeAssistant, entity_id: str) -> bool:
Async friendly. Async friendly.
""" """
if DATA_INSTANCE not in hass.data: instance = get_instance(hass)
return False return instance.entity_filter is None or instance.entity_filter(entity_id)
return hass.data[DATA_INSTANCE].entity_filter(entity_id)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the recorder.""" """Set up the recorder."""
conf = config[DOMAIN] conf = config[DOMAIN]
entity_filter = convert_include_exclude_filter(conf).get_filter() _filter = convert_include_exclude_filter(conf)
entity_filter = None if _filter.empty_filter else _filter.get_filter()
auto_purge = conf[CONF_AUTO_PURGE] auto_purge = conf[CONF_AUTO_PURGE]
auto_repack = conf[CONF_AUTO_REPACK] auto_repack = conf[CONF_AUTO_REPACK]
keep_days = conf[CONF_PURGE_KEEP_DAYS] keep_days = conf[CONF_PURGE_KEEP_DAYS]

View File

@ -178,7 +178,7 @@ class Recorder(threading.Thread):
uri: str, uri: str,
db_max_retries: int, db_max_retries: int,
db_retry_wait: int, db_retry_wait: int,
entity_filter: Callable[[str], bool], entity_filter: Callable[[str], bool] | None,
exclude_event_types: set[EventType[Any] | str], exclude_event_types: set[EventType[Any] | str],
) -> None: ) -> None:
"""Initialize the recorder.""" """Initialize the recorder."""
@ -318,7 +318,10 @@ class Recorder(threading.Thread):
if event.event_type in exclude_event_types: if event.event_type in exclude_event_types:
return return
if (entity_id := event.data.get(ATTR_ENTITY_ID)) is None: if (
entity_filter is None
or (entity_id := event.data.get(ATTR_ENTITY_ID)) is None
):
queue_put(event) queue_put(event)
return return

View File

@ -645,7 +645,7 @@ def _purge_filtered_data(instance: Recorder, session: Session) -> bool:
for (metadata_id, entity_id) in session.query( for (metadata_id, entity_id) in session.query(
StatesMeta.metadata_id, StatesMeta.entity_id StatesMeta.metadata_id, StatesMeta.entity_id
).all() ).all()
if not entity_filter(entity_id) if entity_filter and not entity_filter(entity_id)
] ]
if excluded_metadata_ids: if excluded_metadata_ids:
has_more_states_to_purge = _purge_filtered_states( has_more_states_to_purge = _purge_filtered_states(
@ -765,7 +765,9 @@ def _purge_filtered_events(
@retryable_database_job("purge_entity_data") @retryable_database_job("purge_entity_data")
def purge_entity_data( def purge_entity_data(
instance: Recorder, entity_filter: Callable[[str], bool], purge_before: datetime instance: Recorder,
entity_filter: Callable[[str], bool] | None,
purge_before: datetime,
) -> bool: ) -> bool:
"""Purge states and events of specified entities.""" """Purge states and events of specified entities."""
database_engine = instance.database_engine database_engine = instance.database_engine
@ -777,7 +779,7 @@ def purge_entity_data(
for (metadata_id, entity_id) in session.query( for (metadata_id, entity_id) in session.query(
StatesMeta.metadata_id, StatesMeta.entity_id StatesMeta.metadata_id, StatesMeta.entity_id
).all() ).all()
if entity_filter(entity_id) if entity_filter and entity_filter(entity_id)
] ]
_LOGGER.debug("Purging entity data for %s", selected_metadata_ids) _LOGGER.debug("Purging entity data for %s", selected_metadata_ids)
if not selected_metadata_ids: if not selected_metadata_ids:

View File

@ -80,6 +80,7 @@ def _get_sensor_states(hass: HomeAssistant) -> list[State]:
# We check for state class first before calling the filter # We check for state class first before calling the filter
# function as the filter function is much more expensive # function as the filter function is much more expensive
# than checking the state class # than checking the state class
entity_filter = instance.entity_filter
return [ return [
state state
for state in hass.states.all(DOMAIN) for state in hass.states.all(DOMAIN)
@ -88,7 +89,7 @@ def _get_sensor_states(hass: HomeAssistant) -> list[State]:
type(state_class) is SensorStateClass type(state_class) is SensorStateClass
or try_parse_enum(SensorStateClass, state_class) or try_parse_enum(SensorStateClass, state_class)
) )
and instance.entity_filter(state.entity_id) and (not entity_filter or entity_filter(state.entity_id))
] ]
@ -680,6 +681,7 @@ def validate_statistics(
sensor_entity_ids = {i.entity_id for i in sensor_states} sensor_entity_ids = {i.entity_id for i in sensor_states}
sensor_statistic_ids = set(metadatas) sensor_statistic_ids = set(metadatas)
instance = get_instance(hass) instance = get_instance(hass)
entity_filter = instance.entity_filter
for state in sensor_states: for state in sensor_states:
entity_id = state.entity_id entity_id = state.entity_id
@ -689,7 +691,7 @@ def validate_statistics(
state_unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) state_unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
if metadata := metadatas.get(entity_id): if metadata := metadatas.get(entity_id):
if not instance.entity_filter(state.entity_id): if entity_filter and not entity_filter(state.entity_id):
# Sensor was previously recorded, but no longer is # Sensor was previously recorded, but no longer is
validation_result[entity_id].append( validation_result[entity_id].append(
statistics.ValidationIssue( statistics.ValidationIssue(
@ -739,7 +741,7 @@ def validate_statistics(
) )
) )
elif state_class is not None: elif state_class is not None:
if not instance.entity_filter(state.entity_id): if entity_filter and not entity_filter(state.entity_id):
# Sensor is not recorded # Sensor is not recorded
validation_result[entity_id].append( validation_result[entity_id].append(
statistics.ValidationIssue( statistics.ValidationIssue(