2020-01-03 14:07:05 +00:00
// Copyright 2017-2018 New Vector Ltd
// Copyright 2019-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,
2020-05-28 11:15:21 +01:00
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implie
2020-01-03 14:07:05 +00:00
// See the License for the specific language governing permissions and
// limitations under the License.
package postgres
import (
2022-09-09 13:14:52 +01:00
"context"
2020-01-03 14:07:05 +00:00
"database/sql"
2022-09-09 13:14:52 +01:00
"errors"
2021-04-26 13:25:57 +01:00
"fmt"
2020-03-17 15:12:01 +00:00
2022-09-09 13:14:52 +01:00
"github.com/sirupsen/logrus"
2020-11-05 10:19:23 +00:00
// Import the postgres database driver.
_ "github.com/lib/pq"
2022-08-08 09:18:57 +01:00
2020-08-25 12:32:29 +01:00
"github.com/matrix-org/dendrite/internal/caching"
2020-04-16 10:06:55 +01:00
"github.com/matrix-org/dendrite/internal/sqlutil"
2020-11-05 10:19:23 +00:00
"github.com/matrix-org/dendrite/roomserver/storage/postgres/deltas"
2020-05-26 15:42:42 +01:00
"github.com/matrix-org/dendrite/roomserver/storage/shared"
2022-05-03 16:35:06 +01:00
"github.com/matrix-org/dendrite/setup/base"
2020-12-02 17:41:00 +00:00
"github.com/matrix-org/dendrite/setup/config"
2020-01-03 14:07:05 +00:00
)
// A Database is used to store room events and stream offsets.
type Database struct {
2020-05-26 15:42:42 +01:00
shared . Database
2020-01-03 14:07:05 +00:00
}
// Open a postgres database.
2022-05-03 16:35:06 +01:00
func Open ( base * base . BaseDendrite , dbProperties * config . DatabaseOptions , cache caching . RoomServerCaches ) ( * Database , error ) {
2020-01-03 14:07:05 +00:00
var d Database
var err error
2022-05-03 16:35:06 +01:00
db , writer , err := base . DatabaseConnection ( dbProperties , sqlutil . NewDummyWriter ( ) )
if err != nil {
2021-04-26 13:25:57 +01:00
return nil , fmt . Errorf ( "sqlutil.Open: %w" , err )
2020-01-03 14:07:05 +00:00
}
2020-11-05 10:19:23 +00:00
2021-04-26 13:25:57 +01:00
// Create the tables.
2022-07-25 10:39:22 +01:00
if err = d . create ( db ) ; err != nil {
2020-11-05 10:19:23 +00:00
return nil , err
}
2021-04-26 13:25:57 +01:00
2022-07-25 10:39:22 +01:00
// Special case, since this migration uses several tables, so it needs to
// be sure that all tables are created first.
2022-09-09 13:14:52 +01:00
if err = executeMigration ( base . Context ( ) , db ) ; err != nil {
return nil , err
2020-11-05 10:19:23 +00:00
}
2021-04-26 13:25:57 +01:00
// Then prepare the statements. Now that the migrations have run, any columns referred
// to in the database code should now exist.
2022-08-08 09:18:57 +01:00
if err = d . prepare ( db , writer , cache ) ; err != nil {
2020-11-05 10:19:23 +00:00
return nil , err
}
return & d , nil
}
2022-09-09 13:14:52 +01:00
func executeMigration ( ctx context . Context , db * sql . DB ) error {
// TODO: Remove when we are sure we are not having goose artefacts in the db
// This forces an error, which indicates the migration is already applied, since the
// column event_nid was removed from the table
migrationName := "roomserver: state blocks refactor"
var cName string
err := db . QueryRowContext ( ctx , "select column_name from information_schema.columns where table_name = 'roomserver_state_block' AND column_name = 'event_nid'" ) . Scan ( & cName )
if err != nil {
if errors . Is ( err , sql . ErrNoRows ) { // migration was already executed, as the column was removed
if err = sqlutil . InsertMigration ( ctx , db , migrationName ) ; err != nil {
// not a fatal error, log and continue
logrus . WithError ( err ) . Warnf ( "unable to manually insert migration '%s'" , migrationName )
}
return nil
}
return err
}
m := sqlutil . NewMigrator ( db )
m . AddMigrations ( sqlutil . Migration {
Version : migrationName ,
Up : deltas . UpStateBlocksRefactor ,
} )
return m . Up ( ctx )
}
2021-04-26 13:25:57 +01:00
func ( d * Database ) create ( db * sql . DB ) error {
2022-05-09 14:30:32 +01:00
if err := CreateEventStateKeysTable ( db ) ; err != nil {
2021-04-26 13:25:57 +01:00
return err
}
2022-05-09 14:30:32 +01:00
if err := CreateEventTypesTable ( db ) ; err != nil {
2021-04-26 13:25:57 +01:00
return err
}
2022-05-09 14:30:32 +01:00
if err := CreateEventJSONTable ( db ) ; err != nil {
2021-04-26 13:25:57 +01:00
return err
}
2022-05-09 14:30:32 +01:00
if err := CreateEventsTable ( db ) ; err != nil {
2021-04-26 13:25:57 +01:00
return err
}
2022-05-16 18:33:16 +01:00
if err := CreateRoomsTable ( db ) ; err != nil {
2021-04-26 13:25:57 +01:00
return err
}
2022-05-16 18:33:16 +01:00
if err := CreateStateBlockTable ( db ) ; err != nil {
2021-04-26 13:25:57 +01:00
return err
}
2022-05-16 18:33:16 +01:00
if err := CreateStateSnapshotTable ( db ) ; err != nil {
2021-04-26 13:25:57 +01:00
return err
}
2022-05-10 13:41:12 +01:00
if err := CreatePrevEventsTable ( db ) ; err != nil {
2021-04-26 13:25:57 +01:00
return err
}
2022-05-16 18:33:16 +01:00
if err := CreateRoomAliasesTable ( db ) ; err != nil {
2021-04-26 13:25:57 +01:00
return err
}
2022-05-10 13:41:12 +01:00
if err := CreateInvitesTable ( db ) ; err != nil {
2021-04-26 13:25:57 +01:00
return err
}
2022-05-10 13:41:12 +01:00
if err := CreateMembershipTable ( db ) ; err != nil {
2021-04-26 13:25:57 +01:00
return err
}
2022-05-10 13:41:12 +01:00
if err := CreatePublishedTable ( db ) ; err != nil {
2021-04-26 13:25:57 +01:00
return err
}
2022-05-10 13:41:12 +01:00
if err := CreateRedactionsTable ( db ) ; err != nil {
2021-04-26 13:25:57 +01:00
return err
}
return nil
}
2022-05-03 16:35:06 +01:00
func ( d * Database ) prepare ( db * sql . DB , writer sqlutil . Writer , cache caching . RoomServerCaches ) error {
2022-05-09 14:30:32 +01:00
eventStateKeys , err := PrepareEventStateKeysTable ( db )
2020-05-26 15:42:42 +01:00
if err != nil {
2020-11-05 10:19:23 +00:00
return err
2020-05-26 15:42:42 +01:00
}
2022-05-09 14:30:32 +01:00
eventTypes , err := PrepareEventTypesTable ( db )
2020-05-26 15:42:42 +01:00
if err != nil {
2020-11-05 10:19:23 +00:00
return err
2020-05-26 15:42:42 +01:00
}
2022-05-09 14:30:32 +01:00
eventJSON , err := PrepareEventJSONTable ( db )
2020-05-26 16:45:28 +01:00
if err != nil {
2020-11-05 10:19:23 +00:00
return err
2020-05-26 16:45:28 +01:00
}
2022-05-09 14:30:32 +01:00
events , err := PrepareEventsTable ( db )
2020-05-26 16:45:28 +01:00
if err != nil {
2020-11-05 10:19:23 +00:00
return err
2020-05-26 16:45:28 +01:00
}
2022-05-16 18:33:16 +01:00
rooms , err := PrepareRoomsTable ( db )
2020-05-26 18:23:39 +01:00
if err != nil {
2020-11-05 10:19:23 +00:00
return err
2020-05-26 18:23:39 +01:00
}
2022-05-16 18:33:16 +01:00
stateBlock , err := PrepareStateBlockTable ( db )
2020-05-27 09:36:09 +01:00
if err != nil {
2020-11-05 10:19:23 +00:00
return err
2020-05-27 09:36:09 +01:00
}
2022-05-16 18:33:16 +01:00
stateSnapshot , err := PrepareStateSnapshotTable ( db )
2020-05-27 09:36:09 +01:00
if err != nil {
2020-11-05 10:19:23 +00:00
return err
2020-05-27 09:36:09 +01:00
}
2022-05-10 13:41:12 +01:00
prevEvents , err := PreparePrevEventsTable ( db )
2020-05-27 09:36:09 +01:00
if err != nil {
2020-11-05 10:19:23 +00:00
return err
2020-05-27 09:36:09 +01:00
}
2022-05-16 18:33:16 +01:00
roomAliases , err := PrepareRoomAliasesTable ( db )
2020-05-27 09:36:09 +01:00
if err != nil {
2020-11-05 10:19:23 +00:00
return err
2020-05-27 09:36:09 +01:00
}
2022-05-10 13:41:12 +01:00
invites , err := PrepareInvitesTable ( db )
2020-05-27 11:03:47 +01:00
if err != nil {
2020-11-05 10:19:23 +00:00
return err
2020-05-27 11:03:47 +01:00
}
2022-05-10 13:41:12 +01:00
membership , err := PrepareMembershipTable ( db )
2020-05-27 11:03:47 +01:00
if err != nil {
2020-11-05 10:19:23 +00:00
return err
2020-05-27 11:03:47 +01:00
}
2022-05-10 13:41:12 +01:00
published , err := PreparePublishedTable ( db )
2020-07-02 15:41:18 +01:00
if err != nil {
2020-11-05 10:19:23 +00:00
return err
2020-07-02 15:41:18 +01:00
}
2022-05-10 13:41:12 +01:00
redactions , err := PrepareRedactionsTable ( db )
2020-07-06 17:49:15 +01:00
if err != nil {
2020-11-05 10:19:23 +00:00
return err
2020-07-06 17:49:15 +01:00
}
2020-05-26 15:42:42 +01:00
d . Database = shared . Database {
2020-05-28 11:15:21 +01:00
DB : db ,
2020-08-25 12:32:29 +01:00
Cache : cache ,
2022-05-03 16:35:06 +01:00
Writer : writer ,
2020-05-28 11:15:21 +01:00
EventTypesTable : eventTypes ,
EventStateKeysTable : eventStateKeys ,
EventJSONTable : eventJSON ,
EventsTable : events ,
RoomsTable : rooms ,
2020-05-27 09:36:09 +01:00
StateBlockTable : stateBlock ,
StateSnapshotTable : stateSnapshot ,
2020-05-28 11:15:21 +01:00
PrevEventsTable : prevEvents ,
2020-05-27 09:36:09 +01:00
RoomAliasesTable : roomAliases ,
2020-05-28 11:15:21 +01:00
InvitesTable : invites ,
MembershipTable : membership ,
2020-07-02 15:41:18 +01:00
PublishedTable : published ,
2020-07-06 17:49:15 +01:00
RedactionsTable : redactions ,
2020-05-26 15:42:42 +01:00
}
2020-11-05 10:19:23 +00:00
return nil
2020-01-03 14:07:05 +00:00
}