Resolve state after event against current room state when determining latest state changes (#1479)

* Resolve state after event against current room state when determining latest state changes

* Update sytest-whitelist

* Update sytest-whitelist, blacklist
This commit is contained in:
Neil Alexander 2020-10-05 17:47:08 +01:00 committed by GitHub
parent 4e6b7f726d
commit 2e71d2708f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 31 additions and 11 deletions

View file

@ -215,10 +215,27 @@ 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)
// Get a list of the current latest events. // Get a list of the current room state events if available.
latestStateAtEvents := make([]types.StateAtEvent, len(u.latest)) var currentState []types.StateEntry
if u.roomInfo.StateSnapshotNID != 0 {
currentState, _ = roomState.LoadStateAtSnapshot(u.ctx, u.roomInfo.StateSnapshotNID)
}
// Get a list of the current latest events. This will include both
// the current room state and the latest events after the input event.
// The idea is that we will perform state resolution on this set and
// any conflicting events will be resolved properly.
latestStateAtEvents := make([]types.StateAtEvent, len(u.latest)+len(currentState))
offset := 0
for i := range currentState {
latestStateAtEvents[i] = types.StateAtEvent{
BeforeStateSnapshotNID: u.roomInfo.StateSnapshotNID,
StateEntry: currentState[i],
}
offset++
}
for i := range u.latest { for i := range u.latest {
latestStateAtEvents[i] = u.latest[i].StateAtEvent latestStateAtEvents[offset+i] = u.latest[i].StateAtEvent
} }
// Takes the NIDs of the latest events and creates a state snapshot // Takes the NIDs of the latest events and creates a state snapshot

View file

@ -118,7 +118,7 @@ func (v StateResolution) LoadCombinedStateAfterEvents(
// 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, err return nil, fmt.Errorf("v.db.StateBlockNIDs: %w", err)
} }
var stateBlockNIDs []types.StateBlockNID var stateBlockNIDs []types.StateBlockNID
@ -131,7 +131,7 @@ func (v StateResolution) LoadCombinedStateAfterEvents(
// multiple snapshots. // multiple snapshots.
stateEntryLists, err := v.db.StateEntries(ctx, uniqueStateBlockNIDs(stateBlockNIDs)) stateEntryLists, err := v.db.StateEntries(ctx, uniqueStateBlockNIDs(stateBlockNIDs))
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("v.db.StateEntries: %w", err)
} }
stateBlockNIDsMap := stateBlockNIDListMap(stateBlockNIDLists) stateBlockNIDsMap := stateBlockNIDListMap(stateBlockNIDLists)
stateEntriesMap := stateEntryListMap(stateEntryLists) stateEntriesMap := stateEntryListMap(stateEntryLists)
@ -623,7 +623,7 @@ func (v StateResolution) calculateAndStoreStateAfterManyEvents(
v.calculateStateAfterManyEvents(ctx, v.roomInfo.RoomVersion, prevStates) v.calculateStateAfterManyEvents(ctx, v.roomInfo.RoomVersion, prevStates)
metrics.algorithm = algorithm metrics.algorithm = algorithm
if err != nil { if err != nil {
return metrics.stop(0, err) return metrics.stop(0, fmt.Errorf("v.calculateStateAfterManyEvents: %w", err))
} }
// TODO: Check if we can encode the new state as a delta against the // TODO: Check if we can encode the new state as a delta against the
@ -642,6 +642,7 @@ func (v StateResolution) calculateStateAfterManyEvents(
// First stage: load the state after each of the prev events. // First stage: load the state after each of the prev events.
combined, err = v.LoadCombinedStateAfterEvents(ctx, prevStates) combined, err = v.LoadCombinedStateAfterEvents(ctx, prevStates)
if err != nil { if err != nil {
err = fmt.Errorf("v.LoadCombinedStateAfterEvents: %w", err)
algorithm = "_load_combined_state" algorithm = "_load_combined_state"
return return
} }
@ -672,6 +673,7 @@ func (v StateResolution) calculateStateAfterManyEvents(
var resolved []types.StateEntry var resolved []types.StateEntry
resolved, err = v.resolveConflicts(ctx, roomVersion, notConflicted, conflicts) resolved, err = v.resolveConflicts(ctx, roomVersion, notConflicted, conflicts)
if err != nil { if err != nil {
err = fmt.Errorf("v.resolveConflits: %w", err)
algorithm = "_resolve_conflicts" algorithm = "_resolve_conflicts"
return return
} }

View file

@ -52,4 +52,9 @@ Inbound federation accepts a second soft-failed event
Outbound federation requests missing prev_events and then asks for /state_ids and resolves the state Outbound federation requests missing prev_events and then asks for /state_ids and resolves the state
# We don't implement lazy membership loading yet. # We don't implement lazy membership loading yet.
The only membership state included in a gapped incremental sync is for senders in the timeline The only membership state included in a gapped incremental sync is for senders in the timeline
# Blacklisted out of flakiness after #1479
Invited user can reject local invite after originator leaves
Invited user can reject invite for empty room
If user leaves room, remote user changes device and rejoins we see update in /sync and /keys/changes

View file

@ -400,8 +400,6 @@ Uninvited users cannot join the room
Users cannot invite themselves to a room Users cannot invite themselves to a room
Users cannot invite a user that is already in the room Users cannot invite a user that is already in the room
Invited user can reject invite Invited user can reject invite
Invited user can reject invite for empty room
Invited user can reject local invite after originator leaves
PUT /rooms/:room_id/typing/:user_id sets typing notification PUT /rooms/:room_id/typing/:user_id sets typing notification
Typing notification sent to local room members Typing notification sent to local room members
Typing notifications also sent to remote room members Typing notifications also sent to remote room members
@ -431,7 +429,6 @@ A prev_batch token can be used in the v1 messages API
We don't send redundant membership state across incremental syncs by default We don't send redundant membership state across incremental syncs by default
Typing notifications don't leak Typing notifications don't leak
Users cannot kick users from a room they are not in Users cannot kick users from a room they are not in
Users cannot kick users who have already left a room
User appears in user directory User appears in user directory
User directory correctly update on display name change User directory correctly update on display name change
User in shared private room does appear in user directory User in shared private room does appear in user directory
@ -451,7 +448,6 @@ Banned servers cannot backfill
Inbound /v1/send_leave rejects leaves from other servers Inbound /v1/send_leave rejects leaves from other servers
Guest users can accept invites to private rooms over federation Guest users can accept invites to private rooms over federation
AS user (not ghost) can join room without registering AS user (not ghost) can join room without registering
If user leaves room, remote user changes device and rejoins we see update in /sync and /keys/changes
Can search public room list Can search public room list
Can get remote public room list Can get remote public room list
Asking for a remote rooms list, but supplying the local server's name, returns the local rooms list Asking for a remote rooms list, but supplying the local server's name, returns the local rooms list