From c156030ef965bed019def3993ee21d214fe2f2ba Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Mon, 17 Jul 2017 15:23:59 +0200 Subject: [PATCH] Add a background migration to rename `uploads` in the uploads table --- ...ue_migrate_system_uploads_to_new_folder.rb | 20 ++++++++ db/schema.rb | 2 +- .../migrate_system_uploads_to_new_folder.rb | 47 +++++++++++++++++++ ...grate_system_uploads_to_new_folder_spec.rb | 19 ++++++++ 4 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 db/post_migrate/20170717150329_enqueue_migrate_system_uploads_to_new_folder.rb create mode 100644 lib/gitlab/background_migration/migrate_system_uploads_to_new_folder.rb create mode 100644 spec/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder_spec.rb diff --git a/db/post_migrate/20170717150329_enqueue_migrate_system_uploads_to_new_folder.rb b/db/post_migrate/20170717150329_enqueue_migrate_system_uploads_to_new_folder.rb new file mode 100644 index 00000000000..87069dce006 --- /dev/null +++ b/db/post_migrate/20170717150329_enqueue_migrate_system_uploads_to_new_folder.rb @@ -0,0 +1,20 @@ +class EnqueueMigrateSystemUploadsToNewFolder < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + OLD_FOLDER = 'uploads/system/' + NEW_FOLDER = 'uploads/-/system/' + + disable_ddl_transaction! + + def up + BackgroundMigrationWorker.perform_async('MigrateSystemUploadsToNewFolder', + [OLD_FOLDER, NEW_FOLDER]) + end + + def down + BackgroundMigrationWorker.perform_async('MigrateSystemUploadsToNewFolder', + [NEW_FOLDER, OLD_FOLDER]) + end +end diff --git a/db/schema.rb b/db/schema.rb index 0195d73db39..284b2068166 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170717111152) do +ActiveRecord::Schema.define(version: 20170717150329) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" diff --git a/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder.rb b/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder.rb new file mode 100644 index 00000000000..601c874bc9b --- /dev/null +++ b/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder.rb @@ -0,0 +1,47 @@ +module Gitlab + module BackgroundMigration + class MigrateSystemUploadsToNewFolder + include Gitlab::Database::MigrationHelpers + attr_reader :old_folder, :new_folder + + def perform(old_folder, new_folder) + @old_folder = old_folder + @new_folder = new_folder + + replace_sql = replace_sql(uploads[:path], old_folder, new_folder) + + while remaining_rows > 0 + sql = "UPDATE uploads "\ + "SET path = #{replace_sql} "\ + "WHERE uploads.id IN "\ + " (SELECT uploads.id FROM uploads "\ + " WHERE #{affected_uploads.to_sql} LIMIT 1000)" + connection.execute(sql) + end + end + + def uploads + Arel::Table.new('uploads') + end + + def remaining_rows + remaining_result = connection.exec_query("SELECT count(id) FROM uploads WHERE #{affected_uploads.to_sql}") + remaining = remaining_result.first['count'].to_i + logger.info "#{remaining} uploads remaining" + remaining + end + + def affected_uploads + uploads[:path].matches("#{old_folder}%") + end + + def connection + ActiveRecord::Base.connection + end + + def logger + Sidekiq.logger || Rails.logger || Logger.new(STDOUT) + end + end + end +end diff --git a/spec/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder_spec.rb b/spec/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder_spec.rb new file mode 100644 index 00000000000..a910fb105a5 --- /dev/null +++ b/spec/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe Gitlab::BackgroundMigration::MigrateSystemUploadsToNewFolder do + let(:migration) { described_class.new } + + before do + allow(migration).to receive(:logger).and_return(Logger.new(nil)) + end + + describe '#perform' do + it 'renames the path of system-uploads', truncate: true do + upload = create(:upload, model: create(:empty_project), path: 'uploads/system/project/avatar.jpg') + + migration.perform('uploads/system/', 'uploads/-/system/') + + expect(upload.reload.path).to eq('uploads/-/system/project/avatar.jpg') + end + end +end