Skip to content

Commit d192d33

Browse files
authored
feat: speed up service browser queries when browsing many types (#1311)
1 parent e60cc41 commit d192d33

3 files changed

Lines changed: 27 additions & 18 deletions

File tree

src/zeroconf/_services/browser.pxd

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

44
from .._cache cimport DNSCache
5+
from .._history cimport QuestionHistory
56
from .._protocol.outgoing cimport DNSOutgoing, DNSPointer, DNSQuestion, DNSRecord
67
from .._record_update cimport RecordUpdate
78
from .._updates cimport RecordUpdateListener
@@ -11,7 +12,7 @@ from . cimport Signal, SignalRegistrationInterface
1112

1213
cdef bint TYPE_CHECKING
1314
cdef object cached_possible_types
14-
cdef cython.uint _EXPIRE_REFRESH_TIME_PERCENT
15+
cdef cython.uint _EXPIRE_REFRESH_TIME_PERCENT, _MAX_MSG_TYPICAL, _DNS_PACKET_HEADER_LEN
1516
cdef cython.uint _TYPE_PTR
1617
cdef object SERVICE_STATE_CHANGE_ADDED, SERVICE_STATE_CHANGE_REMOVED, SERVICE_STATE_CHANGE_UPDATED
1718
cdef cython.set _ADDRESS_RECORD_TYPES
@@ -24,8 +25,16 @@ cdef class _DNSPointerOutgoingBucket:
2425

2526
cpdef add(self, cython.uint max_compressed_size, DNSQuestion question, cython.set answers)
2627

28+
@cython.locals(cache=DNSCache, question_history=QuestionHistory, record=DNSRecord)
29+
cpdef generate_service_query(
30+
object zc,
31+
float now,
32+
list type_,
33+
bint multicast,
34+
object question_type
35+
)
2736

28-
@cython.locals(answer=DNSPointer)
37+
@cython.locals(answer=DNSPointer, query_buckets=list, question=DNSQuestion, max_compressed_size=cython.uint, max_bucket_size=cython.uint, query_bucket=_DNSPointerOutgoingBucket)
2938
cdef _group_ptr_queries_with_known_answers(object now, object multicast, cython.dict question_with_known_answers)
3039

3140
cdef class QueryScheduler:

src/zeroconf/_services/browser.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -164,33 +164,31 @@ def _group_ptr_queries_with_known_answers(
164164

165165

166166
def generate_service_query(
167-
zc: 'Zeroconf',
168-
now: float,
169-
types_: List[str],
170-
multicast: bool = True,
171-
question_type: Optional[DNSQuestionType] = None,
167+
zc: 'Zeroconf', now: float_, types_: List[str], multicast: bool, question_type: Optional[DNSQuestionType]
172168
) -> List[DNSOutgoing]:
173169
"""Generate a service query for sending with zeroconf.send."""
174170
questions_with_known_answers: _QuestionWithKnownAnswers = {}
175171
qu_question = not multicast if question_type is None else question_type == DNSQuestionType.QU
172+
question_history = zc.question_history
173+
cache = zc.cache
176174
for type_ in types_:
177175
question = DNSQuestion(type_, _TYPE_PTR, _CLASS_IN)
178176
question.unicast = qu_question
179177
known_answers = {
180178
record
181-
for record in zc.cache.get_all_by_details(type_, _TYPE_PTR, _CLASS_IN)
182-
if not record.is_stale(now)
179+
for record in cache.get_all_by_details(type_, _TYPE_PTR, _CLASS_IN)
180+
if record.is_stale(now) is False
183181
}
184-
if not qu_question and zc.question_history.suppresses(question, now, known_answers):
182+
if not qu_question and question_history.suppresses(question, now, known_answers):
185183
log.debug("Asking %s was suppressed by the question history", question)
186184
continue
187185
if TYPE_CHECKING:
188186
pointer_known_answers = cast(Set[DNSPointer], known_answers)
189187
else:
190188
pointer_known_answers = known_answers
191189
questions_with_known_answers[question] = pointer_known_answers
192-
if not qu_question:
193-
zc.question_history.add_question_at_time(question, now, known_answers)
190+
if qu_question is False:
191+
question_history.add_question_at_time(question, now, known_answers)
194192

195193
return _group_ptr_queries_with_known_answers(now, multicast, questions_with_known_answers)
196194

tests/services/test_browser.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,32 +1010,34 @@ async def test_generate_service_query_suppress_duplicate_questions():
10101010
assert zc.question_history.suppresses(question, now, other_known_answers)
10111011

10121012
# The known answer list is different, do not suppress
1013-
outs = _services_browser.generate_service_query(zc, now, [name], multicast=True)
1013+
outs = _services_browser.generate_service_query(zc, now, [name], multicast=True, question_type=None)
10141014
assert outs
10151015

10161016
zc.cache.async_add_records([answer])
10171017
# The known answer list contains all the asked questions in the history
10181018
# we should suppress
10191019

1020-
outs = _services_browser.generate_service_query(zc, now, [name], multicast=True)
1020+
outs = _services_browser.generate_service_query(zc, now, [name], multicast=True, question_type=None)
10211021
assert not outs
10221022

10231023
# We do not suppress once the question history expires
1024-
outs = _services_browser.generate_service_query(zc, now + 1000, [name], multicast=True)
1024+
outs = _services_browser.generate_service_query(
1025+
zc, now + 1000, [name], multicast=True, question_type=None
1026+
)
10251027
assert outs
10261028

10271029
# We do not suppress QU queries ever
1028-
outs = _services_browser.generate_service_query(zc, now, [name], multicast=False)
1030+
outs = _services_browser.generate_service_query(zc, now, [name], multicast=False, question_type=None)
10291031
assert outs
10301032

10311033
zc.question_history.async_expire(now + 2000)
10321034
# No suppression after clearing the history
1033-
outs = _services_browser.generate_service_query(zc, now, [name], multicast=True)
1035+
outs = _services_browser.generate_service_query(zc, now, [name], multicast=True, question_type=None)
10341036
assert outs
10351037

10361038
# The previous query we just sent is still remembered and
10371039
# the next one is suppressed
1038-
outs = _services_browser.generate_service_query(zc, now, [name], multicast=True)
1040+
outs = _services_browser.generate_service_query(zc, now, [name], multicast=True, question_type=None)
10391041
assert not outs
10401042

10411043
await aiozc.async_close()

0 commit comments

Comments
 (0)