Small tweaks to improve performance of bluetooth matching (#77934)

* Small tweaks to improve performance of bluetooth matching

* Small tweaks to improve performance of bluetooth matching

* cleanup
This commit is contained in:
J. Nick Koston 2022-09-06 18:12:32 -05:00 committed by GitHub
parent 9ba1bb7c73
commit dfef6c3d28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -180,12 +180,20 @@ class BluetoothMatcherIndexBase(Generic[_T]):
We put them in the bucket that they are most likely to match. We put them in the bucket that they are most likely to match.
""" """
# Local name is the cheapest to match since its just a dict lookup
if LOCAL_NAME in matcher: if LOCAL_NAME in matcher:
self.local_name.setdefault( self.local_name.setdefault(
_local_name_to_index_key(matcher[LOCAL_NAME]), [] _local_name_to_index_key(matcher[LOCAL_NAME]), []
).append(matcher) ).append(matcher)
return return
# Manufacturer data is 2nd cheapest since its all ints
if MANUFACTURER_ID in matcher:
self.manufacturer_id.setdefault(matcher[MANUFACTURER_ID], []).append(
matcher
)
return
if SERVICE_UUID in matcher: if SERVICE_UUID in matcher:
self.service_uuid.setdefault(matcher[SERVICE_UUID], []).append(matcher) self.service_uuid.setdefault(matcher[SERVICE_UUID], []).append(matcher)
return return
@ -196,12 +204,6 @@ class BluetoothMatcherIndexBase(Generic[_T]):
) )
return return
if MANUFACTURER_ID in matcher:
self.manufacturer_id.setdefault(matcher[MANUFACTURER_ID], []).append(
matcher
)
return
def remove(self, matcher: _T) -> None: def remove(self, matcher: _T) -> None:
"""Remove a matcher from the index. """Remove a matcher from the index.
@ -214,6 +216,10 @@ class BluetoothMatcherIndexBase(Generic[_T]):
) )
return return
if MANUFACTURER_ID in matcher:
self.manufacturer_id[matcher[MANUFACTURER_ID]].remove(matcher)
return
if SERVICE_UUID in matcher: if SERVICE_UUID in matcher:
self.service_uuid[matcher[SERVICE_UUID]].remove(matcher) self.service_uuid[matcher[SERVICE_UUID]].remove(matcher)
return return
@ -222,10 +228,6 @@ class BluetoothMatcherIndexBase(Generic[_T]):
self.service_data_uuid[matcher[SERVICE_DATA_UUID]].remove(matcher) self.service_data_uuid[matcher[SERVICE_DATA_UUID]].remove(matcher)
return return
if MANUFACTURER_ID in matcher:
self.manufacturer_id[matcher[MANUFACTURER_ID]].remove(matcher)
return
def build(self) -> None: def build(self) -> None:
"""Rebuild the index sets.""" """Rebuild the index sets."""
self.service_uuid_set = set(self.service_uuid) self.service_uuid_set = set(self.service_uuid)
@ -235,33 +237,36 @@ class BluetoothMatcherIndexBase(Generic[_T]):
def match(self, service_info: BluetoothServiceInfoBleak) -> list[_T]: def match(self, service_info: BluetoothServiceInfoBleak) -> list[_T]:
"""Check for a match.""" """Check for a match."""
matches = [] matches = []
if len(service_info.name) >= LOCAL_NAME_MIN_MATCH_LENGTH: if service_info.name and len(service_info.name) >= LOCAL_NAME_MIN_MATCH_LENGTH:
for matcher in self.local_name.get( for matcher in self.local_name.get(
service_info.name[:LOCAL_NAME_MIN_MATCH_LENGTH], [] service_info.name[:LOCAL_NAME_MIN_MATCH_LENGTH], []
): ):
if ble_device_matches(matcher, service_info): if ble_device_matches(matcher, service_info):
matches.append(matcher) matches.append(matcher)
for service_data_uuid in self.service_data_uuid_set.intersection( if self.service_data_uuid_set and service_info.service_data:
service_info.service_data for service_data_uuid in self.service_data_uuid_set.intersection(
): service_info.service_data
for matcher in self.service_data_uuid[service_data_uuid]: ):
if ble_device_matches(matcher, service_info): for matcher in self.service_data_uuid[service_data_uuid]:
matches.append(matcher) if ble_device_matches(matcher, service_info):
matches.append(matcher)
for manufacturer_id in self.manufacturer_id_set.intersection( if self.manufacturer_id_set and service_info.manufacturer_data:
service_info.manufacturer_data for manufacturer_id in self.manufacturer_id_set.intersection(
): service_info.manufacturer_data
for matcher in self.manufacturer_id[manufacturer_id]: ):
if ble_device_matches(matcher, service_info): for matcher in self.manufacturer_id[manufacturer_id]:
matches.append(matcher) if ble_device_matches(matcher, service_info):
matches.append(matcher)
for service_uuid in self.service_uuid_set.intersection( if self.service_uuid_set and service_info.service_uuids:
service_info.service_uuids for service_uuid in self.service_uuid_set.intersection(
): service_info.service_uuids
for matcher in self.service_uuid[service_uuid]: ):
if ble_device_matches(matcher, service_info): for matcher in self.service_uuid[service_uuid]:
matches.append(matcher) if ble_device_matches(matcher, service_info):
matches.append(matcher)
return matches return matches
@ -347,8 +352,6 @@ def ble_device_matches(
service_info: BluetoothServiceInfoBleak, service_info: BluetoothServiceInfoBleak,
) -> bool: ) -> bool:
"""Check if a ble device and advertisement_data matches the matcher.""" """Check if a ble device and advertisement_data matches the matcher."""
device = service_info.device
# Don't check address here since all callers already # Don't check address here since all callers already
# check the address and we don't want to double check # check the address and we don't want to double check
# since it would result in an unreachable reject case. # since it would result in an unreachable reject case.
@ -379,7 +382,8 @@ def ble_device_matches(
return False return False
if (local_name := matcher.get(LOCAL_NAME)) and ( if (local_name := matcher.get(LOCAL_NAME)) and (
(device_name := advertisement_data.local_name or device.name) is None (device_name := advertisement_data.local_name or service_info.device.name)
is None
or not _memorized_fnmatch( or not _memorized_fnmatch(
device_name, device_name,
local_name, local_name,