Skip to content

Commit 5e31f0a

Browse files
authored
feat: reduce overhead to process incoming updates by avoiding the handle_response shim (#1247)
1 parent f26218d commit 5e31f0a

9 files changed

Lines changed: 35 additions & 23 deletions

File tree

src/zeroconf/_core.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,7 @@ def async_remove_listener(self, listener: RecordUpdateListener) -> None:
564564
def handle_response(self, msg: DNSIncoming) -> None:
565565
"""Deal with incoming response packets. All answers
566566
are held in the cache, and listeners are notified."""
567+
self.log_warning_once("handle_response is deprecated, use record_manager.async_updates_from_response")
567568
self.record_manager.async_updates_from_response(msg)
568569

569570
def handle_assembled_query(

src/zeroconf/_listener.pxd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
import cython
33

4+
from ._handlers.record_manager cimport RecordManager
45
from ._protocol.incoming cimport DNSIncoming
56
from ._utils.time cimport current_time_millis, millis_to_seconds
67

@@ -12,9 +13,12 @@ cdef object TYPE_CHECKING
1213
cdef cython.uint _MAX_MSG_ABSOLUTE
1314
cdef cython.uint _DUPLICATE_PACKET_SUPPRESSION_INTERVAL
1415

16+
17+
1518
cdef class AsyncListener:
1619

1720
cdef public object zc
21+
cdef RecordManager _record_manager
1822
cdef public cython.bytes data
1923
cdef public cython.float last_time
2024
cdef public DNSIncoming last_message

src/zeroconf/_listener.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class AsyncListener:
5555

5656
__slots__ = (
5757
'zc',
58+
'_record_manager',
5859
'data',
5960
'last_time',
6061
'last_message',
@@ -66,6 +67,7 @@ class AsyncListener:
6667

6768
def __init__(self, zc: 'Zeroconf') -> None:
6869
self.zc = zc
70+
self._record_manager = zc.record_manager
6971
self.data: Optional[bytes] = None
7072
self.last_time: float = 0
7173
self.last_message: Optional[DNSIncoming] = None
@@ -156,7 +158,7 @@ def datagram_received(
156158
return
157159

158160
if not msg.is_query():
159-
self.zc.handle_response(msg)
161+
self._record_manager.async_updates_from_response(msg)
160162
return
161163

162164
self.handle_query_or_defer(msg, addr, port, self.transport, v6_flow_scope)

src/zeroconf/_protocol/incoming.pxd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ cdef class DNSIncoming:
7070
)
7171
cpdef has_qu_question(self)
7272

73+
cpdef is_query(self)
74+
75+
cpdef is_response(self)
76+
7377
@cython.locals(
7478
off=cython.uint,
7579
label_idx=cython.uint,

tests/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def _inject_responses(zc: Zeroconf, msgs: List[DNSIncoming]) -> None:
4242

4343
async def _wait_for_response():
4444
for msg in msgs:
45-
zc.handle_response(msg)
45+
zc.record_manager.async_updates_from_response(msg)
4646

4747
asyncio.run_coroutine_threadsafe(_wait_for_response(), zc.loop).result()
4848

tests/services/test_info.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -903,7 +903,7 @@ async def test_release_wait_when_new_recorded_added():
903903
)
904904
await aiozc.zeroconf.async_wait_for_start()
905905
await asyncio.sleep(0)
906-
aiozc.zeroconf.handle_response(r.DNSIncoming(generated.packets()[0]))
906+
aiozc.zeroconf.record_manager.async_updates_from_response(r.DNSIncoming(generated.packets()[0]))
907907
assert await asyncio.wait_for(task, timeout=2)
908908
assert info.addresses == [b'\x7f\x00\x00\x01']
909909
await aiozc.async_close()
@@ -966,7 +966,7 @@ async def test_port_changes_are_seen():
966966
)
967967
await aiozc.zeroconf.async_wait_for_start()
968968
await asyncio.sleep(0)
969-
aiozc.zeroconf.handle_response(r.DNSIncoming(generated.packets()[0]))
969+
aiozc.zeroconf.record_manager.async_updates_from_response(r.DNSIncoming(generated.packets()[0]))
970970

971971
generated = r.DNSOutgoing(const._FLAGS_QR_RESPONSE)
972972
generated.add_answer_at_time(
@@ -982,7 +982,7 @@ async def test_port_changes_are_seen():
982982
),
983983
0,
984984
)
985-
aiozc.zeroconf.handle_response(r.DNSIncoming(generated.packets()[0]))
985+
aiozc.zeroconf.record_manager.async_updates_from_response(r.DNSIncoming(generated.packets()[0]))
986986

987987
info = ServiceInfo(type_, registration_name, 80, 10, 10, desc, host)
988988
await info.async_request(aiozc.zeroconf, timeout=200)
@@ -1049,7 +1049,7 @@ async def test_port_changes_are_seen_with_directed_request():
10491049
)
10501050
await aiozc.zeroconf.async_wait_for_start()
10511051
await asyncio.sleep(0)
1052-
aiozc.zeroconf.handle_response(r.DNSIncoming(generated.packets()[0]))
1052+
aiozc.zeroconf.record_manager.async_updates_from_response(r.DNSIncoming(generated.packets()[0]))
10531053

10541054
generated = r.DNSOutgoing(const._FLAGS_QR_RESPONSE)
10551055
generated.add_answer_at_time(
@@ -1065,7 +1065,7 @@ async def test_port_changes_are_seen_with_directed_request():
10651065
),
10661066
0,
10671067
)
1068-
aiozc.zeroconf.handle_response(r.DNSIncoming(generated.packets()[0]))
1068+
aiozc.zeroconf.record_manager.async_updates_from_response(r.DNSIncoming(generated.packets()[0]))
10691069

10701070
info = ServiceInfo(type_, registration_name, 80, 10, 10, desc, host)
10711071
await info.async_request(aiozc.zeroconf, timeout=200, addr="127.0.0.1", port=5353)
@@ -1131,7 +1131,7 @@ async def test_ipv4_changes_are_seen():
11311131
)
11321132
await aiozc.zeroconf.async_wait_for_start()
11331133
await asyncio.sleep(0)
1134-
aiozc.zeroconf.handle_response(r.DNSIncoming(generated.packets()[0]))
1134+
aiozc.zeroconf.record_manager.async_updates_from_response(r.DNSIncoming(generated.packets()[0]))
11351135
info = ServiceInfo(type_, registration_name)
11361136
info.load_from_cache(aiozc.zeroconf)
11371137
assert info.addresses_by_version(IPVersion.V4Only) == [b'\x7f\x00\x00\x01']
@@ -1147,7 +1147,7 @@ async def test_ipv4_changes_are_seen():
11471147
),
11481148
0,
11491149
)
1150-
aiozc.zeroconf.handle_response(r.DNSIncoming(generated.packets()[0]))
1150+
aiozc.zeroconf.record_manager.async_updates_from_response(r.DNSIncoming(generated.packets()[0]))
11511151

11521152
info = ServiceInfo(type_, registration_name)
11531153
info.load_from_cache(aiozc.zeroconf)
@@ -1213,7 +1213,7 @@ async def test_ipv6_changes_are_seen():
12131213
)
12141214
await aiozc.zeroconf.async_wait_for_start()
12151215
await asyncio.sleep(0)
1216-
aiozc.zeroconf.handle_response(r.DNSIncoming(generated.packets()[0]))
1216+
aiozc.zeroconf.record_manager.async_updates_from_response(r.DNSIncoming(generated.packets()[0]))
12171217
info = ServiceInfo(type_, registration_name)
12181218
info.load_from_cache(aiozc.zeroconf)
12191219
assert info.addresses_by_version(IPVersion.V6Only) == [
@@ -1231,7 +1231,7 @@ async def test_ipv6_changes_are_seen():
12311231
),
12321232
0,
12331233
)
1234-
aiozc.zeroconf.handle_response(r.DNSIncoming(generated.packets()[0]))
1234+
aiozc.zeroconf.record_manager.async_updates_from_response(r.DNSIncoming(generated.packets()[0]))
12351235

12361236
info = ServiceInfo(type_, registration_name)
12371237
info.load_from_cache(aiozc.zeroconf)
@@ -1295,7 +1295,7 @@ async def test_bad_ip_addresses_ignored_in_cache():
12951295

12961296
await aiozc.zeroconf.async_wait_for_start()
12971297
await asyncio.sleep(0)
1298-
aiozc.zeroconf.handle_response(r.DNSIncoming(generated.packets()[0]))
1298+
aiozc.zeroconf.record_manager.async_updates_from_response(r.DNSIncoming(generated.packets()[0]))
12991299
info = ServiceInfo(type_, registration_name)
13001300
info.load_from_cache(aiozc.zeroconf)
13011301
assert info.addresses_by_version(IPVersion.V4Only) == [b'\x7f\x00\x00\x01']
@@ -1354,7 +1354,7 @@ async def test_service_name_change_as_seen_has_ip_in_cache():
13541354
)
13551355
await aiozc.zeroconf.async_wait_for_start()
13561356
await asyncio.sleep(0)
1357-
aiozc.zeroconf.handle_response(r.DNSIncoming(generated.packets()[0]))
1357+
aiozc.zeroconf.record_manager.async_updates_from_response(r.DNSIncoming(generated.packets()[0]))
13581358

13591359
info = ServiceInfo(type_, registration_name)
13601360
await info.async_request(aiozc.zeroconf, timeout=200)
@@ -1374,7 +1374,7 @@ async def test_service_name_change_as_seen_has_ip_in_cache():
13741374
),
13751375
0,
13761376
)
1377-
aiozc.zeroconf.handle_response(r.DNSIncoming(generated.packets()[0]))
1377+
aiozc.zeroconf.record_manager.async_updates_from_response(r.DNSIncoming(generated.packets()[0]))
13781378

13791379
info = ServiceInfo(type_, registration_name)
13801380
await info.async_request(aiozc.zeroconf, timeout=200)
@@ -1426,7 +1426,7 @@ async def test_service_name_change_as_seen_ip_not_in_cache():
14261426
)
14271427
await aiozc.zeroconf.async_wait_for_start()
14281428
await asyncio.sleep(0)
1429-
aiozc.zeroconf.handle_response(r.DNSIncoming(generated.packets()[0]))
1429+
aiozc.zeroconf.record_manager.async_updates_from_response(r.DNSIncoming(generated.packets()[0]))
14301430

14311431
info = ServiceInfo(type_, registration_name)
14321432
await info.async_request(aiozc.zeroconf, timeout=200)
@@ -1456,7 +1456,7 @@ async def test_service_name_change_as_seen_ip_not_in_cache():
14561456
),
14571457
0,
14581458
)
1459-
aiozc.zeroconf.handle_response(r.DNSIncoming(generated.packets()[0]))
1459+
aiozc.zeroconf.record_manager.async_updates_from_response(r.DNSIncoming(generated.packets()[0]))
14601460

14611461
info = ServiceInfo(type_, registration_name)
14621462
await info.async_request(aiozc.zeroconf, timeout=200)
@@ -1530,7 +1530,7 @@ async def test_release_wait_when_new_recorded_added_concurrency():
15301530
await asyncio.sleep(0)
15311531
for task in tasks:
15321532
assert not task.done()
1533-
aiozc.zeroconf.handle_response(r.DNSIncoming(generated.packets()[0]))
1533+
aiozc.zeroconf.record_manager.async_updates_from_response(r.DNSIncoming(generated.packets()[0]))
15341534
_, pending = await asyncio.wait(tasks, timeout=2)
15351535
assert not pending
15361536
assert info.addresses == [b'\x7f\x00\x00\x01']

tests/test_asyncio.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,6 +1192,7 @@ def update_service(self, zc, type_, name) -> None: # type: ignore[no-untyped-de
11921192
0,
11931193
)
11941194

1195+
zc.record_manager.async_updates_from_response(DNSIncoming(generated.packets()[0]))
11951196
zc.handle_response(DNSIncoming(generated.packets()[0]))
11961197

11971198
await browser.async_cancel()

tests/test_core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def test_launch_and_close_apple_p2p_on_mac(self):
105105
rv = r.Zeroconf(apple_p2p=True)
106106
rv.close()
107107

108-
def test_handle_response(self):
108+
def test_async_updates_from_response(self):
109109
def mock_incoming_msg(service_state_change: r.ServiceStateChange) -> r.DNSIncoming:
110110
ttl = 120
111111
generated = r.DNSOutgoing(const._FLAGS_QR_RESPONSE)

tests/test_handlers.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,7 +1423,7 @@ async def test_response_aggregation_timings(run_isolated):
14231423
assert len(calls) == 1
14241424
outgoing = send_mock.call_args[0][0]
14251425
incoming = r.DNSIncoming(outgoing.packets()[0])
1426-
zc.handle_response(incoming)
1426+
zc.record_manager.async_updates_from_response(incoming)
14271427
assert info.dns_pointer() in incoming.answers
14281428
assert info2.dns_pointer() in incoming.answers
14291429
send_mock.reset_mock()
@@ -1437,7 +1437,7 @@ async def test_response_aggregation_timings(run_isolated):
14371437
assert len(calls) == 1
14381438
outgoing = send_mock.call_args[0][0]
14391439
incoming = r.DNSIncoming(outgoing.packets()[0])
1440-
zc.handle_response(incoming)
1440+
zc.record_manager.async_updates_from_response(incoming)
14411441
assert info3.dns_pointer() in incoming.answers
14421442
send_mock.reset_mock()
14431443

@@ -1499,7 +1499,7 @@ async def test_response_aggregation_timings_multiple(run_isolated, disable_dupli
14991499
assert len(calls) == 1
15001500
outgoing = send_mock.call_args[0][0]
15011501
incoming = r.DNSIncoming(outgoing.packets()[0])
1502-
zc.handle_response(incoming)
1502+
zc.record_manager.async_updates_from_response(incoming)
15031503
assert info2.dns_pointer() in incoming.answers
15041504

15051505
send_mock.reset_mock()
@@ -1509,7 +1509,7 @@ async def test_response_aggregation_timings_multiple(run_isolated, disable_dupli
15091509
assert len(calls) == 1
15101510
outgoing = send_mock.call_args[0][0]
15111511
incoming = r.DNSIncoming(outgoing.packets()[0])
1512-
zc.handle_response(incoming)
1512+
zc.record_manager.async_updates_from_response(incoming)
15131513
assert info2.dns_pointer() in incoming.answers
15141514

15151515
send_mock.reset_mock()
@@ -1532,7 +1532,7 @@ async def test_response_aggregation_timings_multiple(run_isolated, disable_dupli
15321532
assert len(calls) == 1
15331533
outgoing = send_mock.call_args[0][0]
15341534
incoming = r.DNSIncoming(outgoing.packets()[0])
1535-
zc.handle_response(incoming)
1535+
zc.record_manager.async_updates_from_response(incoming)
15361536
assert info2.dns_pointer() in incoming.answers
15371537

15381538

0 commit comments

Comments
 (0)