Improve logbook context augment performance (#106926)
Makes LazyEventPartialState a bit lazier since almost all the properties are never called.
This commit is contained in:
parent
d8c6534aff
commit
0b9992260a
3 changed files with 35 additions and 19 deletions
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any, cast
|
from typing import TYPE_CHECKING, Any, cast
|
||||||
|
|
||||||
from sqlalchemy.engine.row import Row
|
from sqlalchemy.engine.row import Row
|
||||||
|
|
||||||
|
@ -20,6 +20,11 @@ import homeassistant.util.dt as dt_util
|
||||||
from homeassistant.util.json import json_loads
|
from homeassistant.util.json import json_loads
|
||||||
from homeassistant.util.ulid import ulid_to_bytes
|
from homeassistant.util.ulid import ulid_to_bytes
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from functools import cached_property
|
||||||
|
else:
|
||||||
|
from homeassistant.backports.functools import cached_property
|
||||||
|
|
||||||
|
|
||||||
@dataclass(slots=True)
|
@dataclass(slots=True)
|
||||||
class LogbookConfig:
|
class LogbookConfig:
|
||||||
|
@ -35,16 +40,6 @@ class LogbookConfig:
|
||||||
class LazyEventPartialState:
|
class LazyEventPartialState:
|
||||||
"""A lazy version of core Event with limited State joined in."""
|
"""A lazy version of core Event with limited State joined in."""
|
||||||
|
|
||||||
__slots__ = [
|
|
||||||
"row",
|
|
||||||
"_event_data",
|
|
||||||
"_event_data_cache",
|
|
||||||
"event_type",
|
|
||||||
"entity_id",
|
|
||||||
"state",
|
|
||||||
"data",
|
|
||||||
]
|
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
row: Row | EventAsRow,
|
row: Row | EventAsRow,
|
||||||
|
@ -54,9 +49,6 @@ class LazyEventPartialState:
|
||||||
self.row = row
|
self.row = row
|
||||||
self._event_data: dict[str, Any] | None = None
|
self._event_data: dict[str, Any] | None = None
|
||||||
self._event_data_cache = event_data_cache
|
self._event_data_cache = event_data_cache
|
||||||
self.event_type: str | None = self.row.event_type
|
|
||||||
self.entity_id: str | None = self.row.entity_id
|
|
||||||
self.state = self.row.state
|
|
||||||
# We need to explicitly check for the row is EventAsRow as the unhappy path
|
# We need to explicitly check for the row is EventAsRow as the unhappy path
|
||||||
# to fetch row.data for Row is very expensive
|
# to fetch row.data for Row is very expensive
|
||||||
if type(row) is EventAsRow: # noqa: E721
|
if type(row) is EventAsRow: # noqa: E721
|
||||||
|
@ -64,7 +56,10 @@ class LazyEventPartialState:
|
||||||
# json decode process as we already have the data
|
# json decode process as we already have the data
|
||||||
self.data = row.data
|
self.data = row.data
|
||||||
return
|
return
|
||||||
source = cast(str, self.row.event_data)
|
if TYPE_CHECKING:
|
||||||
|
source = cast(str, row.event_data)
|
||||||
|
else:
|
||||||
|
source = row.event_data
|
||||||
if not source:
|
if not source:
|
||||||
self.data = {}
|
self.data = {}
|
||||||
elif event_data := self._event_data_cache.get(source):
|
elif event_data := self._event_data_cache.get(source):
|
||||||
|
@ -74,17 +69,32 @@ class LazyEventPartialState:
|
||||||
dict[str, Any], json_loads(source)
|
dict[str, Any], json_loads(source)
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
|
def event_type(self) -> str | None:
|
||||||
|
"""Return the event type."""
|
||||||
|
return self.row.event_type
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def entity_id(self) -> str | None:
|
||||||
|
"""Return the entity id."""
|
||||||
|
return self.row.entity_id
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def state(self) -> str | None:
|
||||||
|
"""Return the state."""
|
||||||
|
return self.row.state
|
||||||
|
|
||||||
|
@cached_property
|
||||||
def context_id(self) -> str | None:
|
def context_id(self) -> str | None:
|
||||||
"""Return the context id."""
|
"""Return the context id."""
|
||||||
return bytes_to_ulid_or_none(self.row.context_id_bin)
|
return bytes_to_ulid_or_none(self.row.context_id_bin)
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def context_user_id(self) -> str | None:
|
def context_user_id(self) -> str | None:
|
||||||
"""Return the context user id."""
|
"""Return the context user id."""
|
||||||
return bytes_to_uuid_hex_or_none(self.row.context_user_id_bin)
|
return bytes_to_uuid_hex_or_none(self.row.context_user_id_bin)
|
||||||
|
|
||||||
@property
|
@cached_property
|
||||||
def context_parent_id(self) -> str | None:
|
def context_parent_id(self) -> str | None:
|
||||||
"""Return the context parent id."""
|
"""Return the context parent id."""
|
||||||
return bytes_to_ulid_or_none(self.row.context_parent_id_bin)
|
return bytes_to_ulid_or_none(self.row.context_parent_id_bin)
|
||||||
|
|
|
@ -425,7 +425,7 @@ class EventCache:
|
||||||
|
|
||||||
def get(self, row: EventAsRow | Row) -> LazyEventPartialState:
|
def get(self, row: EventAsRow | Row) -> LazyEventPartialState:
|
||||||
"""Get the event from the row."""
|
"""Get the event from the row."""
|
||||||
if isinstance(row, EventAsRow):
|
if type(row) is EventAsRow: # noqa: E721 - this is never subclassed
|
||||||
return LazyEventPartialState(row, self._event_data_cache)
|
return LazyEventPartialState(row, self._event_data_cache)
|
||||||
if event := self.event_cache.get(row):
|
if event := self.event_cache.get(row):
|
||||||
return event
|
return event
|
||||||
|
|
|
@ -12,9 +12,15 @@ def test_lazy_event_partial_state_context():
|
||||||
context_user_id_bin=b"1234123412341234",
|
context_user_id_bin=b"1234123412341234",
|
||||||
context_parent_id_bin=b"4444444444444444",
|
context_parent_id_bin=b"4444444444444444",
|
||||||
event_data={},
|
event_data={},
|
||||||
|
event_type="event_type",
|
||||||
|
entity_id="entity_id",
|
||||||
|
state="state",
|
||||||
),
|
),
|
||||||
{},
|
{},
|
||||||
)
|
)
|
||||||
assert state.context_id == "1H68SK8C9J6CT32CHK6GRK4CSM"
|
assert state.context_id == "1H68SK8C9J6CT32CHK6GRK4CSM"
|
||||||
assert state.context_user_id == "31323334313233343132333431323334"
|
assert state.context_user_id == "31323334313233343132333431323334"
|
||||||
assert state.context_parent_id == "1M6GT38D1M6GT38D1M6GT38D1M"
|
assert state.context_parent_id == "1M6GT38D1M6GT38D1M6GT38D1M"
|
||||||
|
assert state.event_type == "event_type"
|
||||||
|
assert state.entity_id == "entity_id"
|
||||||
|
assert state.state == "state"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue