Skip to content

Commit 15daf6b

Browse files
committed
feat: speed up instances only used to lookup answers
If there is nothing in the ServiceRegistry we would still process incoming questions. If we have no answers to give, we can skip the handling queries completely as it significantly reduces cpu time.
1 parent 9ca9a57 commit 15daf6b

4 files changed

Lines changed: 32 additions & 6 deletions

File tree

src/zeroconf/_listener.pxd

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import cython
33

44
from ._handlers.record_manager cimport RecordManager
55
from ._protocol.incoming cimport DNSIncoming
6+
from ._services.registry cimport ServiceRegistry
67
from ._utils.time cimport current_time_millis, millis_to_seconds
78

89

@@ -18,6 +19,7 @@ cdef cython.uint _DUPLICATE_PACKET_SUPPRESSION_INTERVAL
1819
cdef class AsyncListener:
1920

2021
cdef public object zc
22+
cdef ServiceRegistry _registry
2123
cdef RecordManager _record_manager
2224
cdef public cython.bytes data
2325
cdef public cython.float last_time
@@ -34,3 +36,12 @@ cdef class AsyncListener:
3436
cpdef _process_datagram_at_time(self, bint debug, cython.uint data_len, cython.float now, bytes data, cython.tuple addrs)
3537

3638
cdef _cancel_any_timers_for_addr(self, object addr)
39+
40+
cpdef handle_query_or_defer(
41+
self,
42+
DNSIncoming msg,
43+
object addr,
44+
object port,
45+
object transport,
46+
tuple v6_flow_scope
47+
)

src/zeroconf/_listener.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class AsyncListener:
5757

5858
__slots__ = (
5959
'zc',
60+
'_registry',
6061
'_record_manager',
6162
'data',
6263
'last_time',
@@ -69,6 +70,7 @@ class AsyncListener:
6970

7071
def __init__(self, zc: 'Zeroconf') -> None:
7172
self.zc = zc
73+
self._registry = zc.registry
7274
self._record_manager = zc.record_manager
7375
self.data: Optional[bytes] = None
7476
self.last_time: float = 0
@@ -171,17 +173,21 @@ def _process_datagram_at_time(
171173
self._record_manager.async_updates_from_response(msg)
172174
return
173175

176+
if not self._registry.has_entries:
177+
# If the registry is empty, we have no answers to give.
178+
return
179+
174180
if TYPE_CHECKING:
175181
assert self.transport is not None
176182
self.handle_query_or_defer(msg, addr, port, self.transport, v6_flow_scope)
177183

178184
def handle_query_or_defer(
179185
self,
180186
msg: DNSIncoming,
181-
addr: str,
182-
port: int,
187+
addr: _str,
188+
port: _int,
183189
transport: _WrappedTransport,
184-
v6_flow_scope: Union[Tuple[()], Tuple[int, int]] = (),
190+
v6_flow_scope: Union[Tuple[()], Tuple[int, int]],
185191
) -> None:
186192
"""Deal with incoming query packets. Provides a response if
187193
possible."""

src/zeroconf/_services/registry.pxd

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ cdef class ServiceRegistry:
99
cdef cython.dict _services
1010
cdef public cython.dict types
1111
cdef public cython.dict servers
12+
cdef public bint has_entries
1213

1314
@cython.locals(
1415
record_list=cython.list,
@@ -17,6 +18,10 @@ cdef class ServiceRegistry:
1718

1819
cdef _add(self, ServiceInfo info)
1920

21+
@cython.locals(
22+
info=ServiceInfo,
23+
old_service_info=ServiceInfo
24+
)
2025
cdef _remove(self, cython.list infos)
2126

2227
cpdef ServiceInfo async_get_info_name(self, str name)

src/zeroconf/_services/registry.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class ServiceRegistry:
3535
the event loop as it is not thread safe.
3636
"""
3737

38-
__slots__ = ("_services", "types", "servers")
38+
__slots__ = ("_services", "types", "servers", "has_entries")
3939

4040
def __init__(
4141
self,
@@ -44,6 +44,7 @@ def __init__(
4444
self._services: Dict[str, ServiceInfo] = {}
4545
self.types: Dict[str, List] = {}
4646
self.servers: Dict[str, List] = {}
47+
self.has_entries: bool = False
4748

4849
def async_add(self, info: ServiceInfo) -> None:
4950
"""Add a new service to the registry."""
@@ -95,14 +96,17 @@ def _add(self, info: ServiceInfo) -> None:
9596
self._services[info.key] = info
9697
self.types.setdefault(info.type.lower(), []).append(info.key)
9798
self.servers.setdefault(info.server_key, []).append(info.key)
99+
self.has_entries = True
98100

99101
def _remove(self, infos: List[ServiceInfo]) -> None:
100102
"""Remove a services under the lock."""
101103
for info in infos:
102-
if info.key not in self._services:
104+
old_service_info = self._services.get(info.key)
105+
if old_service_info is None:
103106
continue
104-
old_service_info = self._services[info.key]
105107
assert old_service_info.server_key is not None
106108
self.types[old_service_info.type.lower()].remove(info.key)
107109
self.servers[old_service_info.server_key].remove(info.key)
108110
del self._services[info.key]
111+
112+
self.has_entries = bool(self._services)

0 commit comments

Comments
 (0)