1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
# The migration is used to cleanup orphaned lfs_objects_projects in order to
# introduce valid foreign keys to this table
class CleanupOrphanedLfsObjectsProjects
# A model to access lfs_objects_projects table in migrations
class LfsObjectsProject < ActiveRecord::Base
self.table_name = 'lfs_objects_projects'
include ::EachBatch
belongs_to :lfs_object
belongs_to :project
end
# A model to access lfs_objects table in migrations
class LfsObject < ActiveRecord::Base
self.table_name = 'lfs_objects'
end
# A model to access projects table in migrations
class Project < ActiveRecord::Base
self.table_name = 'projects'
end
SUB_BATCH_SIZE = 5000
CLEAR_CACHE_DELAY = 1.minute
def perform(start_id, end_id)
cleanup_lfs_objects_projects_without_lfs_object(start_id, end_id)
cleanup_lfs_objects_projects_without_project(start_id, end_id)
end
private
def cleanup_lfs_objects_projects_without_lfs_object(start_id, end_id)
each_record_without_association(start_id, end_id, :lfs_object, :lfs_objects) do |lfs_objects_projects_without_lfs_objects|
projects = Project.where(id: lfs_objects_projects_without_lfs_objects.select(:project_id))
if projects.present?
ProjectCacheWorker.bulk_perform_in_with_contexts(
CLEAR_CACHE_DELAY,
projects,
arguments_proc: ->(project) { [project.id, [], [:lfs_objects_size]] },
context_proc: ->(project) { { project: project } }
)
end
lfs_objects_projects_without_lfs_objects.delete_all
end
end
def cleanup_lfs_objects_projects_without_project(start_id, end_id)
each_record_without_association(start_id, end_id, :project, :projects) do |lfs_objects_projects_without_projects|
lfs_objects_projects_without_projects.delete_all
end
end
def each_record_without_association(start_id, end_id, association, table_name)
batch = LfsObjectsProject.where(id: start_id..end_id)
batch.each_batch(of: SUB_BATCH_SIZE) do |sub_batch|
first, last = sub_batch.pick(Arel.sql('min(lfs_objects_projects.id), max(lfs_objects_projects.id)'))
lfs_objects_without_association =
LfsObjectsProject
.unscoped
.left_outer_joins(association)
.where(id: (first..last), table_name => { id: nil })
yield lfs_objects_without_association
end
end
end
end
end
|