Skip to content

Commit a65abcd

Browse files
committed
feat: Improve performance of loading records from cache in ServiceInfo
- add a few more cython defs
1 parent 248b506 commit a65abcd

3 files changed

Lines changed: 44 additions & 31 deletions

File tree

src/zeroconf/_dns.pxd

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ cdef class DNSService(DNSRecord):
106106
cdef public object priority
107107
cdef public object weight
108108
cdef public object port
109-
cdef public object server
110-
cdef public object server_key
109+
cdef public str server
110+
cdef public str server_key
111111

112112
cdef _eq(self, DNSService other)
113113

src/zeroconf/_services/info.pxd

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
import cython
33

44
from .._cache cimport DNSCache
5-
from .._dns cimport DNSNsec, DNSPointer, DNSRecord, DNSService, DNSText
5+
from .._dns cimport DNSAddress, DNSNsec, DNSPointer, DNSRecord, DNSService, DNSText
66
from .._protocol.outgoing cimport DNSOutgoing
77
from .._updates cimport RecordUpdateListener
88
from .._utils.time cimport current_time_millis
99

1010

1111
cdef object _resolve_all_futures_to_none
12+
cdef object _cached_ip_addresses_wrapper
1213

1314
cdef object _TYPE_SRV
1415
cdef object _TYPE_TXT
@@ -55,29 +56,29 @@ cdef class ServiceInfo(RecordUpdateListener):
5556
cdef public cython.list _dns_address_cache
5657
cdef public cython.set _get_address_and_nsec_records_cache
5758

58-
@cython.locals(
59-
cache=DNSCache,
60-
)
59+
@cython.locals(cache=DNSCache)
6160
cpdef async_update_records(self, object zc, cython.float now, cython.list records)
6261

63-
@cython.locals(
64-
cache=DNSCache
65-
)
66-
cpdef _load_from_cache(self, object zc, object now)
62+
@cython.locals(cache=DNSCache)
63+
cpdef _load_from_cache(self, object zc, cython.float now)
6764

6865
cdef _unpack_text_into_properties(self)
6966

7067
cdef _set_properties(self, cython.dict properties)
7168

7269
cdef _set_text(self, cython.bytes text)
7370

74-
cdef _get_ip_addresses_from_cache_lifo(self, object zc, object now, object type)
75-
76-
cdef _process_record_threadsafe(self, object zc, DNSRecord record, cython.float now)
71+
@cython.locals(record=DNSAddress)
72+
cdef _get_ip_addresses_from_cache_lifo(self, object zc, cython.float now, object type)
7773

7874
@cython.locals(
79-
cache=DNSCache
75+
dns_service_record=DNSService,
76+
dns_text_record=DNSText,
77+
dns_address_record=DNSAddress
8078
)
79+
cdef _process_record_threadsafe(self, object zc, DNSRecord record, cython.float now)
80+
81+
@cython.locals(cache=DNSCache)
8182
cdef cython.list _get_address_records_from_cache_by_type(self, object zc, object _type)
8283

8384
cdef _set_ipv4_addresses_from_cache(self, object zc, object now)

