Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit e80fcef

Browse filesBrowse files
authored
feat: optimize the dns cache (#1119)
1 parent f57d9f1 commit e80fcef
Copy full SHA for e80fcef

File tree

6 files changed

+76
-30
lines changed
Filter options

6 files changed

+76
-30
lines changed

‎build_ext.py

Copy file name to clipboardExpand all lines: build_ext.py
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def build(setup_kwargs: Any) -> None:
2323
dict(
2424
ext_modules=cythonize(
2525
[
26+
"src/zeroconf/_cache.py",
2627
"src/zeroconf/_dns.py",
2728
"src/zeroconf/_protocol/incoming.py",
2829
"src/zeroconf/_protocol/outgoing.py",

‎src/zeroconf/_cache.pxd

Copy file name to clipboard
+28Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import cython
2+
from ._dns cimport (
3+
DNSAddress,
4+
DNSEntry,
5+
DNSHinfo,
6+
DNSPointer,
7+
DNSRecord,
8+
DNSService,
9+
DNSText,
10+
)
11+
12+
13+
cdef object _TYPE_PTR
14+
15+
cdef _remove_key(cython.dict cache, object key, DNSRecord record)
16+
17+
18+
cdef class DNSCache:
19+
20+
cdef public cython.dict cache
21+
cdef public cython.dict service_cache
22+
23+
cdef _async_add(self, DNSRecord record)
24+
25+
cdef _async_remove(self, DNSRecord record)
26+
27+
28+
cdef _dns_record_matches(DNSRecord record, object key, object type_, object class_)

‎src/zeroconf/_cache.py

Copy file name to clipboardExpand all lines: src/zeroconf/_cache.py
+25-17Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,23 @@
3232
DNSRecord,
3333
DNSService,
3434
DNSText,
35-
dns_entry_matches,
3635
)
3736
from ._utils.time import current_time_millis
3837
from .const import _TYPE_PTR
3938

4039
_UNIQUE_RECORD_TYPES = (DNSAddress, DNSHinfo, DNSPointer, DNSText, DNSService)
4140
_UniqueRecordsType = Union[DNSAddress, DNSHinfo, DNSPointer, DNSText, DNSService]
4241
_DNSRecordCacheType = Dict[str, Dict[DNSRecord, DNSRecord]]
42+
_DNSRecord = DNSRecord
43+
_str = str
4344

4445

45-
def _remove_key(cache: _DNSRecordCacheType, key: str, entry: DNSRecord) -> None:
46+
def _remove_key(cache: _DNSRecordCacheType, key: _str, record: _DNSRecord) -> None:
4647
"""Remove a key from a DNSRecord cache
4748
4849
This function must be run in from event loop.
4950
"""
50-
del cache[key][entry]
51+
del cache[key][record]
5152
if not cache[key]:
5253
del cache[key]
5354

@@ -62,7 +63,7 @@ def __init__(self) -> None:
6263
# Functions prefixed with async_ are NOT threadsafe and must
6364
# be run in the event loop.
6465

65-
def _async_add(self, entry: DNSRecord) -> bool:
66+
def _async_add(self, record: _DNSRecord) -> bool:
6667
"""Adds an entry.
6768
6869
Returns true if the entry was not already in the cache.
@@ -75,11 +76,11 @@ def _async_add(self, entry: DNSRecord) -> bool:
7576
# replaces any existing records that are __eq__ to each other which
7677
# removes the risk that accessing the cache from the wrong
7778
# direction would return the old incorrect entry.
78-
store = self.cache.setdefault(entry.key, {})
79-
new = entry not in store and not isinstance(entry, DNSNsec)
80-
store[entry] = entry
81-
if isinstance(entry, DNSService):
82-
self.service_cache.setdefault(entry.server_key, {})[entry] = entry
79+
store = self.cache.setdefault(record.key, {})
80+
new = record not in store and not isinstance(record, DNSNsec)
81+
store[record] = record
82+
if isinstance(record, DNSService):
83+
self.service_cache.setdefault(record.server_key, {})[record] = record
8384
return new
8485

8586
def async_add_records(self, entries: Iterable[DNSRecord]) -> bool:
@@ -95,14 +96,14 @@ def async_add_records(self, entries: Iterable[DNSRecord]) -> bool:
9596
new = True
9697
return new
9798

98-
def _async_remove(self, entry: DNSRecord) -> None:
99+
def _async_remove(self, record: _DNSRecord) -> None:
99100
"""Removes an entry.
100101
101102
This function must be run in from event loop.
102103
"""
103-
if isinstance(entry, DNSService):
104-
_remove_key(self.service_cache, entry.server_key, entry)
105-
_remove_key(self.cache, entry.key, entry)
104+
if isinstance(record, DNSService):
105+
_remove_key(self.service_cache, record.server_key, record)
106+
_remove_key(self.cache, record.key, record)
106107

107108
def async_remove_records(self, entries: Iterable[DNSRecord]) -> None:
108109
"""Remove multiple records.
@@ -128,7 +129,10 @@ def async_get_unique(self, entry: _UniqueRecordsType) -> Optional[DNSRecord]:
128129
This function is not threadsafe and must be called from
129130
the event loop.
130131
"""
131-
return self.cache.get(entry.key, {}).get(entry)
132+
store = self.cache.get(entry.key)
133+
if store is None:
134+
return None
135+
return store.get(entry)
132136

133137
def async_all_by_details(self, name: str, type_: int, class_: int) -> Iterator[DNSRecord]:
134138
"""Gets all matching entries by details.
@@ -138,7 +142,7 @@ def async_all_by_details(self, name: str, type_: int, class_: int) -> Iterator[D
138142
"""
139143
key = name.lower()
140144
for entry in self.cache.get(key, []):
141-
if dns_entry_matches(entry, key, type_, class_):
145+
if _dns_record_matches(entry, key, type_, class_):
142146
yield entry
143147

144148
def async_entries_with_name(self, name: str) -> Dict[DNSRecord, DNSRecord]:
@@ -185,15 +189,15 @@ def get_by_details(self, name: str, type_: int, class_: int) -> Optional[DNSReco
185189
"""
186190
key = name.lower()
187191
for cached_entry in reversed(list(self.cache.get(key, []))):
188-
if dns_entry_matches(cached_entry, key, type_, class_):
192+
if _dns_record_matches(cached_entry, key, type_, class_):
189193
return cached_entry
190194
return None
191195

192196
def get_all_by_details(self, name: str, type_: int, class_: int) -> List[DNSRecord]:
193197
"""Gets all matching entries by details."""
194198
key = name.lower()
195199
return [
196-
entry for entry in list(self.cache.get(key, [])) if dns_entry_matches(entry, key, type_, class_)
200+
entry for entry in list(self.cache.get(key, [])) if _dns_record_matches(entry, key, type_, class_)
197201
]
198202

199203
def entries_with_server(self, server: str) -> List[DNSRecord]:
@@ -218,3 +222,7 @@ def current_entry_with_name_and_alias(self, name: str, alias: str) -> Optional[D
218222
def names(self) -> List[str]:
219223
"""Return a copy of the list of current cache names."""
220224
return list(self.cache)
225+
226+
227+
def _dns_record_matches(record: _DNSRecord, key: _str, type_: int, class_: int) -> bool:
228+
return key == record.key and type_ == record.type and class_ == record.class_

‎src/zeroconf/_dns.pxd

Copy file name to clipboardExpand all lines: src/zeroconf/_dns.pxd
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,5 @@ cdef class DNSRRSet:
7474

7575
cdef _records
7676
cdef _lookup
77+
78+
cdef _dns_entry_matches(DNSEntry entry, object key, object type_, object class_)

‎src/zeroconf/_dns.py

Copy file name to clipboardExpand all lines: src/zeroconf/_dns.py
+16-12Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,6 @@ class DNSQuestionType(enum.Enum):
5959
QM = 2
6060

6161

62-
def dns_entry_matches(record: 'DNSEntry', key: str, type_: int, class_: int) -> bool:
63-
return key == record.key and type_ == record.type and class_ == record.class_
64-
65-
6662
class DNSEntry:
6763

6864
"""A DNS entry"""
@@ -78,7 +74,7 @@ def __init__(self, name: str, type_: int, class_: int) -> None:
7874

7975
def __eq__(self, other: Any) -> bool:
8076
"""Equality test on key (lowercase name), type, and class"""
81-
return dns_entry_matches(other, self.key, self.type, self.class_) and isinstance(other, DNSEntry)
77+
return _dns_entry_matches(other, self.key, self.type, self.class_) and isinstance(other, DNSEntry)
8278

8379
@staticmethod
8480
def get_class_(class_: int) -> str:
@@ -121,7 +117,7 @@ def __hash__(self) -> int:
121117

122118
def __eq__(self, other: Any) -> bool:
123119
"""Tests equality on dns question."""
124-
return isinstance(other, DNSQuestion) and dns_entry_matches(other, self.key, self.type, self.class_)
120+
return isinstance(other, DNSQuestion) and _dns_entry_matches(other, self.key, self.type, self.class_)
125121

126122
@property
127123
def max_size(self) -> int:
@@ -254,7 +250,7 @@ def __eq__(self, other: Any) -> bool:
254250
isinstance(other, DNSAddress)
255251
and self.address == other.address
256252
and self.scope_id == other.scope_id
257-
and dns_entry_matches(other, self.key, self.type, self.class_)
253+
and _dns_entry_matches(other, self.key, self.type, self.class_)
258254
)
259255

260256
def __hash__(self) -> int:
@@ -298,7 +294,7 @@ def __eq__(self, other: Any) -> bool:
298294
isinstance(other, DNSHinfo)
299295
and self.cpu == other.cpu
300296
and self.os == other.os
301-
and dns_entry_matches(other, self.key, self.type, self.class_)
297+
and _dns_entry_matches(other, self.key, self.type, self.class_)
302298
)
303299

304300
def __hash__(self) -> int:
@@ -342,7 +338,7 @@ def __eq__(self, other: Any) -> bool:
342338
return (
343339
isinstance(other, DNSPointer)
344340
and self.alias == other.alias
345-
and dns_entry_matches(other, self.key, self.type, self.class_)
341+
and _dns_entry_matches(other, self.key, self.type, self.class_)
346342
)
347343

348344
def __hash__(self) -> int:
@@ -381,7 +377,7 @@ def __eq__(self, other: Any) -> bool:
381377
return (
382378
isinstance(other, DNSText)
383379
and self.text == other.text
384-
and dns_entry_matches(other, self.key, self.type, self.class_)
380+
and _dns_entry_matches(other, self.key, self.type, self.class_)
385381
)
386382

387383
def __repr__(self) -> str:
@@ -432,7 +428,7 @@ def __eq__(self, other: Any) -> bool:
432428
and self.weight == other.weight
433429
and self.port == other.port
434430
and self.server == other.server
435-
and dns_entry_matches(other, self.key, self.type, self.class_)
431+
and _dns_entry_matches(other, self.key, self.type, self.class_)
436432
)
437433

438434
def __hash__(self) -> int:
@@ -487,7 +483,7 @@ def __eq__(self, other: Any) -> bool:
487483
isinstance(other, DNSNsec)
488484
and self.next_name == other.next_name
489485
and self.rdtypes == other.rdtypes
490-
and dns_entry_matches(other, self.key, self.type, self.class_)
486+
and _dns_entry_matches(other, self.key, self.type, self.class_)
491487
)
492488

493489
def __hash__(self) -> int:
@@ -527,3 +523,11 @@ def suppresses(self, record: DNSRecord) -> bool:
527523
def __contains__(self, record: DNSRecord) -> bool:
528524
"""Returns true if the rrset contains the record."""
529525
return record in self.lookup
526+
527+
528+
_DNSEntry = DNSEntry
529+
_str = str
530+
531+
532+
def _dns_entry_matches(entry: _DNSEntry, key: _str, type_: int, class_: int) -> bool:
533+
return key == entry.key and type_ == entry.type and class_ == entry.class_

‎src/zeroconf/_protocol/incoming.py

Copy file name to clipboardExpand all lines: src/zeroconf/_protocol/incoming.py
+4-1Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
UNPACK_HHiH = struct.Struct(b'!HHiH').unpack_from
6767

6868
_seen_logs: Dict[str, Union[int, tuple]] = {}
69+
_str = str
6970

7071

7172
class DNSIncoming:
@@ -250,7 +251,9 @@ def _read_others(self) -> None:
250251
if rec is not None:
251252
self._answers.append(rec)
252253

253-
def _read_record(self, domain, type_: int, class_: int, ttl: int, length: int) -> Optional[DNSRecord]: # type: ignore[no-untyped-def]
254+
def _read_record(
255+
self, domain: _str, type_: int, class_: int, ttl: int, length: int
256+
) -> Optional[DNSRecord]:
254257
"""Read known records types and skip unknown ones."""
255258
if type_ == _TYPE_A:
256259
return DNSAddress(domain, type_, class_, ttl, self._read_string(4), created=self.now)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.