mirror of
https://github.com/matrix-org/sliding-sync.git
synced 2025-03-10 13:37:11 +00:00
GlobalCache: load LatestEventsByType on startup
This commit is contained in:
parent
747062c23b
commit
da118624d9
@ -6,6 +6,13 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// EventMetadata holds timing information about an event, to be used when sorting room
|
||||
// lists by recency.
|
||||
type EventMetadata struct {
|
||||
NID int64
|
||||
Timestamp uint64
|
||||
}
|
||||
|
||||
// RoomMetadata holds room-scoped data. It is primarily used in two places:
|
||||
// - in the caches.GlobalCache, to hold the latest version of data that is consistent
|
||||
// between all users in the room; and
|
||||
@ -21,15 +28,15 @@ type RoomMetadata struct {
|
||||
CanonicalAlias string
|
||||
JoinCount int
|
||||
InviteCount int
|
||||
// LastMessageTimestamp is the origin_server_ts of the event most recently seen in
|
||||
// this room. Because events arrive at the upstream homeserver out-of-order (and
|
||||
// because origin_server_ts is an untrusted event field), this timestamp can
|
||||
// _decrease_ as new events come in.
|
||||
// TODO removeme
|
||||
LastMessageTimestamp uint64
|
||||
Encrypted bool
|
||||
PredecessorRoomID *string
|
||||
UpgradedRoomID *string
|
||||
RoomType *string
|
||||
// LatestEventsByType tracks timing information for the latest event in the room,
|
||||
// grouped by event type.
|
||||
LatestEventsByType map[string]EventMetadata
|
||||
Encrypted bool
|
||||
PredecessorRoomID *string
|
||||
UpgradedRoomID *string
|
||||
RoomType *string
|
||||
// if this room is a space, which rooms are m.space.child state events. This is the same for all users hence is global.
|
||||
ChildSpaceRooms map[string]struct{}
|
||||
// The latest m.typing ephemeral event for this room.
|
||||
@ -38,8 +45,9 @@ type RoomMetadata struct {
|
||||
|
||||
func NewRoomMetadata(roomID string) *RoomMetadata {
|
||||
return &RoomMetadata{
|
||||
RoomID: roomID,
|
||||
ChildSpaceRooms: make(map[string]struct{}),
|
||||
RoomID: roomID,
|
||||
LatestEventsByType: make(map[string]EventMetadata),
|
||||
ChildSpaceRooms: make(map[string]struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -328,10 +328,20 @@ func (t *EventTable) SelectLatestEventsBetween(txn *sqlx.Tx, roomID string, lowe
|
||||
return events, err
|
||||
}
|
||||
|
||||
func (t *EventTable) selectLatestEventInAllRooms(txn *sqlx.Tx) ([]Event, error) {
|
||||
func (t *EventTable) selectLatestEventByTypeInAllRooms(txn *sqlx.Tx) ([]Event, error) {
|
||||
result := []Event{}
|
||||
// TODO: this query ends up doing a sequential scan on the events table. We have
|
||||
// an index on (event_type, room_id, event_nid) so I'm a little surprised that PG
|
||||
// decides to do so. Can we do something better here? Ideas:
|
||||
// - Find a better query for selecting the newest event of each type in a room.
|
||||
// - At present we only care about the _timestamps_ of these events. Perhaps we
|
||||
// could store those in the DB (and even in an index) as a column and select
|
||||
// those, to avoid having to parse the event bodies.
|
||||
// - We could have the application maintain a `latest_events` table so that the
|
||||
// rows can be directly read. Assuming a mostly-static set of event types, reads
|
||||
// are then linear in the number of rooms.
|
||||
rows, err := txn.Query(
|
||||
`SELECT room_id, event FROM syncv3_events WHERE event_nid in (SELECT MAX(event_nid) FROM syncv3_events GROUP BY room_id)`,
|
||||
`SELECT room_id, event_nid, event FROM syncv3_events WHERE event_nid in (SELECT MAX(event_nid) FROM syncv3_events GROUP BY room_id, event_type)`,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -339,7 +349,7 @@ func (t *EventTable) selectLatestEventInAllRooms(txn *sqlx.Tx) ([]Event, error)
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var ev Event
|
||||
if err := rows.Scan(&ev.RoomID, &ev.JSON); err != nil {
|
||||
if err := rows.Scan(&ev.RoomID, &ev.NID, &ev.JSON); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, ev)
|
||||
|
@ -182,13 +182,22 @@ func (s *Storage) MetadataForAllRooms(txn *sqlx.Tx, tempTableName string, result
|
||||
}
|
||||
|
||||
// work out latest timestamps
|
||||
events, err := s.accumulator.eventsTable.selectLatestEventInAllRooms(txn)
|
||||
events, err := s.accumulator.eventsTable.selectLatestEventByTypeInAllRooms(txn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, ev := range events {
|
||||
metadata := result[ev.RoomID]
|
||||
metadata, ok := result[ev.RoomID]
|
||||
metadata.LastMessageTimestamp = gjson.ParseBytes(ev.JSON).Get("origin_server_ts").Uint()
|
||||
if !ok {
|
||||
metadata = *internal.NewRoomMetadata(ev.RoomID)
|
||||
}
|
||||
parsed := gjson.ParseBytes(ev.JSON)
|
||||
eventMetadata := internal.EventMetadata{
|
||||
NID: ev.NID,
|
||||
Timestamp: parsed.Get("origin_server_ts").Uint(),
|
||||
}
|
||||
metadata.LatestEventsByType[parsed.Get("type").Str] = eventMetadata
|
||||
// it's possible the latest event is a brand new room not caught by the first SELECT for joined
|
||||
// rooms e.g when you're invited to a room so we need to make sure to set the metadata again here
|
||||
metadata.RoomID = ev.RoomID
|
||||
|
Loading…
x
Reference in New Issue
Block a user