2424from twisted .internet import defer
2525
2626from synapse .api .constants import EventTypes , Membership
27+ from synapse .metrics .background_process_metrics import run_as_background_process
28+ from synapse .storage ._base import LoggingTransaction
2729from synapse .storage .events_worker import EventsWorkerStore
2830from synapse .types import get_domain_from_id
2931from synapse .util .async_helpers import Linearizer
5759
5860
5961class RoomMemberWorkerStore (EventsWorkerStore ):
62+ def __init__ (self , db_conn , hs ):
63+ super (RoomMemberWorkerStore , self ).__init__ (db_conn , hs )
64+
65+ # Is the current_state_events.membership up to date? Or is the
66+ # background update still running?
67+ self ._current_state_events_membership_up_to_date = False
68+
69+ txn = LoggingTransaction (
70+ db_conn .cursor (),
71+ name = "_check_safe_current_state_events_membership_updated" ,
72+ database_engine = self .database_engine ,
73+ )
74+ self ._check_safe_current_state_events_membership_updated_txn (txn )
75+ txn .close ()
76+
77+ def _check_safe_current_state_events_membership_updated_txn (self , txn ):
78+ """Checks if it is safe to assume the new current_state_events
79+ membership column is up to date
80+ """
81+
82+ pending_update = self ._simple_select_one_txn (
83+ txn ,
84+ table = "background_updates" ,
85+ keyvalues = {"update_name" : _CURRENT_STATE_MEMBERSHIP_UPDATE_NAME },
86+ retcols = ["update_name" ],
87+ allow_none = True ,
88+ )
89+
90+ self ._current_state_events_membership_up_to_date = not pending_update
91+
92+ # If the update is still running, reschedule to run.
93+ if pending_update :
94+ self ._clock .call_later (
95+ 15.0 ,
96+ run_as_background_process ,
97+ "_check_safe_current_state_events_membership_updated" ,
98+ self .runInteraction ,
99+ "_check_safe_current_state_events_membership_updated" ,
100+ self ._check_safe_current_state_events_membership_updated_txn ,
101+ )
102+
60103 @cachedInlineCallbacks (max_entries = 100000 , iterable = True , cache_context = True )
61104 def get_hosts_in_room (self , room_id , cache_context ):
62105 """Returns the set of all hosts currently in the room
@@ -70,14 +113,23 @@ def get_hosts_in_room(self, room_id, cache_context):
70113 @cached (max_entries = 100000 , iterable = True )
71114 def get_users_in_room (self , room_id ):
72115 def f (txn ):
73- sql = (
74- "SELECT m.user_id FROM room_memberships as m"
75- " INNER JOIN current_state_events as c"
76- " ON m.event_id = c.event_id "
77- " AND m.room_id = c.room_id "
78- " AND m.user_id = c.state_key"
79- " WHERE c.type = 'm.room.member' AND c.room_id = ? AND m.membership = ?"
80- )
116+ # If we can assume current_state_events.membership is up to date
117+ # then we can avoid a join, which is a Very Good Thing given how
118+ # frequently this function gets called.
119+ if self ._current_state_events_membership_up_to_date :
120+ sql = """
121+ SELECT state_key FROM current_state_events
122+ WHERE type = 'm.room.member' AND room_id = ? AND membership = ?
123+ """
124+ else :
125+ sql = """
126+ SELECT state_key FROM room_memberships as m
127+ INNER JOIN current_state_events as c
128+ ON m.event_id = c.event_id
129+ AND m.room_id = c.room_id
130+ AND m.user_id = c.state_key
131+ WHERE c.type = 'm.room.member' AND c.room_id = ? AND m.membership = ?
132+ """
81133
82134 txn .execute (sql , (room_id , Membership .JOIN ))
83135 return [to_ascii (r [0 ]) for r in txn ]
@@ -99,15 +151,26 @@ def _get_room_summary_txn(txn):
99151 # first get counts.
100152 # We do this all in one transaction to keep the cache small.
101153 # FIXME: get rid of this when we have room_stats
102- sql = """
103- SELECT count(*), m.membership FROM room_memberships as m
104- INNER JOIN current_state_events as c
105- ON m.event_id = c.event_id
106- AND m.room_id = c.room_id
107- AND m.user_id = c.state_key
108- WHERE c.type = 'm.room.member' AND c.room_id = ?
109- GROUP BY m.membership
110- """
154+
155+ # If we can assume current_state_events.membership is up to date
156+ # then we can avoid a join, which is a Very Good Thing given how
157+ # frequently this function gets called.
158+ if self ._current_state_events_membership_up_to_date :
159+ sql = """
160+ SELECT count(*), membership FROM current_state_events
161+ WHERE type = 'm.room.member' AND room_id = ?
162+ GROUP BY membership
163+ """
164+ else :
165+ sql = """
166+ SELECT count(*), m.membership FROM room_memberships as m
167+ INNER JOIN current_state_events as c
168+ ON m.event_id = c.event_id
169+ AND m.room_id = c.room_id
170+ AND m.user_id = c.state_key
171+ WHERE c.type = 'm.room.member' AND c.room_id = ?
172+ GROUP BY m.membership
173+ """
111174
112175 txn .execute (sql , (room_id ,))
113176 res = {}
0 commit comments