diff --git a/roomserver/storage/postgres/state_snapshot_table.go b/roomserver/storage/postgres/state_snapshot_table.go index 26ebcf856..99c76befe 100644 --- a/roomserver/storage/postgres/state_snapshot_table.go +++ b/roomserver/storage/postgres/state_snapshot_table.go @@ -77,21 +77,25 @@ const bulkSelectStateBlockNIDsSQL = "" + // helpers.CheckServerAllowedToSeeEvent function. // TODO: There's a sequence scan here because of the hash join strategy, which is // probably O(n) on state key entries, so there must be a way to avoid that somehow. -const bulkSelectStateForHistoryVisibilitySQL = "" + - "SELECT event_nid FROM (" + - " SELECT event_nid, event_type_nid, event_state_key_nid FROM roomserver_events" + - " WHERE (event_type_nid = 5 OR event_type_nid = 7)" + - " AND event_nid = ANY(" + - " SELECT UNNEST(event_nids) FROM roomserver_state_block" + - " WHERE state_block_nid = ANY(" + - " SELECT UNNEST(state_block_nids) FROM roomserver_state_snapshots" + - " WHERE state_snapshot_nid = $1" + - " )" + - " )" + - ") AS roomserver_events" + - " INNER JOIN roomserver_event_state_keys" + - " ON roomserver_events.event_state_key_nid = roomserver_event_state_keys.event_state_key_nid" + - " AND (event_type_nid = 7 OR event_state_key LIKE '%:' || $2);" +// Event type NIDs are: +// - 5: m.room.member as per https://github.com/matrix-org/dendrite/blob/c7f7aec4d07d59120d37d5b16a900f6d608a75c4/roomserver/storage/postgres/event_types_table.go#L40 +// - 7: m.room.history_visibility as per https://github.com/matrix-org/dendrite/blob/c7f7aec4d07d59120d37d5b16a900f6d608a75c4/roomserver/storage/postgres/event_types_table.go#L42 +const bulkSelectStateForHistoryVisibilitySQL = ` + SELECT event_nid FROM ( + SELECT event_nid, event_type_nid, event_state_key_nid FROM roomserver_events + WHERE (event_type_nid = 5 OR event_type_nid = 7) + AND event_nid = ANY( + SELECT UNNEST(event_nids) FROM roomserver_state_block + WHERE state_block_nid = ANY( + SELECT UNNEST(state_block_nids) FROM roomserver_state_snapshots + WHERE state_snapshot_nid = $1 + ) + ) + ) AS roomserver_events + INNER JOIN roomserver_event_state_keys + ON roomserver_events.event_state_key_nid = roomserver_event_state_keys.event_state_key_nid + AND (event_type_nid = 7 OR event_state_key LIKE '%:' || $2); +` type stateSnapshotStatements struct { insertStateStmt *sql.Stmt @@ -170,15 +174,12 @@ func (s *stateSnapshotStatements) BulkSelectStateForHistoryVisibility( } defer rows.Close() // nolint: errcheck results := make([]types.EventNID, 0, 16) - for i := 0; rows.Next(); i++ { + for rows.Next() { var eventNID types.EventNID if err = rows.Scan(&eventNID); err != nil { return nil, err } results = append(results, eventNID) } - if err = rows.Err(); err != nil { - return nil, err - } - return results, nil + return results, rows.Err() } diff --git a/roomserver/storage/tables/interface.go b/roomserver/storage/tables/interface.go index cf64ca28a..58c43ac45 100644 --- a/roomserver/storage/tables/interface.go +++ b/roomserver/storage/tables/interface.go @@ -83,6 +83,9 @@ type Rooms interface { type StateSnapshot interface { InsertState(ctx context.Context, txn *sql.Tx, roomNID types.RoomNID, stateBlockNIDs types.StateBlockNIDs) (stateNID types.StateSnapshotNID, err error) BulkSelectStateBlockNIDs(ctx context.Context, txn *sql.Tx, stateNIDs []types.StateSnapshotNID) ([]types.StateBlockNIDList, error) + // BulkSelectStateForHistoryVisibility is a PostgreSQL-only optimisation for finding + // which users are in a room faster than having to load the entire room state. In the + // case of SQLite, this will return tables.OptimisationNotSupportedError. BulkSelectStateForHistoryVisibility(ctx context.Context, txn *sql.Tx, stateSnapshotNID types.StateSnapshotNID, domain string) ([]types.EventNID, error) }