Skip to content
This repository was archived by the owner on Nov 25, 2024. It is now read-only.

Commit 0ddfb0c

Browse files
authored
Tweak InsertMigration to avoid logging (#2720)
We'd still produce logs in Postgres when trying to insert a migration we already ran. This should stop us from creating those log entries.
1 parent 852d856 commit 0ddfb0c

File tree

4 files changed

+82
-40
lines changed

4 files changed

+82
-40
lines changed

federationapi/federationapi_keys_test.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@ import (
1212
"testing"
1313
"time"
1414

15+
"github.com/matrix-org/gomatrixserverlib"
16+
1517
"github.com/matrix-org/dendrite/federationapi/api"
1618
"github.com/matrix-org/dendrite/federationapi/routing"
1719
"github.com/matrix-org/dendrite/internal/caching"
1820
"github.com/matrix-org/dendrite/setup/base"
1921
"github.com/matrix-org/dendrite/setup/config"
20-
"github.com/matrix-org/gomatrixserverlib"
2122
)
2223

2324
type server struct {
@@ -86,7 +87,12 @@ func TestMain(m *testing.M) {
8687
cfg.Global.JetStream.StoragePath = config.Path(d)
8788
cfg.Global.KeyID = serverKeyID
8889
cfg.Global.KeyValidityPeriod = s.validity
89-
cfg.FederationAPI.Database.ConnectionString = config.DataSource("file::memory:")
90+
f, err := os.CreateTemp(d, "federation_keys_test*.db")
91+
if err != nil {
92+
return -1
93+
}
94+
defer f.Close()
95+
cfg.FederationAPI.Database.ConnectionString = config.DataSource("file:" + f.Name())
9096
s.config = &cfg.FederationAPI
9197

9298
// Create a transport which redirects federation requests to

federationapi/federationapi_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ import (
1010
"testing"
1111
"time"
1212

13+
"github.com/matrix-org/gomatrix"
14+
"github.com/matrix-org/gomatrixserverlib"
15+
"github.com/nats-io/nats.go"
16+
1317
"github.com/matrix-org/dendrite/federationapi"
1418
"github.com/matrix-org/dendrite/federationapi/api"
1519
"github.com/matrix-org/dendrite/federationapi/internal"
@@ -20,9 +24,6 @@ import (
2024
"github.com/matrix-org/dendrite/setup/jetstream"
2125
"github.com/matrix-org/dendrite/test"
2226
"github.com/matrix-org/dendrite/test/testrig"
23-
"github.com/matrix-org/gomatrix"
24-
"github.com/matrix-org/gomatrixserverlib"
25-
"github.com/nats-io/nats.go"
2627
)
2728

2829
type fedRoomserverAPI struct {
@@ -271,7 +272,6 @@ func TestRoomsV3URLEscapeDoNot404(t *testing.T) {
271272
cfg.Global.ServerName = gomatrixserverlib.ServerName("localhost")
272273
cfg.Global.PrivateKey = privKey
273274
cfg.Global.JetStream.InMemory = true
274-
cfg.FederationAPI.Database.ConnectionString = config.DataSource("file::memory:")
275275
base := base.NewBaseDendrite(cfg, "Monolith")
276276
keyRing := &test.NopJSONVerifier{}
277277
// TODO: This is pretty fragile, as if anything calls anything on these nils this test will break.

internal/sqlutil/migrate.go

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,13 @@ type Migration struct {
4949
Down func(ctx context.Context, txn *sql.Tx) error
5050
}
5151

52-
// Migrator
52+
// Migrator contains fields required to run migrations.
5353
type Migrator struct {
5454
db *sql.DB
5555
migrations []Migration
5656
knownMigrations map[string]struct{}
5757
mutex *sync.Mutex
58+
insertStmt *sql.Stmt
5859
}
5960

6061
// NewMigrator creates a new DB migrator.
@@ -82,42 +83,50 @@ func (m *Migrator) AddMigrations(migrations ...Migration) {
8283

8384
// Up executes all migrations in order they were added.
8485
func (m *Migrator) Up(ctx context.Context) error {
85-
var (
86-
err error
87-
dendriteVersion = internal.VersionString()
88-
)
8986
// ensure there is a table for known migrations
9087
executedMigrations, err := m.ExecutedMigrations(ctx)
9188
if err != nil {
9289
return fmt.Errorf("unable to create/get migrations: %w", err)
9390
}
94-
91+
// ensure we close the insert statement, as it's not needed anymore
92+
defer m.close()
9593
return WithTransaction(m.db, func(txn *sql.Tx) error {
9694
for i := range m.migrations {
97-
now := time.Now().UTC().Format(time.RFC3339)
9895
migration := m.migrations[i]
9996
// Skip migration if it was already executed
10097
if _, ok := executedMigrations[migration.Version]; ok {
10198
continue
10299
}
103100
logrus.Debugf("Executing database migration '%s'", migration.Version)
104-
err = migration.Up(ctx, txn)
105-
if err != nil {
101+
102+
if err = migration.Up(ctx, txn); err != nil {
106103
return fmt.Errorf("unable to execute migration '%s': %w", migration.Version, err)
107104
}
108-
_, err = txn.ExecContext(ctx, insertVersionSQL,
109-
migration.Version,
110-
now,
111-
dendriteVersion,
112-
)
113-
if err != nil {
105+
if err = m.insertMigration(ctx, txn, migration.Version); err != nil {
114106
return fmt.Errorf("unable to insert executed migrations: %w", err)
115107
}
116108
}
117109
return nil
118110
})
119111
}
120112

113+
func (m *Migrator) insertMigration(ctx context.Context, txn *sql.Tx, migrationName string) error {
114+
if m.insertStmt == nil {
115+
stmt, err := m.db.Prepare(insertVersionSQL)
116+
if err != nil {
117+
return fmt.Errorf("unable to prepare insert statement: %w", err)
118+
}
119+
m.insertStmt = stmt
120+
}
121+
stmt := TxStmtContext(ctx, txn, m.insertStmt)
122+
_, err := stmt.ExecContext(ctx,
123+
migrationName,
124+
time.Now().Format(time.RFC3339),
125+
internal.VersionString(),
126+
)
127+
return err
128+
}
129+
121130
// ExecutedMigrations returns a map with already executed migrations in addition to creating the
122131
// migrations table, if it doesn't exist.
123132
func (m *Migrator) ExecutedMigrations(ctx context.Context) (map[string]struct{}, error) {
@@ -146,19 +155,20 @@ func (m *Migrator) ExecutedMigrations(ctx context.Context) (map[string]struct{},
146155
// inserts a migration given their name to the database.
147156
// This should only be used when manually inserting migrations.
148157
func InsertMigration(ctx context.Context, db *sql.DB, migrationName string) error {
149-
_, err := db.ExecContext(ctx, createDBMigrationsSQL)
158+
m := NewMigrator(db)
159+
defer m.close()
160+
existingMigrations, err := m.ExecutedMigrations(ctx)
150161
if err != nil {
151-
return fmt.Errorf("unable to create db_migrations: %w", err)
162+
return err
152163
}
153-
_, err = db.ExecContext(ctx, insertVersionSQL,
154-
migrationName,
155-
time.Now().Format(time.RFC3339),
156-
internal.VersionString(),
157-
)
158-
// If the migration was already executed, we'll get a unique constraint error,
159-
// return nil instead, to avoid unnecessary logging.
160-
if IsUniqueConstraintViolationErr(err) {
164+
if _, ok := existingMigrations[migrationName]; ok {
161165
return nil
162166
}
163-
return err
167+
return m.insertMigration(ctx, nil, migrationName)
168+
}
169+
170+
func (m *Migrator) close() {
171+
if m.insertStmt != nil {
172+
internal.CloseAndLogIfError(context.Background(), m.insertStmt, "unable to close insert statement")
173+
}
164174
}

internal/sqlutil/migrate_test.go

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,10 @@ import (
77
"reflect"
88
"testing"
99

10+
_ "github.com/mattn/go-sqlite3"
11+
1012
"github.com/matrix-org/dendrite/internal/sqlutil"
1113
"github.com/matrix-org/dendrite/test"
12-
_ "github.com/mattn/go-sqlite3"
1314
)
1415

1516
var dummyMigrations = []sqlutil.Migration{
@@ -81,11 +82,12 @@ func Test_migrations_Up(t *testing.T) {
8182
}
8283

8384
ctx := context.Background()
84-
for _, tt := range tests {
85-
t.Run(tt.name, func(t *testing.T) {
86-
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
87-
conStr, close := test.PrepareDBConnectionString(t, dbType)
88-
defer close()
85+
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
86+
conStr, close := test.PrepareDBConnectionString(t, dbType)
87+
defer close()
88+
89+
for _, tt := range tests {
90+
t.Run(tt.name, func(t *testing.T) {
8991
driverName := "sqlite3"
9092
if dbType == test.DBTypePostgres {
9193
driverName = "postgres"
@@ -107,6 +109,30 @@ func Test_migrations_Up(t *testing.T) {
107109
t.Errorf("expected: %+v, got %v", tt.wantResult, result)
108110
}
109111
})
110-
})
111-
}
112+
}
113+
})
114+
}
115+
116+
func Test_insertMigration(t *testing.T) {
117+
test.WithAllDatabases(t, func(t *testing.T, dbType test.DBType) {
118+
conStr, close := test.PrepareDBConnectionString(t, dbType)
119+
defer close()
120+
driverName := "sqlite3"
121+
if dbType == test.DBTypePostgres {
122+
driverName = "postgres"
123+
}
124+
125+
db, err := sql.Open(driverName, conStr)
126+
if err != nil {
127+
t.Errorf("unable to open database: %v", err)
128+
}
129+
130+
if err := sqlutil.InsertMigration(context.Background(), db, "testing"); err != nil {
131+
t.Fatalf("unable to insert migration: %s", err)
132+
}
133+
// Second insert should not return an error, as it was already executed.
134+
if err := sqlutil.InsertMigration(context.Background(), db, "testing"); err != nil {
135+
t.Fatalf("unable to insert migration: %s", err)
136+
}
137+
})
112138
}

0 commit comments

Comments
 (0)