Don't create so many state snapshots when updating forward extremities (#1718)

* Light-weight checking of state changes when updating forward extremities

* Only do this for non-state events, since state events will always result in state change at extremities
This commit is contained in:
Neil Alexander 2021-01-18 13:21:33 +00:00 committed by GitHub
parent dd1e31bee7
commit 244ff0dccb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 6 deletions

View file

@ -100,7 +100,8 @@ type latestEventsUpdater struct {
// The eventID of the event that was processed before this one. // The eventID of the event that was processed before this one.
lastEventIDSent string lastEventIDSent string
// The latest events in the room after processing this event. // The latest events in the room after processing this event.
latest []types.StateAtEventAndReference oldLatest []types.StateAtEventAndReference
latest []types.StateAtEventAndReference
// The state entries removed from and added to the current state of the // The state entries removed from and added to the current state of the
// room as a result of processing this event. They are sorted lists. // room as a result of processing this event. They are sorted lists.
removed []types.StateEntry removed []types.StateEntry
@ -123,10 +124,10 @@ func (u *latestEventsUpdater) doUpdateLatestEvents() error {
// state snapshot from somewhere else, e.g. a federated room join, // state snapshot from somewhere else, e.g. a federated room join,
// then start with an empty set - none of the forward extremities // then start with an empty set - none of the forward extremities
// that we knew about before matter anymore. // that we knew about before matter anymore.
oldLatest := []types.StateAtEventAndReference{} u.oldLatest = []types.StateAtEventAndReference{}
if !u.rewritesState { if !u.rewritesState {
u.oldStateNID = u.updater.CurrentStateSnapshotNID() u.oldStateNID = u.updater.CurrentStateSnapshotNID()
oldLatest = u.updater.LatestEvents() u.oldLatest = u.updater.LatestEvents()
} }
// If the event has already been written to the output log then we // If the event has already been written to the output log then we
@ -140,7 +141,7 @@ func (u *latestEventsUpdater) doUpdateLatestEvents() error {
// Work out what the latest events are. This will include the new // Work out what the latest events are. This will include the new
// event if it is not already referenced. // event if it is not already referenced.
extremitiesChanged, err := u.calculateLatest( extremitiesChanged, err := u.calculateLatest(
oldLatest, u.event, u.oldLatest, u.event,
types.StateAtEventAndReference{ types.StateAtEventAndReference{
EventReference: u.event.EventReference(), EventReference: u.event.EventReference(),
StateAtEvent: u.stateAtEvent, StateAtEvent: u.stateAtEvent,
@ -200,6 +201,37 @@ func (u *latestEventsUpdater) latestState() error {
var err error var err error
roomState := state.NewStateResolution(u.api.DB, *u.roomInfo) roomState := state.NewStateResolution(u.api.DB, *u.roomInfo)
// Work out if the state at the extremities has actually changed
// or not. If they haven't then we won't bother doing all of the
// hard work.
if u.event.StateKey() == nil {
stateChanged := false
oldStateNIDs := make([]types.StateSnapshotNID, 0, len(u.oldLatest))
newStateNIDs := make([]types.StateSnapshotNID, 0, len(u.latest))
for _, old := range u.oldLatest {
oldStateNIDs = append(oldStateNIDs, old.BeforeStateSnapshotNID)
}
for _, new := range u.latest {
newStateNIDs = append(newStateNIDs, new.BeforeStateSnapshotNID)
}
oldStateNIDs = state.UniqueStateSnapshotNIDs(oldStateNIDs)
newStateNIDs = state.UniqueStateSnapshotNIDs(newStateNIDs)
if len(oldStateNIDs) != len(newStateNIDs) {
stateChanged = true
} else {
for i := range oldStateNIDs {
if oldStateNIDs[i] != newStateNIDs[i] {
stateChanged = true
break
}
}
}
if !stateChanged {
u.newStateNID = u.oldStateNID
return nil
}
}
// Get a list of the current latest events. This may or may not // Get a list of the current latest events. This may or may not
// include the new event from the input path, depending on whether // include the new event from the input path, depending on whether
// it is a forward extremity or not. // it is a forward extremity or not.

View file

@ -116,7 +116,7 @@ func (v StateResolution) LoadCombinedStateAfterEvents(
// Deduplicate the IDs before passing them to the database. // Deduplicate the IDs before passing them to the database.
// There could be duplicates because the events could be state events where // There could be duplicates because the events could be state events where
// the snapshot of the room state before them was the same. // the snapshot of the room state before them was the same.
stateBlockNIDLists, err := v.db.StateBlockNIDs(ctx, uniqueStateSnapshotNIDs(stateNIDs)) stateBlockNIDLists, err := v.db.StateBlockNIDs(ctx, UniqueStateSnapshotNIDs(stateNIDs))
if err != nil { if err != nil {
return nil, fmt.Errorf("v.db.StateBlockNIDs: %w", err) return nil, fmt.Errorf("v.db.StateBlockNIDs: %w", err)
} }
@ -1103,7 +1103,7 @@ func (s stateNIDSorter) Len() int { return len(s) }
func (s stateNIDSorter) Less(i, j int) bool { return s[i] < s[j] } func (s stateNIDSorter) Less(i, j int) bool { return s[i] < s[j] }
func (s stateNIDSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s stateNIDSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func uniqueStateSnapshotNIDs(nids []types.StateSnapshotNID) []types.StateSnapshotNID { func UniqueStateSnapshotNIDs(nids []types.StateSnapshotNID) []types.StateSnapshotNID {
return nids[:util.SortAndUnique(stateNIDSorter(nids))] return nids[:util.SortAndUnique(stateNIDSorter(nids))]
} }