Skip to content

Commit a200842

Browse files
authored
feat: speed up unpacking TXT record data in ServiceInfo (#1318)
1 parent 72fed78 commit a200842

3 files changed

Lines changed: 33 additions & 11 deletions

File tree

bench/txt_properties.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import timeit
2+
3+
from zeroconf import ServiceInfo
4+
5+
info = ServiceInfo(
6+
"_test._tcp.local.",
7+
"test._test._tcp.local.",
8+
properties=(
9+
b"\x19md=AlexanderHomeAssistant\x06pv=1.0\x14id=59:8A:0B:74:65:1D\x05"
10+
b"c#=14\x04s#=1\x04ff=0\x04ci=2\x04sf=0\x0bsh=ccZLPA=="
11+
),
12+
)
13+
14+
15+
def process_properties() -> None:
16+
info._properties = None
17+
info.properties
18+
19+
20+
count = 100000
21+
time = timeit.Timer(process_properties).timeit(count)
22+
print(f"Processing {count} properties took {time} seconds")

src/zeroconf/_services/info.pxd

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ cdef class ServiceInfo(RecordUpdateListener):
6363
@cython.locals(cache=DNSCache)
6464
cpdef bint _load_from_cache(self, object zc, cython.float now)
6565

66-
cdef _unpack_text_into_properties(self)
66+
@cython.locals(length="unsigned char", index="unsigned int", key_value=bytes, key_sep_value=tuple)
67+
cdef void _unpack_text_into_properties(self)
6768

6869
cdef _set_properties(self, cython.dict properties)
6970

src/zeroconf/_services/info.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -388,27 +388,26 @@ def _set_text(self, text: bytes) -> None:
388388
def _unpack_text_into_properties(self) -> None:
389389
"""Unpacks the text field into properties"""
390390
text = self.text
391-
if not text:
391+
end = len(text)
392+
if end == 0:
392393
# Properties should be set atomically
393394
# in case another thread is reading them
394395
self._properties = {}
395396
return
396397

397398
index = 0
398-
pairs: List[bytes] = []
399-
end = len(text)
399+
properties: Dict[Union[str, bytes], Optional[Union[str, bytes]]] = {}
400400
while index < end:
401401
length = text[index]
402402
index += 1
403-
pairs.append(text[index : index + length])
403+
key_value = text[index : index + length]
404+
key_sep_value = key_value.partition(b'=')
405+
key = key_sep_value[0]
406+
if key not in properties:
407+
properties[key] = key_sep_value[2] or None
404408
index += length
405409

406-
# Reverse the list so that the first item in the list
407-
# is the last item in the text field. This is important
408-
# to preserve backwards compatibility where the first
409-
# key always wins if the key is seen multiple times.
410-
pairs.reverse()
411-
self._properties = {key: value or None for key, _, value in (pair.partition(b'=') for pair in pairs)}
410+
self._properties = properties
412411

413412
def get_name(self) -> str:
414413
"""Name accessor"""

0 commit comments

Comments
 (0)