Make push rules use proper structures. (#13522)

This improves load times for push rules:

| Version              | Time per user | Time for 1k users | 
| -------------------- | ------------- | ----------------- |
| Before               |       138 µs  |             138ms |
| Now (with custom)    |       2.11 µs |            2.11ms |
| Now (without custom) |       49.7 ns |           0.05 ms |

This therefore has a large impact on send times for rooms
with large numbers of local users in the room.
This commit is contained in:
Erik Johnston 2022-08-16 12:22:17 +01:00 committed by GitHub
parent d642ce4b32
commit 5442891cbc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 495 additions and 334 deletions

View file

@ -18,16 +18,15 @@ from typing import Any, Dict, List, Optional
from synapse.push.rulekinds import PRIORITY_CLASS_INVERSE_MAP, PRIORITY_CLASS_MAP
from synapse.types import UserID
from .baserules import FilteredPushRules, PushRule
def format_push_rules_for_user(
user: UserID, ruleslist: List
user: UserID, ruleslist: FilteredPushRules
) -> Dict[str, Dict[str, list]]:
"""Converts a list of rawrules and a enabled map into nested dictionaries
to match the Matrix client-server format for push rules"""
# We're going to be mutating this a lot, so do a deep copy
ruleslist = copy.deepcopy(ruleslist)
rules: Dict[str, Dict[str, List[Dict[str, Any]]]] = {
"global": {},
"device": {},
@ -35,11 +34,30 @@ def format_push_rules_for_user(
rules["global"] = _add_empty_priority_class_arrays(rules["global"])
for r in ruleslist:
template_name = _priority_class_to_template_name(r["priority_class"])
for r, enabled in ruleslist:
template_name = _priority_class_to_template_name(r.priority_class)
rulearray = rules["global"][template_name]
template_rule = _rule_to_template(r)
if not template_rule:
continue
rulearray.append(template_rule)
template_rule["enabled"] = enabled
if "conditions" not in template_rule:
# Not all formatted rules have explicit conditions, e.g. "room"
# rules omit them as they can be derived from the kind and rule ID.
#
# If the formatted rule has no conditions then we can skip the
# formatting of conditions.
continue
# Remove internal stuff.
for c in r["conditions"]:
template_rule["conditions"] = copy.deepcopy(template_rule["conditions"])
for c in template_rule["conditions"]:
c.pop("_cache_key", None)
pattern_type = c.pop("pattern_type", None)
@ -52,16 +70,6 @@ def format_push_rules_for_user(
if sender_type == "user_id":
c["sender"] = user.to_string()
rulearray = rules["global"][template_name]
template_rule = _rule_to_template(r)
if template_rule:
if "enabled" in r:
template_rule["enabled"] = r["enabled"]
else:
template_rule["enabled"] = True
rulearray.append(template_rule)
return rules
@ -71,24 +79,24 @@ def _add_empty_priority_class_arrays(d: Dict[str, list]) -> Dict[str, list]:
return d
def _rule_to_template(rule: Dict[str, Any]) -> Optional[Dict[str, Any]]:
unscoped_rule_id = None
if "rule_id" in rule:
unscoped_rule_id = _rule_id_from_namespaced(rule["rule_id"])
def _rule_to_template(rule: PushRule) -> Optional[Dict[str, Any]]:
templaterule: Dict[str, Any]
template_name = _priority_class_to_template_name(rule["priority_class"])
unscoped_rule_id = _rule_id_from_namespaced(rule.rule_id)
template_name = _priority_class_to_template_name(rule.priority_class)
if template_name in ["override", "underride"]:
templaterule = {k: rule[k] for k in ["conditions", "actions"]}
templaterule = {"conditions": rule.conditions, "actions": rule.actions}
elif template_name in ["sender", "room"]:
templaterule = {"actions": rule["actions"]}
unscoped_rule_id = rule["conditions"][0]["pattern"]
templaterule = {"actions": rule.actions}
unscoped_rule_id = rule.conditions[0]["pattern"]
elif template_name == "content":
if len(rule["conditions"]) != 1:
if len(rule.conditions) != 1:
return None
thecond = rule["conditions"][0]
thecond = rule.conditions[0]
if "pattern" not in thecond:
return None
templaterule = {"actions": rule["actions"]}
templaterule = {"actions": rule.actions}
templaterule["pattern"] = thecond["pattern"]
else:
# This should not be reached unless this function is not kept in sync
@ -97,8 +105,8 @@ def _rule_to_template(rule: Dict[str, Any]) -> Optional[Dict[str, Any]]:
if unscoped_rule_id:
templaterule["rule_id"] = unscoped_rule_id
if "default" in rule:
templaterule["default"] = rule["default"]
if rule.default:
templaterule["default"] = True
return templaterule