Skip to content

Commit

Permalink
Improve performance of query scheduler (#1043)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdraco authored Dec 24, 2021
1 parent 95ee5dc commit 27e50ff
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 17 deletions.
2 changes: 1 addition & 1 deletion tests/test_asyncio.py
Original file line number Diff line number Diff line change
Expand Up @@ -923,7 +923,7 @@ def send(out, addr=const._MDNS_ADDR, port=const._MDNS_PORT, v6_flow_scope=()):
# Increase simulated time shift by 1/4 of the TTL in seconds
time_offset += expected_ttl / 4
now = _new_current_time_millis()
browser.reschedule_type(type_, now)
browser.reschedule_type(type_, now, now)
sleep_count += 1
await asyncio.wait_for(got_query.wait(), 1)
got_query.clear()
Expand Down
2 changes: 1 addition & 1 deletion zeroconf/_handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ def _answer_question(
self._add_address_answers(question.name, answer_set, known_answers, now, type_)

if type_ in (_TYPE_SRV, _TYPE_TXT, _TYPE_ANY):
service = self.registry.async_get_info_name(question.name) # type: ignore
service = self.registry.async_get_info_name(question.name)
if service is not None:
if type_ in (_TYPE_SRV, _TYPE_ANY):
# Add recommended additional answers according to
Expand Down
29 changes: 14 additions & 15 deletions zeroconf/_services/browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ def _async_process_record_update(
elif record.is_expired(now):
self._enqueue_callback(ServiceStateChange.Removed, type_, name)
else:
self.reschedule_type(type_, record.get_expiration_time(_EXPIRE_REFRESH_TIME_PERCENT))
self.reschedule_type(type_, now, record.get_expiration_time(_EXPIRE_REFRESH_TIME_PERCENT))
return

# If its expired or already exists in the cache it cannot be updated.
Expand Down Expand Up @@ -431,9 +431,8 @@ def _async_cancel(self) -> None:
self._cancel_send_timer()
self.zc.async_remove_listener(self)

def _generate_ready_queries(self, first_request: bool) -> List[DNSOutgoing]:
def _generate_ready_queries(self, first_request: bool, now: float) -> List[DNSOutgoing]:
"""Generate the service browser query for any type that is due."""
now = current_time_millis()
ready_types = self.query_scheduler.process_ready_types(now)
if not ready_types:
return []
Expand All @@ -448,40 +447,40 @@ def _generate_ready_queries(self, first_request: bool) -> List[DNSOutgoing]:
async def _async_start_query_sender(self) -> None:
"""Start scheduling queries."""
await self.zc.async_wait_for_start()
self._async_send_ready_queries()
self._async_schedule_next()
self._async_send_ready_queries_schedule_next()

def _cancel_send_timer(self) -> None:
"""Cancel the next send."""
if self._next_send_timer:
self._next_send_timer.cancel()

def reschedule_type(self, type_: str, next_time: float) -> None:
def reschedule_type(self, type_: str, now: float, next_time: float) -> None:
"""Reschedule a type to be refreshed in the future."""
if self.query_scheduler.reschedule_type(type_, next_time):
self._cancel_send_timer()
self._async_schedule_next()
self._async_send_ready_queries()
self._async_schedule_next(now)
self._async_send_ready_queries(now)

def _async_send_ready_queries(self) -> None:
def _async_send_ready_queries(self, now: float) -> None:
"""Send any ready queries."""
outs = self._generate_ready_queries(self._first_request)
outs = self._generate_ready_queries(self._first_request, now)
if outs:
self._first_request = False
for out in outs:
self.zc.async_send(out, addr=self.addr, port=self.port)

def _async_send_ready_queries_schedule_next(self) -> None:
"""Send ready queries and schedule next one."""
"""Send ready queries and schedule next one checking for done first."""
if self.done or self.zc.done:
return
self._async_send_ready_queries()
self._async_schedule_next()
now = current_time_millis()
self._async_send_ready_queries(now)
self._async_schedule_next(now)

def _async_schedule_next(self) -> None:
def _async_schedule_next(self, now: float) -> None:
"""Scheule the next time."""
assert self.zc.loop is not None
delay = millis_to_seconds(self.query_scheduler.millis_to_wait(current_time_millis()))
delay = millis_to_seconds(self.query_scheduler.millis_to_wait(now))
self._next_send_timer = self.zc.loop.call_later(delay, self._async_send_ready_queries_schedule_next)


Expand Down

0 comments on commit 27e50ff

Please sign in to comment.