mirror of
https://github.com/go-gitea/gitea.git
synced 2025-03-14 18:25:37 +08:00
Add global lock for migrations to make upgrade more safe with multiple replications (#33706)
This commit is contained in:
parent
b8c2afdc5f
commit
1b2dffff8e
@ -4,6 +4,7 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
golog "log"
|
golog "log"
|
||||||
"os"
|
"os"
|
||||||
@ -130,8 +131,8 @@ func runRecreateTable(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
recreateTables := migrate_base.RecreateTables(beans...)
|
recreateTables := migrate_base.RecreateTables(beans...)
|
||||||
|
|
||||||
return db.InitEngineWithMigration(stdCtx, func(x *xorm.Engine) error {
|
return db.InitEngineWithMigration(stdCtx, func(ctx context.Context, x *xorm.Engine) error {
|
||||||
if err := migrations.EnsureUpToDate(x); err != nil {
|
if err := migrations.EnsureUpToDate(ctx, x); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return recreateTables(x)
|
return recreateTables(x)
|
||||||
|
@ -7,9 +7,9 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/migrations"
|
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/services/versioned_migration"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
@ -36,7 +36,7 @@ func runMigrate(ctx *cli.Context) error {
|
|||||||
log.Info("Log path: %s", setting.Log.RootPath)
|
log.Info("Log path: %s", setting.Log.RootPath)
|
||||||
log.Info("Configuration file: %s", setting.CustomConf)
|
log.Info("Configuration file: %s", setting.CustomConf)
|
||||||
|
|
||||||
if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil {
|
if err := db.InitEngineWithMigration(context.Background(), versioned_migration.Migrate); err != nil {
|
||||||
log.Fatal("Failed to initialize ORM engine: %v", err)
|
log.Fatal("Failed to initialize ORM engine: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ import (
|
|||||||
actions_model "code.gitea.io/gitea/models/actions"
|
actions_model "code.gitea.io/gitea/models/actions"
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
git_model "code.gitea.io/gitea/models/git"
|
git_model "code.gitea.io/gitea/models/git"
|
||||||
"code.gitea.io/gitea/models/migrations"
|
|
||||||
packages_model "code.gitea.io/gitea/models/packages"
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
repo_model "code.gitea.io/gitea/models/repo"
|
repo_model "code.gitea.io/gitea/models/repo"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
@ -21,6 +20,7 @@ import (
|
|||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/storage"
|
"code.gitea.io/gitea/modules/storage"
|
||||||
|
"code.gitea.io/gitea/services/versioned_migration"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
@ -227,7 +227,7 @@ func runMigrateStorage(ctx *cli.Context) error {
|
|||||||
log.Info("Log path: %s", setting.Log.RootPath)
|
log.Info("Log path: %s", setting.Log.RootPath)
|
||||||
log.Info("Configuration file: %s", setting.CustomConf)
|
log.Info("Configuration file: %s", setting.CustomConf)
|
||||||
|
|
||||||
if err := db.InitEngineWithMigration(context.Background(), migrations.Migrate); err != nil {
|
if err := db.InitEngineWithMigration(context.Background(), versioned_migration.Migrate); err != nil {
|
||||||
log.Fatal("Failed to initialize ORM engine: %v", err)
|
log.Fatal("Failed to initialize ORM engine: %v", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ func UnsetDefaultEngine() {
|
|||||||
// When called from the "doctor" command, the migration function is a version check
|
// When called from the "doctor" command, the migration function is a version check
|
||||||
// that prevents the doctor from fixing anything in the database if the migration level
|
// that prevents the doctor from fixing anything in the database if the migration level
|
||||||
// is different from the expected value.
|
// is different from the expected value.
|
||||||
func InitEngineWithMigration(ctx context.Context, migrateFunc func(*xorm.Engine) error) (err error) {
|
func InitEngineWithMigration(ctx context.Context, migrateFunc func(context.Context, *xorm.Engine) error) (err error) {
|
||||||
if err = InitEngine(ctx); err != nil {
|
if err = InitEngine(ctx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -122,7 +122,7 @@ func InitEngineWithMigration(ctx context.Context, migrateFunc func(*xorm.Engine)
|
|||||||
// Installation should only be being re-run if users want to recover an old database.
|
// Installation should only be being re-run if users want to recover an old database.
|
||||||
// However, we should think carefully about should we support re-install on an installed instance,
|
// However, we should think carefully about should we support re-install on an installed instance,
|
||||||
// as there may be other problems due to secret reinitialization.
|
// as there may be other problems due to secret reinitialization.
|
||||||
if err = migrateFunc(xormEngine); err != nil {
|
if err = migrateFunc(ctx, xormEngine); err != nil {
|
||||||
return fmt.Errorf("migrate: %w", err)
|
return fmt.Errorf("migrate: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,7 +413,7 @@ func ExpectedDBVersion() int64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EnsureUpToDate will check if the db is at the correct version
|
// EnsureUpToDate will check if the db is at the correct version
|
||||||
func EnsureUpToDate(x *xorm.Engine) error {
|
func EnsureUpToDate(ctx context.Context, x *xorm.Engine) error {
|
||||||
currentDB, err := GetCurrentDBVersion(x)
|
currentDB, err := GetCurrentDBVersion(x)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/setting/config"
|
"code.gitea.io/gitea/modules/setting/config"
|
||||||
|
"code.gitea.io/gitea/services/versioned_migration"
|
||||||
|
|
||||||
"xorm.io/xorm"
|
"xorm.io/xorm"
|
||||||
)
|
)
|
||||||
@ -41,16 +42,16 @@ func InitDBEngine(ctx context.Context) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func migrateWithSetting(x *xorm.Engine) error {
|
func migrateWithSetting(ctx context.Context, x *xorm.Engine) error {
|
||||||
if setting.Database.AutoMigration {
|
if setting.Database.AutoMigration {
|
||||||
return migrations.Migrate(x)
|
return versioned_migration.Migrate(ctx, x)
|
||||||
}
|
}
|
||||||
|
|
||||||
if current, err := migrations.GetCurrentDBVersion(x); err != nil {
|
if current, err := migrations.GetCurrentDBVersion(x); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if current < 0 {
|
} else if current < 0 {
|
||||||
// execute migrations when the database isn't initialized even if AutoMigration is false
|
// execute migrations when the database isn't initialized even if AutoMigration is false
|
||||||
return migrations.Migrate(x)
|
return versioned_migration.Migrate(ctx, x)
|
||||||
} else if expected := migrations.ExpectedDBVersion(); current != expected {
|
} else if expected := migrations.ExpectedDBVersion(); current != expected {
|
||||||
log.Fatal(`"database.AUTO_MIGRATION" is disabled, but current database version %d is not equal to the expected version %d.`+
|
log.Fatal(`"database.AUTO_MIGRATION" is disabled, but current database version %d is not equal to the expected version %d.`+
|
||||||
`You can set "database.AUTO_MIGRATION" to true or migrate manually by running "gitea [--config /path/to/app.ini] migrate"`, current, expected)
|
`You can set "database.AUTO_MIGRATION" to true or migrate manually by running "gitea [--config /path/to/app.ini] migrate"`, current, expected)
|
||||||
|
@ -17,7 +17,6 @@ import (
|
|||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
db_install "code.gitea.io/gitea/models/db/install"
|
db_install "code.gitea.io/gitea/models/db/install"
|
||||||
"code.gitea.io/gitea/models/migrations"
|
|
||||||
system_model "code.gitea.io/gitea/models/system"
|
system_model "code.gitea.io/gitea/models/system"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/auth/password/hash"
|
"code.gitea.io/gitea/modules/auth/password/hash"
|
||||||
@ -37,6 +36,7 @@ import (
|
|||||||
auth_service "code.gitea.io/gitea/services/auth"
|
auth_service "code.gitea.io/gitea/services/auth"
|
||||||
"code.gitea.io/gitea/services/context"
|
"code.gitea.io/gitea/services/context"
|
||||||
"code.gitea.io/gitea/services/forms"
|
"code.gitea.io/gitea/services/forms"
|
||||||
|
"code.gitea.io/gitea/services/versioned_migration"
|
||||||
|
|
||||||
"gitea.com/go-chi/session"
|
"gitea.com/go-chi/session"
|
||||||
)
|
)
|
||||||
@ -359,7 +359,7 @@ func SubmitInstall(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Init the engine with migration
|
// Init the engine with migration
|
||||||
if err = db.InitEngineWithMigration(ctx, migrations.Migrate); err != nil {
|
if err = db.InitEngineWithMigration(ctx, versioned_migration.Migrate); err != nil {
|
||||||
db.UnsetDefaultEngine()
|
db.UnsetDefaultEngine()
|
||||||
ctx.Data["Err_DbSetting"] = true
|
ctx.Data["Err_DbSetting"] = true
|
||||||
ctx.RenderWithErr(ctx.Tr("install.invalid_db_setting", err), tplInstall, &form)
|
ctx.RenderWithErr(ctx.Tr("install.invalid_db_setting", err), tplInstall, &form)
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
"code.gitea.io/gitea/models/migrations"
|
"code.gitea.io/gitea/models/migrations"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/services/versioned_migration"
|
||||||
)
|
)
|
||||||
|
|
||||||
func checkDBVersion(ctx context.Context, logger log.Logger, autofix bool) error {
|
func checkDBVersion(ctx context.Context, logger log.Logger, autofix bool) error {
|
||||||
@ -21,7 +22,7 @@ func checkDBVersion(ctx context.Context, logger log.Logger, autofix bool) error
|
|||||||
logger.Warn("Got Error: %v during ensure up to date", err)
|
logger.Warn("Got Error: %v during ensure up to date", err)
|
||||||
logger.Warn("Attempting to migrate to the latest DB version to fix this.")
|
logger.Warn("Attempting to migrate to the latest DB version to fix this.")
|
||||||
|
|
||||||
err = db.InitEngineWithMigration(ctx, migrations.Migrate)
|
err = db.InitEngineWithMigration(ctx, versioned_migration.Migrate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Critical("Error: %v during migration", err)
|
logger.Critical("Error: %v during migration", err)
|
||||||
}
|
}
|
||||||
|
24
services/versioned_migration/migration.go
Normal file
24
services/versioned_migration/migration.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// Copyright 2025 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package versioned_migration //nolint
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models/migrations"
|
||||||
|
"code.gitea.io/gitea/modules/globallock"
|
||||||
|
|
||||||
|
"xorm.io/xorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Migrate(ctx context.Context, x *xorm.Engine) error {
|
||||||
|
// only one instance can do the migration at the same time if there are multiple instances
|
||||||
|
release, err := globallock.Lock(ctx, "gitea_versioned_migration")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer release()
|
||||||
|
|
||||||
|
return migrations.Migrate(x)
|
||||||
|
}
|
@ -5,6 +5,7 @@ package migrations
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"compress/gzip"
|
"compress/gzip"
|
||||||
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
@ -247,7 +248,7 @@ func restoreOldDB(t *testing.T, version string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func wrappedMigrate(x *xorm.Engine) error {
|
func wrappedMigrate(ctx context.Context, x *xorm.Engine) error {
|
||||||
currentEngine = x
|
currentEngine = x
|
||||||
return migrations.Migrate(x)
|
return migrations.Migrate(x)
|
||||||
}
|
}
|
||||||
@ -264,7 +265,7 @@ func doMigrationTest(t *testing.T, version string) {
|
|||||||
|
|
||||||
beans, _ := db.NamesToBean()
|
beans, _ := db.NamesToBean()
|
||||||
|
|
||||||
err = db.InitEngineWithMigration(t.Context(), func(x *xorm.Engine) error {
|
err = db.InitEngineWithMigration(t.Context(), func(ctx context.Context, x *xorm.Engine) error {
|
||||||
currentEngine = x
|
currentEngine = x
|
||||||
return migrate_base.RecreateTables(beans...)(x)
|
return migrate_base.RecreateTables(beans...)(x)
|
||||||
})
|
})
|
||||||
@ -272,7 +273,7 @@ func doMigrationTest(t *testing.T, version string) {
|
|||||||
currentEngine.Close()
|
currentEngine.Close()
|
||||||
|
|
||||||
// We do this a second time to ensure that there is not a problem with retained indices
|
// We do this a second time to ensure that there is not a problem with retained indices
|
||||||
err = db.InitEngineWithMigration(t.Context(), func(x *xorm.Engine) error {
|
err = db.InitEngineWithMigration(t.Context(), func(ctx context.Context, x *xorm.Engine) error {
|
||||||
currentEngine = x
|
currentEngine = x
|
||||||
return migrate_base.RecreateTables(beans...)(x)
|
return migrate_base.RecreateTables(beans...)(x)
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user