Repository navigation
fix(schema-1): per-message cost no longer grows with the device tree - #224
Merged
Merged
Conversation
ControllerRoutes.dispatch tested every recorded subscription in turn with paho's topic_matches_sub, which builds a fresh matcher for each call. Tree-rooted discovery records four routes per device, so every message cost grew with the panel, and the panel's own topics, recorded first and matched last, cost the most. The recorded patterns now live in one paho MQTTMatcher, and dispatch resolves the patterns that match through the typed route table. The most recently recorded match still wins, decided by a recording number rather than by the matcher's order, and a pattern is removed from the matcher only when it was recorded. _release indexes the new pattern once instead of once per held topic. paho leaves its matcher unannotated inside a py.typed package, so mypy exempts calls into paho.mqtt.matcher. What the matcher yields is used only as a key into the typed table. The new overlap test is the only one a first-match matcher fails; the existing ordering tests cannot tell recency from specificity. Refs #223
The transport asks is_ready() before and after every message, and each call walked the declared tree twice, through _awaiting_descriptions and Controller.is_tree_complete. Readiness cannot change on an ordinary value, so on a quiet tree that work bought nothing. The adapter now keeps its last answer and forgets it on the Controller's own events: a device's first $state, a change of state, a removal, a $description, and the panel's info/model value. The next call works it out again, never the event itself, because a description is announced before the SDK has reconciled the children it declares. The walk is unchanged, moved to _tree_ready(). Each readiness test asks after every message, as the transport does, and compares with a fresh adapter fed the same messages. The replays cover five arrival orders, and the scenarios cover the panel leaving ready, a child removed and returning, a child declared and withdrawn, the model's declaration changing, and a childless panel whose $state arrives last. Disabling any one of the five events fails at least one of them; the discovered event is caught only by the childless panel. Refs #223
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #223.
Every MQTT message on a parent/child panel paid for two things that grow with the tree:
ControllerRoutes.dispatchtested each recorded subscription in turn withtopic_matches_sub, which builds a fresh matcher per call. That's four routes per device, and the panel's own topics, recorded first, are matched last.SpanMqttClient._on_messageasksis_ready()before and after each message, and every call walked the declared tree twice.Changes
fix(transport): the recorded patterns live in one pahoMQTTMatcher. Dispatch looks up the matching patterns in the typed route table, and the most recently recorded one still wins, decided by a recording number._releaseindexes the new pattern once instead of once per held topic. paho leavespaho/mqtt/matcher.pyunannotated, so mypy getsuntyped_calls_exclude = ["paho.mqtt.matcher"], with a comment on the one shape that keeps itsAnycontained.fix(adapter):is_ready()keeps its answer and forgets it on theController's own events: a device's first$state, a change of state, a removal, a$description, and the panel'sinfo/modelvalue. The next call works it out again. The tree walk is unchanged.client.pyis unchanged.Tree changes stay correct:
$descriptionor a removal, which updates the routes and clears readiness.info/namevalue. It doesn't touch routes or readiness, and it still reaches the snapshot.Measured
Per message, both
is_ready()calls plushandle_message, on an M-series Mac. The reference tree was grown by cloning circuits.Not yet measured on a CM4; the issue reporter has offered to test.
Tests
Falsified:
Full suite: 1872 passed, 7 skipped (live capture absent), 9 xfailed. All pre-commit hooks pass.