mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-16 07:16:38 +00:00
[management] remove GLOBAL when disabling foreign keys on mysql (#4615)
This commit is contained in:
@@ -85,12 +85,7 @@ func NewSqlStore(ctx context.Context, db *gorm.DB, storeEngine types.Engine, met
|
||||
conns = runtime.NumCPU()
|
||||
}
|
||||
|
||||
switch storeEngine {
|
||||
case types.MysqlStoreEngine:
|
||||
if err := db.Exec("SET GLOBAL FOREIGN_KEY_CHECKS = 0").Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case types.SqliteStoreEngine:
|
||||
if storeEngine == types.SqliteStoreEngine {
|
||||
if err == nil {
|
||||
log.WithContext(ctx).Warnf("setting NB_SQL_MAX_OPEN_CONNS is not supported for sqlite, using default value 1")
|
||||
}
|
||||
@@ -175,7 +170,7 @@ func (s *SqlStore) SaveAccount(ctx context.Context, account *types.Account) erro
|
||||
group.StoreGroupPeers()
|
||||
}
|
||||
|
||||
err := s.db.Transaction(func(tx *gorm.DB) error {
|
||||
err := s.transaction(func(tx *gorm.DB) error {
|
||||
result := tx.Select(clause.Associations).Delete(account.Policies, "account_id = ?", account.Id)
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
@@ -270,7 +265,7 @@ func (s *SqlStore) checkAccountDomainBeforeSave(ctx context.Context, accountID,
|
||||
func (s *SqlStore) DeleteAccount(ctx context.Context, account *types.Account) error {
|
||||
start := time.Now()
|
||||
|
||||
err := s.db.Transaction(func(tx *gorm.DB) error {
|
||||
err := s.transaction(func(tx *gorm.DB) error {
|
||||
result := tx.Select(clause.Associations).Delete(account.Policies, "account_id = ?", account.Id)
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
@@ -324,7 +319,7 @@ func (s *SqlStore) SavePeer(ctx context.Context, accountID string, peer *nbpeer.
|
||||
peerCopy := peer.Copy()
|
||||
peerCopy.AccountID = accountID
|
||||
|
||||
err := s.db.Transaction(func(tx *gorm.DB) error {
|
||||
err := s.transaction(func(tx *gorm.DB) error {
|
||||
// check if peer exists before saving
|
||||
var peerID string
|
||||
result := tx.Model(&nbpeer.Peer{}).Select("id").Take(&peerID, accountAndIDQueryCondition, accountID, peer.ID)
|
||||
@@ -613,7 +608,7 @@ func (s *SqlStore) GetUserByUserID(ctx context.Context, lockStrength LockingStre
|
||||
}
|
||||
|
||||
func (s *SqlStore) DeleteUser(ctx context.Context, accountID, userID string) error {
|
||||
err := s.db.Transaction(func(tx *gorm.DB) error {
|
||||
err := s.transaction(func(tx *gorm.DB) error {
|
||||
result := tx.Delete(&types.PersonalAccessToken{}, "user_id = ?", userID)
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
@@ -2932,6 +2927,16 @@ func (s *SqlStore) ExecuteInTransaction(ctx context.Context, operation func(stor
|
||||
if tx.Error != nil {
|
||||
return tx.Error
|
||||
}
|
||||
|
||||
// For MySQL, disable FK checks within this transaction to avoid deadlocks
|
||||
// This is session-scoped and doesn't require SUPER privileges
|
||||
if s.storeEngine == types.MysqlStoreEngine {
|
||||
if err := tx.Exec("SET FOREIGN_KEY_CHECKS = 0").Error; err != nil {
|
||||
tx.Rollback()
|
||||
return fmt.Errorf("failed to disable FK checks: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
repo := s.withTx(tx)
|
||||
err := operation(repo)
|
||||
if err != nil {
|
||||
@@ -2939,6 +2944,14 @@ func (s *SqlStore) ExecuteInTransaction(ctx context.Context, operation func(stor
|
||||
return err
|
||||
}
|
||||
|
||||
// Re-enable FK checks before commit (optional, as transaction end resets it)
|
||||
if s.storeEngine == types.MysqlStoreEngine {
|
||||
if err := tx.Exec("SET FOREIGN_KEY_CHECKS = 1").Error; err != nil {
|
||||
tx.Rollback()
|
||||
return fmt.Errorf("failed to re-enable FK checks: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
err = tx.Commit().Error
|
||||
|
||||
log.WithContext(ctx).Tracef("transaction took %v", time.Since(startTime))
|
||||
@@ -2956,6 +2969,31 @@ func (s *SqlStore) withTx(tx *gorm.DB) Store {
|
||||
}
|
||||
}
|
||||
|
||||
// transaction wraps a GORM transaction with MySQL-specific FK checks handling
|
||||
// Use this instead of db.Transaction() directly to avoid deadlocks on MySQL/Aurora
|
||||
func (s *SqlStore) transaction(fn func(*gorm.DB) error) error {
|
||||
return s.db.Transaction(func(tx *gorm.DB) error {
|
||||
// For MySQL, disable FK checks within this transaction to avoid deadlocks
|
||||
// This is session-scoped and doesn't require SUPER privileges
|
||||
if s.storeEngine == types.MysqlStoreEngine {
|
||||
if err := tx.Exec("SET FOREIGN_KEY_CHECKS = 0").Error; err != nil {
|
||||
return fmt.Errorf("failed to disable FK checks: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
err := fn(tx)
|
||||
|
||||
// Re-enable FK checks before commit (optional, as transaction end resets it)
|
||||
if s.storeEngine == types.MysqlStoreEngine && err == nil {
|
||||
if fkErr := tx.Exec("SET FOREIGN_KEY_CHECKS = 1").Error; fkErr != nil {
|
||||
return fmt.Errorf("failed to re-enable FK checks: %w", fkErr)
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func (s *SqlStore) GetDB() *gorm.DB {
|
||||
return s.db
|
||||
}
|
||||
@@ -3212,7 +3250,7 @@ func (s *SqlStore) SavePolicy(ctx context.Context, policy *types.Policy) error {
|
||||
}
|
||||
|
||||
func (s *SqlStore) DeletePolicy(ctx context.Context, accountID, policyID string) error {
|
||||
return s.db.Transaction(func(tx *gorm.DB) error {
|
||||
return s.transaction(func(tx *gorm.DB) error {
|
||||
if err := tx.Where("policy_id = ?", policyID).Delete(&types.PolicyRule{}).Error; err != nil {
|
||||
return fmt.Errorf("delete policy rules: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user