From 33f50e7d2da4432d1ee20cc66c02c2833743ca4e Mon Sep 17 00:00:00 2001 From: Gary Holtz Date: Mon, 1 Dec 2025 23:20:43 -0600 Subject: [PATCH 1/2] Make merge_request_diff_commits queries partition compatible --- app/services/projects/destroy_service.rb | 50 ++++++++++++++++++------ 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index 12d7ed15d00aef..403f7d69bc1346 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -212,18 +212,44 @@ def log_destroy_event def destroy_mr_diff_relations! delete_batch_size = 1000 - project.merge_requests.each_batch(column: :iid, of: BATCH_SIZE) do |relation_ids| - loop do - inner_query = MergeRequestDiffFile - .select(:merge_request_diff_id, :relative_order) - .where(merge_request_diff_id: MergeRequestDiff.where(merge_request_id: relation_ids).select(:id)) - .limit(delete_batch_size) - - deleted_rows = MergeRequestDiffFile - .where("(merge_request_diff_files.merge_request_diff_id, merge_request_diff_files.relative_order) IN (?)", inner_query) - .delete_all - - break if deleted_rows == 0 + if Feature.enabled?(:merge_request_diff_commits_partition, project) + # partition compatible queries + project.merge_requests.each_batch(column: :iid, of: BATCH_SIZE) do |relation_ids| + loop do + inner_query = MergeRequestDiffCommit + .select(:merge_request_diff_id, :relative_order) + .where( + merge_request_diff_id: MergeRequestDiff.where(merge_request_id: relation_ids).select(:id) + ) + .where(project_id: project.id) + .limit(delete_batch_size) + + deleted_rows = MergeRequestDiffCommit + .where(project_id: project.id) + .where( + "(merge_request_diff_commits.merge_request_diff_id, merge_request_diff_commits.relative_order) IN (?)", + inner_query + ) + .delete_all + + break if deleted_rows == 0 + end + end + else + # records without project ids + project.merge_requests.each_batch(column: :iid, of: BATCH_SIZE) do |relation_ids| + loop do + inner_query = MergeRequestDiffFile + .select(:merge_request_diff_id, :relative_order) + .where(merge_request_diff_id: MergeRequestDiff.where(merge_request_id: relation_ids).select(:id)) + .limit(delete_batch_size) + + deleted_rows = MergeRequestDiffFile + .where("(merge_request_diff_files.merge_request_diff_id, merge_request_diff_files.relative_order) IN (?)", inner_query) + .delete_all + + break if deleted_rows == 0 + end end end -- GitLab From 7cae9c4c76cf179e96fc9f7746c96a53261d0280 Mon Sep 17 00:00:00 2001 From: Gary Holtz Date: Fri, 12 Dec 2025 21:51:11 -0600 Subject: [PATCH 2/2] Adding spec --- .../services/projects/destroy_service_spec.rb | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb index 34e78907b559fb..a4655c5348b465 100644 --- a/spec/services/projects/destroy_service_spec.rb +++ b/spec/services/projects/destroy_service_spec.rb @@ -1087,6 +1087,62 @@ end end + describe '#destroy_mr_diff_relations!' do + let(:service) { described_class.new(project, user, {}) } + + context 'when merge_request_diff_commits_partition feature flag is enabled' do + let!(:merge_request) { create(:merge_request, source_project: project) } + let!(:merge_request_diff) { merge_request.merge_request_diffs.first } + + before do + MergeRequestDiffCommit.where(merge_request_diff_id: merge_request_diff.id).delete_all + + 3.times do |i| + MergeRequestDiffCommit.create!( + merge_request_diff_id: merge_request_diff.id, + project_id: project.id, + relative_order: i, + sha: Digest::SHA256.hexdigest("commit-#{i}"), + authored_date: Time.current, + committed_date: Time.current + ) + end + end + + it 'deletes MergeRequestDiffCommit records using partition-compatible queries' do + expect(MergeRequestDiffCommit.where(project_id: project.id).count).to eq(3) + + service.send(:destroy_mr_diff_relations!) + + expect(MergeRequestDiffCommit.where(project_id: project.id).count).to eq(0) + end + + it 'only deletes records for the current project' do + other_project = create(:project, :repository, namespace: user.namespace) + other_merge_request = create(:merge_request, source_project: other_project) + other_diff = other_merge_request.merge_request_diffs.first + + MergeRequestDiffCommit.where(merge_request_diff_id: other_diff.id).delete_all + + 2.times do |i| + MergeRequestDiffCommit.create!( + merge_request_diff_id: other_diff.id, + project_id: other_project.id, + relative_order: i, + sha: Digest::SHA256.hexdigest("other-commit-#{i}"), + authored_date: Time.current, + committed_date: Time.current + ) + end + + service.send(:destroy_mr_diff_relations!) + + expect(MergeRequestDiffCommit.where(project_id: project.id).count).to eq(0) + expect(MergeRequestDiffCommit.where(project_id: other_project.id).count).to eq(2) + end + end + end + def destroy_project(project, user, params = {}) described_class.new(project, user, params).public_send(async ? :async_execute : :execute) end -- GitLab