Flush InternalId records after import
After the import has finished, we flush (delete) the InternalId records related to the project at hand. This means we're starting over with tracking correct internal id values, a new record will be created automatically when the next internal id is generated. The GitHub importer assigns iid values by using supplied values from GitHub. We skip tracking internal id values during the import in favor of higher concurrency. Deleting any InternalId records after the import has finished is an extra measure to guarantee consistency. Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/54270.
This commit is contained in:
parent
13f5f7e64d
commit
fede3a0b75
|
@ -66,6 +66,17 @@ class InternalId < ActiveRecord::Base
|
|||
InternalIdGenerator.new(subject, scope, usage, init).generate
|
||||
end
|
||||
|
||||
# Flushing records is generally safe in a sense that those
|
||||
# records are going to be re-created when needed.
|
||||
#
|
||||
# A filter condition has to be provided to not accidentally flush
|
||||
# records for all projects.
|
||||
def flush_records!(filter)
|
||||
raise ArgumentError, "filter cannot be empty" if filter.blank?
|
||||
|
||||
where(filter).delete_all
|
||||
end
|
||||
|
||||
def available?
|
||||
@available_flag ||= ActiveRecord::Migrator.current_version >= REQUIRED_SCHEMA_VERSION # rubocop:disable Gitlab/PredicateMemoization
|
||||
end
|
||||
|
|
|
@ -1585,6 +1585,13 @@ class Project < ActiveRecord::Base
|
|||
def after_import
|
||||
repository.after_import
|
||||
wiki.repository.after_import
|
||||
|
||||
# The import assigns iid values on its own, e.g. by re-using GitHub ids.
|
||||
# Flush existing InternalId records for this project for consistency reasons.
|
||||
# Those records are going to be recreated with the next normal creation
|
||||
# of a model instance (e.g. an Issue).
|
||||
InternalId.flush_records!(project: self)
|
||||
|
||||
import_state.finish
|
||||
import_state.remove_jid
|
||||
update_project_counter_caches
|
||||
|
|
|
@ -13,6 +13,29 @@ describe InternalId do
|
|||
it { is_expected.to validate_presence_of(:usage) }
|
||||
end
|
||||
|
||||
describe '.flush_records!' do
|
||||
subject { described_class.flush_records!(project: project) }
|
||||
|
||||
let(:another_project) { create(:project) }
|
||||
|
||||
before do
|
||||
create_list(:issue, 2, project: project)
|
||||
create_list(:issue, 2, project: another_project)
|
||||
end
|
||||
|
||||
it 'deletes all records for the given project' do
|
||||
expect { subject }.to change { described_class.where(project: project).count }.from(1).to(0)
|
||||
end
|
||||
|
||||
it 'retains records for other projects' do
|
||||
expect { subject }.not_to change { described_class.where(project: another_project).count }
|
||||
end
|
||||
|
||||
it 'does not allow an empty filter' do
|
||||
expect { described_class.flush_records!({}) }.to raise_error(/filter cannot be empty/)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.generate_next' do
|
||||
subject { described_class.generate_next(issue, scope, usage, init) }
|
||||
|
||||
|
|
|
@ -3767,6 +3767,7 @@ describe Project do
|
|||
expect(import_state).to receive(:remove_jid)
|
||||
expect(project).to receive(:after_create_default_branch)
|
||||
expect(project).to receive(:refresh_markdown_cache!)
|
||||
expect(InternalId).to receive(:flush_records!).with(project: project)
|
||||
|
||||
project.after_import
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue