feat: significantly speed up writing outgoing dns records (#1260) · python-zeroconf/python-zeroconf@bf2f366

@@ -22,6 +22,7 @@

22222323

import enum

2424

import logging

25+

from struct import Struct

2526

from typing import TYPE_CHECKING, Dict, List, Optional, Sequence, Tuple, Union

26272728

from .._cache import DNSCache

@@ -43,10 +44,16 @@

4344

str_ = str

4445

float_ = float

4546

int_ = int

47+

bytes_ = bytes

4648

DNSQuestion_ = DNSQuestion

4749

DNSRecord_ = DNSRecord

4850495152+

PACK_BYTE = Struct('>B').pack

53+

PACK_SHORT = Struct('>H').pack

54+

PACK_LONG = Struct('>L').pack

55+56+5057

class State(enum.Enum):

5158

init = 0

5259

finished = 1

@@ -200,35 +207,35 @@ def add_question_or_all_cache(

200207201208

def _write_byte(self, value: int_) -> None:

202209

"""Writes a single byte to the packet"""

203-

self.data.append(value.to_bytes(1, 'big'))

210+

self.data.append(PACK_BYTE(value))

204211

self.size += 1

205212206213

def _insert_short_at_start(self, value: int_) -> None:

207214

"""Inserts an unsigned short at the start of the packet"""

208-

self.data.insert(0, value.to_bytes(2, 'big'))

215+

self.data.insert(0, PACK_SHORT(value))

209216210217

def _replace_short(self, index: int_, value: int_) -> None:

211218

"""Replaces an unsigned short in a certain position in the packet"""

212-

self.data[index] = value.to_bytes(2, 'big')

219+

self.data[index] = PACK_SHORT(value)

213220214221

def write_short(self, value: int_) -> None:

215222

"""Writes an unsigned short to the packet"""

216-

self.data.append(value.to_bytes(2, 'big'))

223+

self.data.append(PACK_SHORT(value))

217224

self.size += 2

218225219226

def _write_int(self, value: Union[float, int]) -> None:

220227

"""Writes an unsigned integer to the packet"""

221-

self.data.append(int(value).to_bytes(4, 'big'))

228+

self.data.append(PACK_LONG(int(value)))

222229

self.size += 4

223230224-

def write_string(self, value: bytes) -> None:

231+

def write_string(self, value: bytes_) -> None:

225232

"""Writes a string to the packet"""

226233

if TYPE_CHECKING:

227234

assert isinstance(value, bytes)

228235

self.data.append(value)

229236

self.size += len(value)

230237231-

def _write_utf(self, s: str) -> None:

238+

def _write_utf(self, s: str_) -> None:

232239

"""Writes a UTF-8 string of a given length to the packet"""

233240

utfstr = s.encode('utf-8')

234241

length = len(utfstr)

@@ -446,7 +453,8 @@ def _packets(self) -> List[bytes]:

446453

questions_offset, answer_offset, authority_offset, additional_offset

447454

):

448455

# https://datatracker.ietf.org/doc/html/rfc6762#section-7.2

449-

log.debug("Setting TC flag")

456+

if debug_enable: # pragma: no branch

457+

log.debug("Setting TC flag")

450458

self._insert_short_at_start(self.flags | _FLAGS_TC)

451459

else:

452460

self._insert_short_at_start(self.flags)

@@ -459,9 +467,13 @@ def _packets(self) -> List[bytes]:

459467

self.packets_data.append(b''.join(self.data))

460468

self._reset_for_next_packet()

461469462-

if (questions_written + answers_written + authorities_written + additionals_written) == 0 and (

463-

len(self.questions) + len(self.answers) + len(self.authorities) + len(self.additionals)

464-

) > 0:

470+

if (

471+

not questions_written

472+

and not answers_written

473+

and not authorities_written

474+

and not additionals_written

475+

and (self.questions or self.answers or self.authorities or self.additionals)

476+

):

465477

log.warning("packets() made no progress adding records; returning")

466478

break

467479

self.state = State.finished