bd-109: Add retry logic and race condition handling for N-way collisions
- Added ExecInTransaction helper for atomic database operations - Added IsUniqueConstraintError to detect UNIQUE constraint violations - Wrapped RemapCollisions with retry logic (3 attempts with counter sync) - Enhanced handleRename to detect race conditions where target ID exists - Added defensive checks for when old ID has been deleted by another clone Progress: Improves N-way collision handling, though full solution requires more work (tracked in bd-108). Tests now reach later convergence rounds before hitting complex collision scenarios. Amp-Thread-ID: https://ampcode.com/threads/T-2b850a80-f8bd-4e38-b661-e33d1cfa7281 Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
@@ -3,6 +3,8 @@ package sqlite
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// QueryContext exposes the underlying database QueryContext method for advanced queries
|
||||
@@ -16,3 +18,37 @@ func (s *SQLiteStorage) QueryContext(ctx context.Context, query string, args ...
|
||||
func (s *SQLiteStorage) BeginTx(ctx context.Context) (*sql.Tx, error) {
|
||||
return s.db.BeginTx(ctx, nil)
|
||||
}
|
||||
|
||||
// ExecInTransaction executes a function within a database transaction.
|
||||
// If the function returns an error, the transaction is rolled back.
|
||||
// Otherwise, the transaction is committed.
|
||||
func (s *SQLiteStorage) ExecInTransaction(ctx context.Context, fn func(*sql.Tx) error) error {
|
||||
tx, err := s.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to begin transaction: %w", err)
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
|
||||
if err := fn(tx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return fmt.Errorf("failed to commit transaction: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsUniqueConstraintError checks if an error is a UNIQUE constraint violation
|
||||
func IsUniqueConstraintError(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
return strings.Contains(err.Error(), "UNIQUE constraint failed")
|
||||
}
|
||||
|
||||
// isUniqueConstraintError is an alias for IsUniqueConstraintError for internal use
|
||||
func isUniqueConstraintError(err error) bool {
|
||||
return IsUniqueConstraintError(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user