瀏覽代碼

Revert "chore(db): update schema version in the same transaction as migration (#10321)"

This reverts commit 4459438245de4e114047756bb9debfe1634116eb.
Jakob Borg 1 月之前
父節點
當前提交
21ad99c80a
共有 2 個文件被更改,包括 27 次插入72 次删除
  1. 24 68
      internal/db/sqlite/basedb.go
  2. 3 4
      internal/db/sqlite/sql/README.md

+ 24 - 68
internal/db/sqlite/basedb.go

@@ -7,14 +7,11 @@
 package sqlite
 
 import (
-	"cmp"
 	"database/sql"
 	"embed"
 	"io/fs"
-	"log/slog"
 	"net/url"
 	"path/filepath"
-	"slices"
 	"strconv"
 	"strings"
 	"sync"
@@ -22,7 +19,6 @@ import (
 	"time"
 
 	"github.com/jmoiron/sqlx"
-	"github.com/syncthing/syncthing/internal/slogutil"
 	"github.com/syncthing/syncthing/lib/build"
 	"github.com/syncthing/syncthing/lib/protocol"
 )
@@ -46,7 +42,6 @@ type baseDB struct {
 	tplInput      map[string]any
 }
 
-//nolint:noctx
 func openBase(path string, maxConns int, pragmas, schemaScripts, migrationScripts []string) (*baseDB, error) {
 	// Open the database with options to enable foreign keys and recursive
 	// triggers (needed for the delete+insert triggers on row replace).
@@ -95,29 +90,20 @@ func openBase(path string, maxConns int, pragmas, schemaScripts, migrationScript
 	ver, _ := db.getAppliedSchemaVersion()
 	shouldVacuum := false
 	if ver.SchemaVersion > 0 {
-		type migration struct {
-			script  string
-			version int
-		}
-		migrations := make([]migration, 0, len(migrationScripts))
-		for _, script := range migrationScripts {
-			base := filepath.Base(script)
-			nstr, _, ok := strings.Cut(base, "-")
+		filter := func(scr string) bool {
+			scr = filepath.Base(scr)
+			nstr, _, ok := strings.Cut(scr, "-")
 			if !ok {
-				continue
+				return false
 			}
 			n, err := strconv.ParseInt(nstr, 10, 32)
 			if err != nil {
-				continue
+				return false
 			}
-			migrations = append(migrations, migration{
-				script:  script,
-				version: int(n),
-			})
+			return int(n) > ver.SchemaVersion
 		}
-		slices.SortFunc(migrations, func(m1, m2 migration) int { return cmp.Compare(m1.version, m2.version) })
-		for _, m := range migrations {
-			if err := db.applyMigration(m.version, m.script); err != nil {
+		for _, script := range migrationScripts {
+			if err := db.runScripts(script, filter); err != nil {
 				return nil, wrap(err)
 			}
 			shouldVacuum = true
@@ -125,7 +111,7 @@ func openBase(path string, maxConns int, pragmas, schemaScripts, migrationScript
 	}
 
 	// Set the current schema version, if not already set
-	if err := setAppliedSchemaVersion(currentSchemaVersion, db.sql); err != nil {
+	if err := db.setAppliedSchemaVersion(currentSchemaVersion); err != nil {
 		return nil, wrap(err)
 	}
 
@@ -242,7 +228,6 @@ func (f failedStmt) Get(_ any, _ ...any) error           { return f.err }
 func (f failedStmt) Queryx(_ ...any) (*sqlx.Rows, error) { return nil, f.err }
 func (f failedStmt) Select(_ any, _ ...any) error        { return f.err }
 
-//nolint:noctx
 func (s *baseDB) runScripts(glob string, filter ...func(s string) bool) error {
 	scripts, err := fs.Glob(embedded, glob)
 	if err != nil {
@@ -262,53 +247,24 @@ nextScript:
 				continue nextScript
 			}
 		}
-		if err := s.execScript(tx, scr); err != nil {
-			return wrap(err)
+		bs, err := fs.ReadFile(embedded, scr)
+		if err != nil {
+			return wrap(err, scr)
+		}
+		// SQLite requires one statement per exec, so we split the init
+		// files on lines containing only a semicolon and execute them
+		// separately. We require it on a separate line because there are
+		// also statement-internal semicolons in the triggers.
+		for _, stmt := range strings.Split(string(bs), "\n;") {
+			if _, err := tx.Exec(s.expandTemplateVars(stmt)); err != nil {
+				return wrap(err, stmt)
+			}
 		}
 	}
 
 	return wrap(tx.Commit())
 }
 
-//nolint:noctx
-func (s *baseDB) applyMigration(ver int, script string) error {
-	tx, err := s.sql.Begin()
-	if err != nil {
-		return wrap(err)
-	}
-	defer tx.Rollback() //nolint:errcheck
-
-	slog.Info("Applying database migration", slogutil.FilePath(s.baseName), "toSchema", ver, "script", script)
-
-	if err := s.execScript(tx, script); err != nil {
-		return wrap(err)
-	}
-
-	if err := setAppliedSchemaVersion(ver, tx); err != nil {
-		return wrap(err)
-	}
-
-	return wrap(tx.Commit())
-}
-
-//nolint:noctx
-func (s *baseDB) execScript(tx *sql.Tx, scr string) error {
-	bs, err := fs.ReadFile(embedded, scr)
-	if err != nil {
-		return wrap(err, scr)
-	}
-	// SQLite requires one statement per exec, so we split the init
-	// files on lines containing only a semicolon and execute them
-	// separately. We require it on a separate line because there are
-	// also statement-internal semicolons in the triggers.
-	for _, stmt := range strings.Split(string(bs), "\n;") {
-		if _, err := tx.Exec(s.expandTemplateVars(stmt)); err != nil {
-			return wrap(err, stmt)
-		}
-	}
-	return nil
-}
-
 type schemaVersion struct {
 	SchemaVersion    int
 	AppliedAt        int64
@@ -319,11 +275,11 @@ func (s *schemaVersion) AppliedTime() time.Time {
 	return time.Unix(0, s.AppliedAt)
 }
 
-func setAppliedSchemaVersion(ver int, execer sqlx.Execer) error {
-	_, err := execer.Exec(`
+func (s *baseDB) setAppliedSchemaVersion(ver int) error {
+	_, err := s.stmt(`
 		INSERT OR IGNORE INTO schemamigrations (schema_version, applied_at, syncthing_version)
 		VALUES (?, ?, ?)
-	`, ver, time.Now().UnixNano(), build.LongVersion)
+	`).Exec(ver, time.Now().UnixNano(), build.LongVersion)
 	return wrap(err)
 }
 

+ 3 - 4
internal/db/sqlite/sql/README.md

@@ -2,8 +2,7 @@ These SQL scripts are embedded in the binary.
 
 Scripts in `schema/` are run at every startup, in alphanumerical order.
 
-Scripts in `migrations/` are run when a migration is needed; they must begin
+Scripts in `migrations/` are run when a migration is needed; the must begin
 with a number that equals the schema version that results from that
-migration. Only one script per schema version must exist.
-Migrations are not run on initial database creation, so the scripts in `schema/`
-should create the latest version.
+migration. Migrations are not run on initial database creation, so the
+scripts in `schema/` should create the latest version.