mirror of
https://github.com/hoernschen/dendrite.git
synced 2025-07-29 12:42:46 +00:00
Fix sqlite locking bugs present on sytest (#1543)
* Fix sqite locking bugs present on sytest Comments do the explaining. * Fix deadlock in sqlite mode Caused by starting a writer whilst within a writer * Only complain about invalid state deltas for non-overwrite events * Do not re-process outlier unnecessarily
This commit is contained in:
parent
92982a402f
commit
eb86e2b336
4 changed files with 52 additions and 13 deletions
|
@ -70,16 +70,14 @@ func (u *LatestEventsUpdater) CurrentStateSnapshotNID() types.StateSnapshotNID {
|
|||
return u.currentStateSnapshotNID
|
||||
}
|
||||
|
||||
// StorePreviousEvents implements types.RoomRecentEventsUpdater
|
||||
// StorePreviousEvents implements types.RoomRecentEventsUpdater - This must be called from a Writer
|
||||
func (u *LatestEventsUpdater) StorePreviousEvents(eventNID types.EventNID, previousEventReferences []gomatrixserverlib.EventReference) error {
|
||||
return u.d.Writer.Do(u.d.DB, u.txn, func(txn *sql.Tx) error {
|
||||
for _, ref := range previousEventReferences {
|
||||
if err := u.d.PrevEventsTable.InsertPreviousEvent(u.ctx, txn, ref.EventID, ref.EventSHA256, eventNID); err != nil {
|
||||
return fmt.Errorf("u.d.PrevEventsTable.InsertPreviousEvent: %w", err)
|
||||
}
|
||||
for _, ref := range previousEventReferences {
|
||||
if err := u.d.PrevEventsTable.InsertPreviousEvent(u.ctx, u.txn, ref.EventID, ref.EventSHA256, eventNID); err != nil {
|
||||
return fmt.Errorf("u.d.PrevEventsTable.InsertPreviousEvent: %w", err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsReferenced implements types.RoomRecentEventsUpdater
|
||||
|
|
|
@ -492,15 +492,32 @@ func (d *Database) StoreEvent(
|
|||
if roomInfo == nil && len(prevEvents) > 0 {
|
||||
return 0, types.StateAtEvent{}, nil, "", fmt.Errorf("expected room %q to exist", event.RoomID())
|
||||
}
|
||||
// Create an updater - NB: on sqlite this WILL create a txn as we are directly calling the shared DB form of
|
||||
// GetLatestEventsForUpdate - not via the SQLiteDatabase form which has `nil` txns. This
|
||||
// function only does SELECTs though so the created txn (at this point) is just a read txn like
|
||||
// any other so this is fine. If we ever update GetLatestEventsForUpdate or NewLatestEventsUpdater
|
||||
// to do writes however then this will need to go inside `Writer.Do`.
|
||||
updater, err = d.GetLatestEventsForUpdate(ctx, *roomInfo)
|
||||
if err != nil {
|
||||
return 0, types.StateAtEvent{}, nil, "", fmt.Errorf("NewLatestEventsUpdater: %w", err)
|
||||
}
|
||||
if err = updater.StorePreviousEvents(eventNID, prevEvents); err != nil {
|
||||
return 0, types.StateAtEvent{}, nil, "", fmt.Errorf("updater.StorePreviousEvents: %w", err)
|
||||
// Ensure that we atomically store prev events AND commit them. If we don't wrap StorePreviousEvents
|
||||
// and EndTransaction in a writer then it's possible for a new write txn to be made between the two
|
||||
// function calls which will then fail with 'database is locked'. This new write txn would HAVE to be
|
||||
// something like SetRoomAlias/RemoveRoomAlias as normal input events are already done sequentially due to
|
||||
// SupportsConcurrentRoomInputs() == false on sqlite, though this does not apply to setting room aliases
|
||||
// as they don't go via InputRoomEvents
|
||||
err = d.Writer.Do(d.DB, updater.txn, func(txn *sql.Tx) error {
|
||||
if err = updater.StorePreviousEvents(eventNID, prevEvents); err != nil {
|
||||
return fmt.Errorf("updater.StorePreviousEvents: %w", err)
|
||||
}
|
||||
succeeded := true
|
||||
err = sqlutil.EndTransaction(updater, &succeeded)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return 0, types.StateAtEvent{}, nil, "", err
|
||||
}
|
||||
succeeded := true
|
||||
err = sqlutil.EndTransaction(updater, &succeeded)
|
||||
}
|
||||
|
||||
return roomNID, types.StateAtEvent{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue