diff options
author | Michael Kozono <mkozono@gmail.com> | 2017-09-07 10:58:50 -0700 |
---|---|---|
committer | Michael Kozono <mkozono@gmail.com> | 2017-09-14 14:17:22 -0700 |
commit | bedcb7f43ddb8d6e2cce9424e3d988fe1d5a7cc8 (patch) | |
tree | 4fc98ac4b7c4f66f7e3c617da59c6e79cffbfbaf | |
parent | ec3b3797e789d82200de2694458cc7cde2093549 (diff) | |
download | gitlab-ce-bedcb7f43ddb8d6e2cce9424e3d988fe1d5a7cc8.tar.gz |
Delete conflicting redirects in background
-rw-r--r-- | db/post_migrate/20170907170235_delete_conflicting_redirect_routes.rb | 66 | ||||
-rw-r--r-- | lib/gitlab/background_migration/delete_conflicting_redirect_routes.rb | 52 |
2 files changed, 118 insertions, 0 deletions
diff --git a/db/post_migrate/20170907170235_delete_conflicting_redirect_routes.rb b/db/post_migrate/20170907170235_delete_conflicting_redirect_routes.rb new file mode 100644 index 00000000000..4111c884c28 --- /dev/null +++ b/db/post_migrate/20170907170235_delete_conflicting_redirect_routes.rb @@ -0,0 +1,66 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class DeleteConflictingRedirectRoutes < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + BATCH_SIZE = 1000 # Number of rows to process per job + JOB_BUFFER_SIZE = 1000 # Number of jobs to bulk queue at a time + MIGRATION = 'DeleteConflictingRedirectRoutes'.freeze + + disable_ddl_transaction! + + class Route < ActiveRecord::Base + include EachBatch + + self.table_name = 'routes' + end + + def up + jobs = [] + + say opening_message + + queue_background_migration_jobs(Route, MIGRATION) + end + + def down + # nothing + end + + def opening_message + <<~MSG + Clean up redirect routes that conflict with regular routes. + See initial bug fix: + https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/13357 + MSG + end + + def queue_background_migration_jobs(model_class, job_class_name, batch_size = BATCH_SIZE) + jobs = [] + + model_class.each_batch(of: batch_size) do |relation| + start_id, end_id = relation.pluck('MIN(id), MAX(id)').first + + # Note: This conditional will only be true if JOB_BUFFER_SIZE * batch_size < (total number of rows) + if jobs.length >= JOB_BUFFER_SIZE + # We push multiple jobs at a time to reduce the time spent in + # Sidekiq/Redis operations. We're using this buffer based approach so we + # don't need to run additional queries for every range. + bulk_queue_jobs(jobs) + jobs.clear + end + + jobs << [job_class_name, [start_id, end_id]] + end + + bulk_queue_jobs(jobs) unless jobs.empty? + end + + def bulk_queue_jobs(jobs) + say "Queuing #{jobs.size} BackgroundMigrationWorker jobs..." + + BackgroundMigrationWorker.perform_bulk(jobs) + end +end diff --git a/lib/gitlab/background_migration/delete_conflicting_redirect_routes.rb b/lib/gitlab/background_migration/delete_conflicting_redirect_routes.rb new file mode 100644 index 00000000000..c33b6d513da --- /dev/null +++ b/lib/gitlab/background_migration/delete_conflicting_redirect_routes.rb @@ -0,0 +1,52 @@ +module Gitlab + module BackgroundMigration + class DeleteConflictingRedirectRoutes + class Route < ActiveRecord::Base + self.table_name = 'routes' + end + + class RedirectRoute < ActiveRecord::Base + self.table_name = 'redirect_routes' + end + + # start_id - The start ID of the range of events to process + # end_id - The end ID of the range to process. + def perform(start_id, end_id) + return unless migrate? + + conflicts = RedirectRoute.where(routes_match_redirects_clause(start_id, end_id)) + num_rows = conflicts.delete_all + + Rails.logger.info("Gitlab::BackgroundMigration::DeleteConflictingRedirectRoutes [#{start_id}, #{end_id}] - Deleted #{num_rows} redirect routes that were conflicting with routes.") + end + + def migrate? + Route.table_exists? && RedirectRoute.table_exists? + end + + def routes_match_redirects_clause(start_id, end_id) + <<~ROUTES_MATCH_REDIRECTS + EXISTS ( + SELECT 1 FROM routes + WHERE (#{route_paths_match_redirects}) + AND routes.id BETWEEN #{start_id} AND #{end_id} + ) + ROUTES_MATCH_REDIRECTS + end + + def route_paths_match_redirects + if Gitlab::Database.postgresql? + <<~ROUTE_PATHS_MATCH_REDIRECTS + LOWER(redirect_routes.path) = LOWER(routes.path) + OR LOWER(redirect_routes.path) LIKE LOWER(CONCAT(routes.path, '/%')) + ROUTE_PATHS_MATCH_REDIRECTS + else + <<~ROUTE_PATHS_MATCH_REDIRECTS + redirect_routes.path = routes.path + OR redirect_routes.path LIKE CONCAT(routes.path, '/%') + ROUTE_PATHS_MATCH_REDIRECTS + end + end + end + end +end |