diff options
author | Neil Alexander <neilalexander@users.noreply.github.com> | 2020-12-11 14:02:17 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-11 14:02:17 +0000 |
commit | ebcacd1bb56d6e37ff743c0430bc91e24d440199 (patch) | |
tree | d9cd72accebe4004e8eb067026ab0158ccff0a1a /syncapi/storage/sqlite3 | |
parent | c55361c1b88b272c9a06e7dbc61f60e3effbd063 (diff) |
Give receipts their own stream ID in the database (#1631)
* Give read recipts their own database sequence
* Give receipts their own stream ID
* Change migration names
* Reset sequences
* Add max receipt queries, missing stream_id table entry for SQLite
Diffstat (limited to 'syncapi/storage/sqlite3')
-rw-r--r-- | syncapi/storage/sqlite3/deltas/20201211125500_sequences.go | 58 | ||||
-rw-r--r-- | syncapi/storage/sqlite3/receipt_table.go | 21 | ||||
-rw-r--r-- | syncapi/storage/sqlite3/stream_id_table.go | 12 | ||||
-rw-r--r-- | syncapi/storage/sqlite3/syncserver.go | 11 |
4 files changed, 99 insertions, 3 deletions
diff --git a/syncapi/storage/sqlite3/deltas/20201211125500_sequences.go b/syncapi/storage/sqlite3/deltas/20201211125500_sequences.go new file mode 100644 index 00000000..64905013 --- /dev/null +++ b/syncapi/storage/sqlite3/deltas/20201211125500_sequences.go @@ -0,0 +1,58 @@ +// Copyright 2020 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package deltas + +import ( + "database/sql" + "fmt" + + "github.com/matrix-org/dendrite/internal/sqlutil" + "github.com/pressly/goose" +) + +func LoadFromGoose() { + goose.AddMigration(UpFixSequences, DownFixSequences) +} + +func LoadFixSequences(m *sqlutil.Migrations) { + m.AddMigration(UpFixSequences, DownFixSequences) +} + +func UpFixSequences(tx *sql.Tx) error { + _, err := tx.Exec(` + -- We need to delete all of the existing receipts because the indexes + -- will be wrong, and we'll get primary key violations if we try to + -- reuse existing stream IDs from a different sequence. + DELETE FROM syncapi_receipts; + UPDATE syncapi_stream_id SET stream_id=1 WHERE stream_name="receipt"; + `) + if err != nil { + return fmt.Errorf("failed to execute upgrade: %w", err) + } + return nil +} + +func DownFixSequences(tx *sql.Tx) error { + _, err := tx.Exec(` + -- We need to delete all of the existing receipts because the indexes + -- will be wrong, and we'll get primary key violations if we try to + -- reuse existing stream IDs from a different sequence. + DELETE FROM syncapi_receipts; + `) + if err != nil { + return fmt.Errorf("failed to execute downgrade: %w", err) + } + return nil +} diff --git a/syncapi/storage/sqlite3/receipt_table.go b/syncapi/storage/sqlite3/receipt_table.go index b1770e80..dfde1fd2 100644 --- a/syncapi/storage/sqlite3/receipt_table.go +++ b/syncapi/storage/sqlite3/receipt_table.go @@ -55,11 +55,15 @@ const selectRoomReceipts = "" + " FROM syncapi_receipts" + " WHERE id > $1 and room_id in ($2)" +const selectMaxReceiptIDSQL = "" + + "SELECT MAX(id) FROM syncapi_receipts" + type receiptStatements struct { db *sql.DB streamIDStatements *streamIDStatements upsertReceipt *sql.Stmt selectRoomReceipts *sql.Stmt + selectMaxReceiptID *sql.Stmt } func NewSqliteReceiptsTable(db *sql.DB, streamID *streamIDStatements) (tables.Receipts, error) { @@ -77,12 +81,15 @@ func NewSqliteReceiptsTable(db *sql.DB, streamID *streamIDStatements) (tables.Re if r.selectRoomReceipts, err = db.Prepare(selectRoomReceipts); err != nil { return nil, fmt.Errorf("unable to prepare selectRoomReceipts statement: %w", err) } + if r.selectMaxReceiptID, err = db.Prepare(selectMaxReceiptIDSQL); err != nil { + return nil, fmt.Errorf("unable to prepare selectRoomReceipts statement: %w", err) + } return r, nil } // UpsertReceipt creates new user receipts func (r *receiptStatements) UpsertReceipt(ctx context.Context, txn *sql.Tx, roomId, receiptType, userId, eventId string, timestamp gomatrixserverlib.Timestamp) (pos types.StreamPosition, err error) { - pos, err = r.streamIDStatements.nextStreamID(ctx, txn) + pos, err = r.streamIDStatements.nextReceiptID(ctx, txn) if err != nil { return } @@ -116,3 +123,15 @@ func (r *receiptStatements) SelectRoomReceiptsAfter(ctx context.Context, roomIDs } return res, rows.Err() } + +func (s *receiptStatements) SelectMaxReceiptID( + ctx context.Context, txn *sql.Tx, +) (id int64, err error) { + var nullableID sql.NullInt64 + stmt := sqlutil.TxStmt(txn, s.selectMaxReceiptID) + err = stmt.QueryRowContext(ctx).Scan(&nullableID) + if nullableID.Valid { + id = nullableID.Int64 + } + return +} diff --git a/syncapi/storage/sqlite3/stream_id_table.go b/syncapi/storage/sqlite3/stream_id_table.go index e6bdc4fc..f73be422 100644 --- a/syncapi/storage/sqlite3/stream_id_table.go +++ b/syncapi/storage/sqlite3/stream_id_table.go @@ -18,6 +18,8 @@ CREATE TABLE IF NOT EXISTS syncapi_stream_id ( ); INSERT INTO syncapi_stream_id (stream_name, stream_id) VALUES ("global", 0) ON CONFLICT DO NOTHING; +INSERT INTO syncapi_stream_id (stream_name, stream_id) VALUES ("receipt", 0) + ON CONFLICT DO NOTHING; ` const increaseStreamIDStmt = "" + @@ -56,3 +58,13 @@ func (s *streamIDStatements) nextStreamID(ctx context.Context, txn *sql.Tx) (pos err = selectStmt.QueryRowContext(ctx, "global").Scan(&pos) return } + +func (s *streamIDStatements) nextReceiptID(ctx context.Context, txn *sql.Tx) (pos types.StreamPosition, err error) { + increaseStmt := sqlutil.TxStmt(txn, s.increaseStreamIDStmt) + selectStmt := sqlutil.TxStmt(txn, s.selectStreamIDStmt) + if _, err = increaseStmt.ExecContext(ctx, "receipt"); err != nil { + return + } + err = selectStmt.QueryRowContext(ctx, "receipt").Scan(&pos) + return +} diff --git a/syncapi/storage/sqlite3/syncserver.go b/syncapi/storage/sqlite3/syncserver.go index 7df71b38..1ad0e947 100644 --- a/syncapi/storage/sqlite3/syncserver.go +++ b/syncapi/storage/sqlite3/syncserver.go @@ -25,6 +25,7 @@ import ( "github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/syncapi/storage/shared" + "github.com/matrix-org/dendrite/syncapi/storage/sqlite3/deltas" ) // SyncServerDatasource represents a sync server datasource which manages @@ -46,13 +47,14 @@ func NewDatabase(dbProperties *config.DatabaseOptions) (*SyncServerDatasource, e return nil, err } d.writer = sqlutil.NewExclusiveWriter() - if err = d.prepare(); err != nil { + if err = d.prepare(dbProperties); err != nil { return nil, err } return &d, nil } -func (d *SyncServerDatasource) prepare() (err error) { +// nolint:gocyclo +func (d *SyncServerDatasource) prepare(dbProperties *config.DatabaseOptions) (err error) { if err = d.PartitionOffsetStatements.Prepare(d.db, d.writer, "syncapi"); err != nil { return err } @@ -99,6 +101,11 @@ func (d *SyncServerDatasource) prepare() (err error) { if err != nil { return err } + m := sqlutil.NewMigrations() + deltas.LoadFixSequences(m) + if err = m.RunDeltas(d.db, dbProperties); err != nil { + return err + } d.Database = shared.Database{ DB: d.db, Writer: d.writer, |