src/zeroconf/_services/info.py

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,9 @@ def _cached_ip_addresses(address: Union[str, bytes, int]) -> Optional[Union[IPv4
107107
return None
108108

109109

110+
_cached_ip_addresses_wrapper = _cached_ip_addresses
111+
112+
110113
class ServiceInfo(RecordUpdateListener):
111114
"""Service information.
112115
@@ -197,7 +200,7 @@ def __init__(
197200
self.host_ttl = host_ttl
198201
self.other_ttl = other_ttl
199202
self.interface_index = interface_index
200-
self._new_records_futures: Set[asyncio.Future] = set()
203+
self._new_records_futures: Optional[Set[asyncio.Future]] = None
201204
self._dns_address_cache: Optional[List[DNSAddress]] = None
202205
self._dns_pointer_cache: Optional[DNSPointer] = None
203206
self._dns_service_cache: Optional[DNSService] = None
@@ -240,7 +243,7 @@ def addresses(self, value: List[bytes]) -> None:
240243
self._get_address_and_nsec_records_cache = None
241244

242245
for address in value:
243-
addr = _cached_ip_addresses(address)
246+
addr = _cached_ip_addresses_wrapper(address)
244247
if addr is None:
245248
raise TypeError(
246249
"Addresses must either be IPv4 or IPv6 strings, bytes, or integers;"
@@ -272,6 +275,8 @@ def properties(self) -> Dict[Union[str, bytes], Optional[Union[str, bytes]]]:
272275

273276
async def async_wait(self, timeout: float, loop: Optional[asyncio.AbstractEventLoop] = None) -> None:
274277
"""Calling task waits for a given number of milliseconds or until notified."""
278+
if not self._new_records_futures:
279+
self._new_records_futures = set()
275280
await wait_for_future_set_or_timeout(
276281
loop or asyncio.get_running_loop(), self._new_records_futures, timeout
277282
)
@@ -409,7 +414,7 @@ def _get_ip_addresses_from_cache_lifo(
409414
for record in self._get_address_records_from_cache_by_type(zc, type):
410415
if record.is_expired(now):
411416
continue
412-
ip_addr = _cached_ip_addresses(record.address)
417+
ip_addr = _cached_ip_addresses_wrapper(record.address)
413418
if ip_addr is not None:
414419
address_list.append(ip_addr)
415420
address_list.reverse() # Reverse to get LIFO order
@@ -455,12 +460,17 @@ def _process_record_threadsafe(self, zc: 'Zeroconf', record: DNSRecord, now: flo
455460

456461
record_key = record.key
457462
record_type = type(record)
458-
if record_key == self.server_key and record_type is DNSAddress:
463+
if record_type is DNSAddress and record_key == self.server_key:
464+
dns_address_record = record
459465
if TYPE_CHECKING:
460-
assert isinstance(record, DNSAddress)
461-
ip_addr = _cached_ip_addresses(record.address)
466+
assert isinstance(dns_address_record, DNSAddress)
467+
ip_addr = _cached_ip_addresses_wrapper(dns_address_record.address)
462468
if ip_addr is None:
463-
log.warning("Encountered invalid address while processing %s: %s", record, record.address)
469+
log.warning(
470+
"Encountered invalid address while processing %s: %s",
471+
dns_address_record,
472+
dns_address_record.address,
473+
)
464474
return False
465475

466476
if ip_addr.version == 4:
@@ -492,22 +502,24 @@ def _process_record_threadsafe(self, zc: 'Zeroconf', record: DNSRecord, now: flo
492502
return False
493503

494504
if record_type is DNSText:
505+
dns_text_record = record
495506
if TYPE_CHECKING:
496-
assert isinstance(record, DNSText)
497-
self._set_text(record.text)
507+
assert isinstance(dns_text_record, DNSText)
508+
self._set_text(dns_text_record.text)
498509
return True
499510

500511
if record_type is DNSService:
512+
dns_service_record = record
501513
if TYPE_CHECKING:
502-
assert isinstance(record, DNSService)
514+
assert isinstance(dns_service_record, DNSService)
503515
old_server_key = self.server_key
504-
self._name = record.name
505-
self.key = record.key
506-
self.server = record.server
507-
self.server_key = record.server_key
508-
self.port = record.port
509-
self.weight = record.weight
510-
self.priority = record.priority
516+
self._name = dns_service_record.name
517+
self.key = dns_service_record.key
518+
self.server = dns_service_record.server
519+
self.server_key = dns_service_record.server_key
520+
self.port = dns_service_record.port
521+
self.weight = dns_service_record.weight
522+
self.priority = dns_service_record.priority
511523
if old_server_key != self.server_key:
512524
self._set_ipv4_addresses_from_cache(zc, now)
513525
self._set_ipv6_addresses_from_cache(zc, now)

0 commit comments

Comments
 (0)