State storage refactor (#1839)

* Hash-deduplicated state storage (and migrations) for PostgreSQL and SQLite

* Refactor droomserver database setup for migrations

* Fix conflict statements

* Update migration names

* Set a boundary for old to new block/snapshot IDs so we don't rewrite them more than once accidentally

* Create sequence if not exists

* Fix boundary queries

* Fix boundary queries

* Use Query

* Break out queries a bit

* More sequence tweaks

* Query parameters are not playing the game

* Injection escaping may not work for CREATE SEQUENCE after all

* Fix snapshot sequence name

* Use boundaried IDs in SQLite too

* Use IFNULL for SQLite

* Use COALESCE in PostgreSQL

* Review comments @Kegsay
This commit is contained in:
Neil Alexander 2021-04-26 13:25:57 +01:00 committed by GitHub
parent d6e9b7b307
commit 5ce1fe80de
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 1076 additions and 554 deletions

View file

@ -53,17 +53,22 @@ func Open(dbProperties *config.DatabaseOptions, cache caching.RoomServerCaches)
// which it will never obtain.
db.SetMaxOpenConns(20)
// Create tables before executing migrations so we don't fail if the table is missing,
// and THEN prepare statements so we don't fail due to referencing new columns
ms := membershipStatements{}
if err := ms.execSchema(db); err != nil {
// Create the tables.
if err := d.create(db); err != nil {
return nil, err
}
// Then execute the migrations. By this point the tables are created with the latest
// schemas.
m := sqlutil.NewMigrations()
deltas.LoadAddForgottenColumn(m)
deltas.LoadStateBlocksRefactor(m)
if err := m.RunDeltas(db, dbProperties); err != nil {
return nil, err
}
// Then prepare the statements. Now that the migrations have run, any columns referred
// to in the database code should now exist.
if err := d.prepare(db, cache); err != nil {
return nil, err
}
@ -71,62 +76,107 @@ func Open(dbProperties *config.DatabaseOptions, cache caching.RoomServerCaches)
return &d, nil
}
// nolint: gocyclo
func (d *Database) create(db *sql.DB) error {
if err := createEventStateKeysTable(db); err != nil {
return err
}
if err := createEventTypesTable(db); err != nil {
return err
}
if err := createEventJSONTable(db); err != nil {
return err
}
if err := createEventsTable(db); err != nil {
return err
}
if err := createRoomsTable(db); err != nil {
return err
}
if err := createTransactionsTable(db); err != nil {
return err
}
if err := createStateBlockTable(db); err != nil {
return err
}
if err := createStateSnapshotTable(db); err != nil {
return err
}
if err := createPrevEventsTable(db); err != nil {
return err
}
if err := createRoomAliasesTable(db); err != nil {
return err
}
if err := createInvitesTable(db); err != nil {
return err
}
if err := createMembershipTable(db); err != nil {
return err
}
if err := createPublishedTable(db); err != nil {
return err
}
if err := createRedactionsTable(db); err != nil {
return err
}
return nil
}
func (d *Database) prepare(db *sql.DB, cache caching.RoomServerCaches) error {
var err error
eventStateKeys, err := NewSqliteEventStateKeysTable(db)
eventStateKeys, err := prepareEventStateKeysTable(db)
if err != nil {
return err
}
eventTypes, err := NewSqliteEventTypesTable(db)
eventTypes, err := prepareEventTypesTable(db)
if err != nil {
return err
}
eventJSON, err := NewSqliteEventJSONTable(db)
eventJSON, err := prepareEventJSONTable(db)
if err != nil {
return err
}
events, err := NewSqliteEventsTable(db)
events, err := prepareEventsTable(db)
if err != nil {
return err
}
rooms, err := NewSqliteRoomsTable(db)
rooms, err := prepareRoomsTable(db)
if err != nil {
return err
}
transactions, err := NewSqliteTransactionsTable(db)
transactions, err := prepareTransactionsTable(db)
if err != nil {
return err
}
stateBlock, err := NewSqliteStateBlockTable(db)
stateBlock, err := prepareStateBlockTable(db)
if err != nil {
return err
}
stateSnapshot, err := NewSqliteStateSnapshotTable(db)
stateSnapshot, err := prepareStateSnapshotTable(db)
if err != nil {
return err
}
prevEvents, err := NewSqlitePrevEventsTable(db)
prevEvents, err := preparePrevEventsTable(db)
if err != nil {
return err
}
roomAliases, err := NewSqliteRoomAliasesTable(db)
roomAliases, err := prepareRoomAliasesTable(db)
if err != nil {
return err
}
invites, err := NewSqliteInvitesTable(db)
invites, err := prepareInvitesTable(db)
if err != nil {
return err
}
membership, err := NewSqliteMembershipTable(db)
membership, err := prepareMembershipTable(db)
if err != nil {
return err
}
published, err := NewSqlitePublishedTable(db)
published, err := preparePublishedTable(db)
if err != nil {
return err
}
redactions, err := NewSqliteRedactionsTable(db)
redactions, err := prepareRedactionsTable(db)
if err != nil {
return err
}