Skip to content

Commit

Permalink
feat: speed up matching types in the ServiceBrowser (#1144)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdraco committed Apr 2, 2023
1 parent da10a3b commit 68871c3
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 6 deletions.
20 changes: 14 additions & 6 deletions src/zeroconf/_services/browser.py
Expand Up @@ -39,7 +39,7 @@
cast,
)

from .._dns import DNSAddress, DNSPointer, DNSQuestion, DNSQuestionType, DNSRecord
from .._dns import DNSPointer, DNSQuestion, DNSQuestionType, DNSRecord
from .._logger import log
from .._protocol.outgoing import DNSOutgoing
from .._services import (
Expand All @@ -49,7 +49,7 @@
SignalRegistrationInterface,
)
from .._updates import RecordUpdate, RecordUpdateListener
from .._utils.name import possible_types, service_type_name
from .._utils.name import cached_possible_types, service_type_name
from .._utils.time import current_time_millis, millis_to_seconds
from ..const import (
_BROWSER_BACKOFF_LIMIT,
Expand All @@ -62,6 +62,8 @@
_MDNS_ADDR,
_MDNS_ADDR6,
_MDNS_PORT,
_TYPE_A,
_TYPE_AAAA,
_TYPE_PTR,
)

Expand Down Expand Up @@ -338,7 +340,9 @@ def service_state_changed(self) -> SignalRegistrationInterface:

def _names_matching_types(self, names: Iterable[str]) -> List[Tuple[str, str]]:
"""Return the type and name for records matching the types we are browsing."""
return [(type_, name) for name in names for type_ in self.types.intersection(possible_types(name))]
return [
(type_, name) for name in names for type_ in self.types.intersection(cached_possible_types(name))
]

def _enqueue_callback(
self,
Expand All @@ -363,8 +367,12 @@ def _async_process_record_update(
self, now: float, record: DNSRecord, old_record: Optional[DNSRecord]
) -> None:
"""Process a single record update from a batch of updates."""
if isinstance(record, DNSPointer):
for type_ in self.types.intersection(possible_types(record.name)):
record_type = record.type

if record_type is _TYPE_PTR:
if TYPE_CHECKING:
record = cast(DNSPointer, record)
for type_ in self.types.intersection(cached_possible_types(record.name)):
if old_record is None:
self._enqueue_callback(ServiceStateChange.Added, type_, record.alias)
elif record.is_expired(now):
Expand All @@ -377,7 +385,7 @@ def _async_process_record_update(
if old_record or record.is_expired(now):
return

if isinstance(record, DNSAddress):
if record_type in (_TYPE_A, _TYPE_AAAA):
# Iterate through the DNSCache and callback any services that use this address
for type_, name in self._names_matching_types(
{service.name for service in self.zc.cache.async_entries_with_server(record.name)}
Expand Down
4 changes: 4 additions & 0 deletions src/zeroconf/_utils/name.py
Expand Up @@ -20,6 +20,7 @@
USA
"""

from functools import lru_cache
from typing import Set

from .._exceptions import BadTypeInNameException
Expand Down Expand Up @@ -170,3 +171,6 @@ def possible_types(name: str) -> Set[str]:
break
types.add('.'.join(parts))
return types


cached_possible_types = lru_cache(maxsize=256)(possible_types)

0 comments on commit 68871c3

Please sign in to comment.