Use transactional isolation only if available

This commit is contained in:
Neil Alexander 2020-09-08 17:44:29 +01:00
parent e66c057297
commit 06c75fadf4
No known key found for this signature in database
GPG key ID: A02A2019A2BB0944
3 changed files with 61 additions and 51 deletions

View file

@ -80,6 +80,7 @@ func NewDatabase(dbProperties *config.DatabaseOptions) (*SyncServerDatasource, e
}
d.Database = shared.Database{
DB: d.db,
TransactionalIsolation: true,
Writer: d.writer,
Invites: invites,
AccountData: accountData,

View file

@ -37,6 +37,7 @@ import (
// For now this contains the shared functions
type Database struct {
DB *sql.DB
TransactionalIsolation bool
Writer sqlutil.Writer
Invites tables.Invites
AccountData tables.AccountData
@ -49,6 +50,19 @@ type Database struct {
EDUCache *cache.EDUCache
}
func (d *Database) getIsolatedTransactionIfAvailable(ctx context.Context, succeeded *bool) (txn *sql.Tx, done func(), err error) {
if d.TransactionalIsolation {
txn, err = d.DB.BeginTx(ctx, &txReadOnlySnapshot)
if err != nil {
return nil, nil, err
}
done = func() {
sqlutil.EndTransactionWithCheck(txn, succeeded, &err)
}
}
return
}
// Events lookups a list of event by their event ID.
// Returns a list of events matching the requested IDs found in the database.
// If an event is not found in the database then it will be omitted from the list.
@ -422,17 +436,14 @@ func (d *Database) addPDUDeltaToResponse(
wantFullState bool,
res *types.Response,
) (joinedRoomIDs []string, err error) {
txn, err := d.DB.BeginTx(ctx, &txReadOnlySnapshot)
if err != nil {
return nil, err
}
succeeded := false
defer func() {
_ = d.Writer.Do(d.DB, txn, func(txn *sql.Tx) error {
sqlutil.EndTransactionWithCheck(txn, &succeeded, &err)
return nil
})
}()
txn, done, err := d.getIsolatedTransactionIfAvailable(ctx, &succeeded)
if err != nil {
return nil, fmt.Errorf("getIsolatedTransactionIfAvailable: %w", err)
}
if txn != nil {
defer done()
}
stateFilter := gomatrixserverlib.DefaultStateFilter() // TODO: use filter provided in request
@ -620,17 +631,14 @@ func (d *Database) getResponseWithPDUsForCompleteSync(
// a consistent view of the database throughout. This includes extracting the sync position.
// This does have the unfortunate side-effect that all the matrixy logic resides in this function,
// but it's better to not hide the fact that this is being done in a transaction.
txn, err := d.DB.BeginTx(ctx, &txReadOnlySnapshot)
succeeded := false
txn, done, err := d.getIsolatedTransactionIfAvailable(ctx, &succeeded)
if err != nil {
return
}
succeeded := false
defer func() {
_ = d.Writer.Do(d.DB, txn, func(txn *sql.Tx) error {
sqlutil.EndTransactionWithCheck(txn, &succeeded, &err)
return nil
})
}()
if txn != nil {
defer done()
}
// Get the current sync position which we will base the sync response on.
toPos, err = d.syncPositionTx(ctx, txn)

View file

@ -93,6 +93,7 @@ func (d *SyncServerDatasource) prepare() (err error) {
}
d.Database = shared.Database{
DB: d.db,
TransactionalIsolation: false,
Writer: d.writer,
Invites: invites,
AccountData: accountData,