Adapt shared lock skip logic to dbswap branch (#2437)
This commit is contained in:
1 parent
bed6e1a0ff
commit
9002930d65
2 files changed
+60
-20
No files matched your search
@@ -402,7 +402,7 @@ func (c *Command) Run(args []string) int {
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
sm, err := acquireDatabaseSharedLock(c.Context, c.Server.Database)
|
||||
sm, err := acquireSchemaManager(c.Context, c.Server.Database, c.Config.Controller.Database.SkipSharedLockAcquisition)
|
||||
if err != nil {
|
||||
c.UI.Error(fmt.Errorf("Failed to acquire database shared lock: %w", err).Error())
|
||||
return base.CommandCliError
|
||||
@@ -433,6 +433,13 @@ func (c *Command) Run(args []string) int {
|
||||
c.UI.Error(err.Error())
|
||||
return base.CommandCliError
|
||||
}
|
||||
|
||||
if c.Config.Controller.Database.SkipSharedLockAcquisition {
|
||||
if err := c.schemaManager.Close(c.Context); err != nil {
|
||||
c.UI.Error(fmt.Errorf("Unable to release shared lock to the database: %w", err).Error())
|
||||
return base.CommandCliError
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if c.Config.Controller != nil {
|
||||
@@ -874,7 +881,7 @@ func (c *Command) reloadControllerDatabase(newConfig *config.Config) error {
|
||||
}
|
||||
|
||||
// Acquire new lock on the new database and verify that it's in a good state to be used.
|
||||
newDbSchemaManager, err := acquireDatabaseSharedLock(c.Context, newDb)
|
||||
newDbSchemaManager, err := acquireSchemaManager(c.Context, newDb, c.Config.Controller.Database.SkipSharedLockAcquisition)
|
||||
if err != nil {
|
||||
_ = newDb.Close(c.Context)
|
||||
return fmt.Errorf("failed to acquire shared lock on new database: %w", err)
|
||||
@@ -887,6 +894,12 @@ func (c *Command) reloadControllerDatabase(newConfig *config.Config) error {
|
||||
return fmt.Errorf("invalid new database state: %w", err)
|
||||
}
|
||||
|
||||
if newConfig.Controller.Database.SkipSharedLockAcquisition {
|
||||
if err := newDbSchemaManager.Close(c.Context); err != nil {
|
||||
return fmt.Errorf("unable to release shared lock to the database for new schema manager: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
oldDbSchemaManager := c.schemaManager
|
||||
|
||||
// Swap underlying database with new one and update application state.
|
||||
@@ -907,10 +920,10 @@ func (c *Command) reloadControllerDatabase(newConfig *config.Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// acquireDatabaseSharedLock uses the schema manager to acquire a shared lock on
|
||||
// acquireSchemaManager returns a schema manager and generally acquires a shared lock on
|
||||
// the database. This is done as a mechanism to disallow running migration commands
|
||||
// while the database is in use.
|
||||
func acquireDatabaseSharedLock(ctx context.Context, db *db.DB) (*schema.Manager, error) {
|
||||
func acquireSchemaManager(ctx context.Context, db *db.DB, skipSharedLock bool) (*schema.Manager, error) {
|
||||
if db == nil {
|
||||
return nil, fmt.Errorf("nil database")
|
||||
}
|
||||
@@ -926,9 +939,11 @@ func acquireDatabaseSharedLock(ctx context.Context, db *db.DB) (*schema.Manager,
|
||||
}
|
||||
|
||||
// This is an advisory locks on the DB which is released when the db session ends.
|
||||
err = manager.SharedLock(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to gain shared access to the database: %w", err)
|
||||
if !skipSharedLock {
|
||||
err = manager.SharedLock(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to gain shared access to the database: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return manager, nil
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/db/schema/internal/edition"
|
||||
"github.com/hashicorp/boundary/internal/db/schema/internal/log"
|
||||
@@ -13,6 +14,7 @@ import (
|
||||
"github.com/hashicorp/boundary/internal/db/schema/internal/provider"
|
||||
"github.com/hashicorp/boundary/internal/db/schema/migration"
|
||||
"github.com/hashicorp/boundary/internal/errors"
|
||||
"github.com/hashicorp/boundary/internal/observability/event"
|
||||
)
|
||||
|
||||
// driver provides functionality to a database.
|
||||
@@ -59,11 +61,13 @@ type driver interface {
|
||||
// the underlying boundary database schema.
|
||||
// Manager is not thread safe.
|
||||
type Manager struct {
|
||||
db *sql.DB
|
||||
driver driver
|
||||
dialect string
|
||||
editions edition.Editions
|
||||
selectedRepairs RepairMigrations
|
||||
db *sql.DB
|
||||
driver driver
|
||||
dialect string
|
||||
editions edition.Editions
|
||||
selectedRepairs RepairMigrations
|
||||
sharedLockAcquired bool
|
||||
sharedLockMutex *sync.Mutex
|
||||
}
|
||||
|
||||
// NewManager creates a new schema manager. An error is returned
|
||||
@@ -79,6 +83,7 @@ func NewManager(ctx context.Context, dialect Dialect, db *sql.DB, opt ...Option)
|
||||
db: db,
|
||||
dialect: string(dialect),
|
||||
selectedRepairs: opts.withRepairMigrations,
|
||||
sharedLockMutex: new(sync.Mutex),
|
||||
}
|
||||
if opts.withEditions != nil {
|
||||
dbM.editions = opts.withEditions
|
||||
@@ -128,12 +133,16 @@ func (b *Manager) CurrentState(ctx context.Context) (*State, error) {
|
||||
// database connection afterwards.
|
||||
func (b *Manager) Close(ctx context.Context) error {
|
||||
const op = "schema.(Manager).Close"
|
||||
err := b.SharedUnlock(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
|
||||
if err := b.SharedUnlock(ctx); err != nil {
|
||||
event.WriteError(ctx, op, fmt.Errorf("error unlocking shared database lock: %w", err))
|
||||
}
|
||||
|
||||
return b.driver.Close()
|
||||
if err := b.driver.Close(); err != sql.ErrConnDone {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SharedLock attempts to obtain a shared lock on the database. This can fail
|
||||
@@ -141,9 +150,17 @@ func (b *Manager) Close(ctx context.Context) error {
|
||||
// error is returned.
|
||||
func (b *Manager) SharedLock(ctx context.Context) error {
|
||||
const op = "schema.(Manager).SharedLock"
|
||||
if err := b.driver.TrySharedLock(ctx); err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
|
||||
b.sharedLockMutex.Lock()
|
||||
defer b.sharedLockMutex.Unlock()
|
||||
|
||||
if !b.sharedLockAcquired {
|
||||
if err := b.driver.TrySharedLock(ctx); err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
b.sharedLockAcquired = true
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -152,9 +169,17 @@ func (b *Manager) SharedLock(ctx context.Context) error {
|
||||
// that is not held is not an error.
|
||||
func (b *Manager) SharedUnlock(ctx context.Context) error {
|
||||
const op = "schema.(Manager).SharedUnlock"
|
||||
if err := b.driver.UnlockShared(ctx); err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
|
||||
b.sharedLockMutex.Lock()
|
||||
defer b.sharedLockMutex.Unlock()
|
||||
|
||||
if b.sharedLockAcquired {
|
||||
if err := b.driver.UnlockShared(ctx); err != nil {
|
||||
return errors.Wrap(ctx, err, op)
|
||||
}
|
||||
b.sharedLockAcquired = false
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user