mirror of
https://github.com/RayLabsHQ/gitea-mirror.git
synced 2026-03-25 07:07:41 +03:00
* fix: prevent starred repo name collisions during concurrent mirroring (#95) When multiple starred repos share the same short name (e.g. alice/dotfiles and bob/dotfiles), concurrent batch mirroring could cause 409 Conflict errors because generateUniqueRepoName only checked Gitea via HTTP, missing repos that were claimed in the local DB but not yet created remotely. Three fixes: - Add DB-level check in generateUniqueRepoName so it queries the local repositories table for existing mirroredLocation claims, preventing two concurrent jobs from picking the same target name. - Clear mirroredLocation on failed mirror so a failed repo doesn't falsely hold a location that was never successfully created, which would block retries and confuse the uniqueness check. - Extract isMirroredLocationClaimedInDb helper for the DB lookup, using ne() to exclude the current repo's own record from the collision check. * fix: address review findings for starred repo name collision fix - Make generateUniqueRepoName immediately claim name by writing mirroredLocation to DB, closing the TOCTOU race window between name selection and the later status="mirroring" DB update - Add fullName validation guard (must contain "/") - Make isMirroredLocationClaimedInDb fail-closed (return true on DB error) to be conservative about preventing collisions - Scope mirroredLocation clear on failure to starred repos only, preserving it for non-starred repos that may have partially created in Gitea and need the location for recovery * fix: address P1/P2 review findings for starred repo name collision P1a: Remove early name claiming from generateUniqueRepoName to prevent stale claims on early return paths. The function now only checks availability — the actual claim happens at the status="mirroring" DB write (after both idempotency checks), which is protected by a new unique partial index. P1b: Add unique partial index on (userId, mirroredLocation) WHERE mirroredLocation != '' via migration 0010. This enforces atomicity at the DB level: if two concurrent workers try to claim the same name, the second gets a constraint violation rather than silently colliding. P2: Only clear mirroredLocation on failure if the Gitea migrate call itself failed (migrateSucceeded flag). If migrate succeeded but metadata mirroring failed, preserve the location since the repo physically exists in Gitea and we need it for recovery/retry.
10 lines
590 B
SQL
10 lines
590 B
SQL
-- Add index for mirroredLocation lookups (used by name collision detection)
|
|
CREATE INDEX IF NOT EXISTS `idx_repositories_mirrored_location` ON `repositories` (`user_id`, `mirrored_location`);
|
|
|
|
-- Add unique partial index to enforce that no two repos for the same user
|
|
-- can claim the same non-empty mirroredLocation. This prevents race conditions
|
|
-- during concurrent batch mirroring of starred repos with duplicate names.
|
|
CREATE UNIQUE INDEX IF NOT EXISTS `uniq_repositories_user_mirrored_location`
|
|
ON `repositories` (`user_id`, `mirrored_location`)
|
|
WHERE `mirrored_location` != '';
|