Commit 650567e0 authored by Andreas Brandl's avatar Andreas Brandl

Simplify migration and use plain SQL

parent 9e273eae
......@@ -3,7 +3,7 @@
class FixProjectsWithoutProjectFeature < ActiveRecord::Migration[5.2]
include Gitlab::Database::MigrationHelpers
BATCH_SIZE = 100_000
BATCH_SIZE = 50_000
disable_ddl_transaction!
......
......@@ -2,61 +2,59 @@
module Gitlab
module BackgroundMigration
# Project model for this migration
class Project < ActiveRecord::Base
include EachBatch
end
ENABLED = 20
INSERT_BATCH_SIZE = 10_000
# This migration creates missing project_features records
# for the projects within the given range of ids
class FixProjectsWithoutProjectFeature
def perform(from_id, to_id)
Project.transaction do
projects = Project.where(<<~SQL, from_id, to_id)
projects.id BETWEEN ? AND ?
AND NOT EXISTS (
SELECT 1 FROM project_features
WHERE project_features.project_id = projects.id
)
SQL
projects.each_batch(of: INSERT_BATCH_SIZE) do |batch|
insert_missing_records(batch)
end
if number_of_created_records = create_missing!(from_id, to_id) > 0
log(number_of_created_records, from_id, to_id)
end
end
private
def insert_missing_records(projects)
features = projects.map do |project|
record = {
project_id: project.id,
merge_requests_access_level: ENABLED,
issues_access_level: ENABLED,
wiki_access_level: ENABLED,
snippets_access_level: ENABLED,
builds_access_level: ENABLED,
repository_access_level: ENABLED,
pages_access_level: ENABLED,
forking_access_level: ENABLED
}
record['created_at'] = record['updated_at'] = Time.now.to_s(:db)
def create_missing!(from_id, to_id)
result = ActiveRecord::Base.connection.select_one(sql, nil, [[nil, from_id], [nil, to_id]])
return 0 unless result
record
end
Gitlab::Database.bulk_insert(:project_features, features, on_conflict: :do_nothing)
result['number_of_created_records']
end
logger.info(message: "FixProjectsWithoutProjectFeature: created missing project_features for Projects #{projects.map(&:id).join(', ')}")
def sql
<<~SQL
WITH created_records AS (
INSERT INTO project_features (
project_id,
merge_requests_access_level,
issues_access_level,
wiki_access_level,
snippets_access_level,
builds_access_level,
repository_access_level,
pages_access_level,
forking_access_level,
created_at,
updated_at
)
SELECT projects.id, 20, 20, 20, 20, 20, 20, 20, 20, NOW(), NOW()
FROM projects
WHERE projects.id BETWEEN $1 AND $2
AND NOT EXISTS (
SELECT 1 FROM project_features
WHERE project_features.project_id = projects.id
)
ON CONFLICT (project_id) DO NOTHING
RETURNING *
)
SELECT COUNT(*) as number_of_created_records
FROM created_records
SQL
end
def logger
@logger ||= Gitlab::BackgroundMigration::Logger.build
def log(count, from_id, to_id)
logger = Gitlab::BackgroundMigration::Logger.build
logger.info(message: "FixProjectsWithoutProjectFeature: created missing project_features for #{count} projects in id=#{from_id}...#{to_id}")
end
end
end
......
......@@ -25,10 +25,30 @@ describe Gitlab::BackgroundMigration::FixProjectsWithoutProjectFeature, :migrati
ActiveRecord::Base.connection.select_one('SELECT MIN(id), MAX(id) FROM projects').values
end
it 'creates a default ProjectFeature for projects without it' do
it 'creates a ProjectFeature for projects without it' do
expect { subject }.to change { project_feature_records }.from([project.id]).to([project.id, *projects_without_feature.map(&:id)])
end
it 'creates ProjectFeature records with default values' do
subject
project_id = projects_without_feature.first.id
record = ActiveRecord::Base.connection.select_one('SELECT * FROM project_features WHERE id=$1', nil, [[nil, project_id]])
expect(record.except('id', 'project_id', 'created_at', 'updated_at')).to eq(
{
"merge_requests_access_level" => 20,
"issues_access_level" => 20,
"wiki_access_level" => 20,
"snippets_access_level" => 20,
"builds_access_level" => 20,
"repository_access_level" => 20,
"pages_access_level" => 20,
"forking_access_level" => 20
}
)
end
it 'sets created_at/updated_at timestamps' do
subject
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment