-
Notifications
You must be signed in to change notification settings - Fork 235
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a column participant
to room_memberships
table
#18068
base: develop
Are you sure you want to change the base?
Changes from all commits
afeed5b
754c27b
830e5e6
bc05f58
e76f94e
62e6a04
93e7a0c
115ff00
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Add a column `participant` to `room_memberships` table. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1606,6 +1606,35 @@ def _get_rooms_for_user_by_join_date_txn( | |
from_ts, | ||
) | ||
|
||
async def set_room_participation(self, room_id: str, user_id: str) -> None: | ||
""" | ||
Record the provided user as participating in the given room | ||
|
||
Args: | ||
room_id: ID of the room to set the participant in | ||
user_id: the user ID of the user | ||
""" | ||
await self.db_pool.simple_update( | ||
"room_memberships", | ||
{"user_id": user_id, "room_id": room_id}, | ||
{"participant": True}, | ||
"update_room_participation", | ||
) | ||
|
||
async def get_room_participation(self, room_id: str, user_id: str) -> bool: | ||
""" | ||
Check whether a user is listed as a participant in a room | ||
|
||
Args: | ||
room_id: ID of the room to check in | ||
user_id: user ID of the user | ||
""" | ||
return await self.db_pool.simple_select_one_onecol( | ||
"room_memberships", | ||
{"user_id": user_id, "room_id": room_id}, | ||
"participant", | ||
) | ||
Comment on lines
+1632
to
+1636
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should order this by |
||
|
||
|
||
class RoomMemberBackgroundUpdateStore(SQLBaseStore): | ||
def __init__( | ||
|
@@ -1636,6 +1665,84 @@ def __init__( | |
columns=["user_id", "room_id"], | ||
) | ||
|
||
self.db_pool.updates.register_background_update_handler( | ||
"populate_participant_bg_update", self._populate_participant | ||
) | ||
|
||
async def _populate_participant(self, progress: JsonDict, batch_size: int) -> int: | ||
""" | ||
Background update to populate column `participant` on `room_memberships` table | ||
one room at a time | ||
""" | ||
last_room_id = progress.get("last_room_id", "") | ||
H-Shay marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
def _get_current_room_txn( | ||
txn: LoggingTransaction, last_room_id: str | ||
) -> Optional[str]: | ||
sql = """ | ||
SELECT room_id from room_memberships WHERE room_id > ? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that Note: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Currently we have:
I think we can instead do this in one query that processes a batch of Constrain your query to the current Now the table can continue to grow without things changing from underneath you, as historical data is only (rarely) deleted. |
||
ORDER BY room_id | ||
LIMIT 1; | ||
""" | ||
txn.execute(sql, (last_room_id,)) | ||
res = txn.fetchone() | ||
if res: | ||
room_id = res[0] | ||
return room_id | ||
else: | ||
return None | ||
|
||
def _background_populate_participant_per_room_txn( | ||
txn: LoggingTransaction, current_room_id: str | ||
) -> None: | ||
sql = """ | ||
SELECT DISTINCT c.state_key | ||
FROM current_state_events AS c | ||
INNER JOIN events AS e USING(room_id) | ||
WHERE room_id = ? | ||
AND c.membership = 'join' | ||
AND e.type = 'm.room.message' | ||
OR e.type = 'm.room.encrypted' | ||
AND c.state_key = e.sender; | ||
""" | ||
H-Shay marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
txn.execute(sql, (current_room_id,)) | ||
res = txn.fetchall() | ||
|
||
if res: | ||
participants = [user[0] for user in res] | ||
for participant in participants: | ||
self.db_pool.simple_update_txn( | ||
txn, | ||
table="room_memberships", | ||
keyvalues={"user_id": participant, "room_id": current_room_id}, | ||
updatevalues={"participant": True}, | ||
) | ||
Comment on lines
+1715
to
+1720
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note: we could batch this query by using |
||
|
||
current_room_id = await self.db_pool.runInteraction( | ||
"_get_current_room_txn", _get_current_room_txn, last_room_id | ||
) | ||
if not current_room_id: | ||
await self.db_pool.updates._end_background_update( | ||
"populate_participant_bg_update" | ||
) | ||
return 1 | ||
|
||
await self.db_pool.runInteraction( | ||
"_background_populate_participant_per_room_txn", | ||
_background_populate_participant_per_room_txn, | ||
current_room_id, | ||
) | ||
|
||
progress["last_room_id"] = current_room_id | ||
await self.db_pool.runInteraction( | ||
"populate_participant_bg_update", | ||
self.db_pool.updates._background_update_progress_txn, | ||
"populate_participant_bg_update", | ||
progress, | ||
) | ||
return 1 | ||
|
||
async def _background_add_membership_profile( | ||
self, progress: JsonDict, batch_size: int | ||
) -> int: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
-- | ||
-- This file is licensed under the Affero General Public License (AGPL) version 3. | ||
-- | ||
-- Copyright (C) 2025 New Vector, Ltd | ||
-- | ||
-- This program is free software: you can redistribute it and/or modify | ||
-- it under the terms of the GNU Affero General Public License as | ||
-- published by the Free Software Foundation, either version 3 of the | ||
-- License, or (at your option) any later version. | ||
-- | ||
-- See the GNU Affero General Public License for more details: | ||
-- <https://www.gnu.org/licenses/agpl-3.0.html>. | ||
|
||
-- Add a column `participant` to `room_memberships` table to track whether a room member has sent | ||
-- a `m.room.message` event into a room they are a member of | ||
H-Shay marked this conversation as resolved.
Show resolved
Hide resolved
|
||
ALTER TABLE room_memberships ADD COLUMN participant BOOLEAN DEFAULT FALSE; | ||
|
||
-- Add a background update to populate `participant` column | ||
INSERT INTO background_updates (ordering, update_name, progress_json) VALUES | ||
(8901, 'populate_participant_bg_update', '{}'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that
room_memberships
is an append-only list of a user's joins/leaves to a room. When settingparticipant
totrue
, we only need to do this for the most recent row for that user inroom_memberships
. We can do this by setting alimit
of1
here, and ordering byevent_stream_ordering DESC
. This should also cut down the query time.An additional advantage from doing so is that for those that have joined and left a room repeatedly, we'll be able to look back in old rows of
room_memberships
and answer the question: for the periods that this user was in the room, which of those times did they participate? (Is that a useful signal for T&S purposes?)