summaryrefslogtreecommitdiff
path: root/doc/development/migration_style_guide.md
diff options
context:
space:
mode:
Diffstat (limited to 'doc/development/migration_style_guide.md')
-rw-r--r--doc/development/migration_style_guide.md29
1 files changed, 29 insertions, 0 deletions
diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md
index 0bd9979e790..d85b7372814 100644
--- a/doc/development/migration_style_guide.md
+++ b/doc/development/migration_style_guide.md
@@ -162,6 +162,9 @@ def down
end
```
+Migrations like this are inherently risky and [additional actions](database_review.md#preparation-when-adding-data-migrations)
+are required when preparing the migration for review.
+
## Atomicity
By default, migrations are single transaction. That is, a transaction is opened
@@ -769,6 +772,32 @@ to run on a large table, as long as it is only updating a small subset of the
rows in the table, but do not ignore that without validating on the GitLab.com
staging environment - or asking someone else to do so for you - beforehand.
+## Removing a foreign key constraint
+
+When removing a foreign key constraint, we need to acquire a lock on both tables
+that are related to the foreign key. For tables with heavy write patterns, it's a good
+idea to use `with_lock_retries`, otherwise you might fail to acquire a lock in time.
+You might also run into deadlocks when acquiring a lock, because ordinarily
+the application writes in `parent,child` order. However, removing a foreign
+key acquires the lock in `child,parent` order. To resolve this, you can
+explicitly acquire the lock in `parent,child`, for example:
+
+```ruby
+disable_ddl_transaction!
+
+def up
+ with_lock_retries do
+ execute('lock table ci_pipelines, ci_builds in access exclusive mode')
+
+ remove_foreign_key :ci_builds, to_table: :ci_pipelines, column: :pipeline_id, on_delete: :cascade, name: 'the_fk_name'
+ end
+end
+
+def down
+ add_concurrent_foreign_key :ci_builds, :ci_pipelines, column: :pipeline_id, on_delete: :cascade, name: 'the_fk_name'
+end
+```
+
## Dropping a database table
Dropping a database table is uncommon, and the `drop_table` method