Commit 9f3a8f88 authored by Kerri Miller's avatar Kerri Miller

Merge branch '226924-capture-diff-note-positions-draft-notes-publish' into 'master'

Reduce N+1 Gitaly queries when publishing multiple draft notes

See merge request gitlab-org/gitlab!68045
parents 5ef9b4a8 b870a652
...@@ -32,26 +32,28 @@ module DraftNotes ...@@ -32,26 +32,28 @@ module DraftNotes
review = Review.create!(author: current_user, merge_request: merge_request, project: project) review = Review.create!(author: current_user, merge_request: merge_request, project: project)
draft_notes.map do |draft_note| created_notes = draft_notes.map do |draft_note|
draft_note.review = review draft_note.review = review
create_note_from_draft(draft_note) create_note_from_draft(draft_note, skip_capture_diff_note_position: true)
end end
draft_notes.delete_all
capture_diff_note_positions(created_notes)
draft_notes.delete_all
set_reviewed set_reviewed
notification_service.async.new_review(review) notification_service.async.new_review(review)
MergeRequests::ResolvedDiscussionNotificationService.new(project: project, current_user: current_user).execute(merge_request) MergeRequests::ResolvedDiscussionNotificationService.new(project: project, current_user: current_user).execute(merge_request)
end end
def create_note_from_draft(draft) def create_note_from_draft(draft, skip_capture_diff_note_position: false)
# Make sure the diff file is unfolded in order to find the correct line # Make sure the diff file is unfolded in order to find the correct line
# codes. # codes.
draft.diff_file&.unfold_diff_lines(draft.original_position) draft.diff_file&.unfold_diff_lines(draft.original_position)
note = Notes::CreateService.new(draft.project, draft.author, draft.publish_params).execute note = Notes::CreateService.new(draft.project, draft.author, draft.publish_params).execute(
set_discussion_resolve_status(note, draft) skip_capture_diff_note_position: skip_capture_diff_note_position
)
set_discussion_resolve_status(note, draft)
note note
end end
...@@ -70,5 +72,19 @@ module DraftNotes ...@@ -70,5 +72,19 @@ module DraftNotes
def set_reviewed def set_reviewed
::MergeRequests::MarkReviewerReviewedService.new(project: project, current_user: current_user).execute(merge_request) ::MergeRequests::MarkReviewerReviewedService.new(project: project, current_user: current_user).execute(merge_request)
end end
def capture_diff_note_positions(notes)
paths = notes.flat_map do |note|
note.diff_file&.paths if note.diff_note?
end
return if paths.empty?
capture_service = Discussions::CaptureDiffNotePositionService.new(merge_request, paths.compact)
notes.each do |note|
capture_service.execute(note.discussion) if note.diff_note? && note.start_of_discussion?
end
end
end end
end end
...@@ -4,7 +4,7 @@ module Notes ...@@ -4,7 +4,7 @@ module Notes
class CreateService < ::Notes::BaseService class CreateService < ::Notes::BaseService
include IncidentManagement::UsageData include IncidentManagement::UsageData
def execute def execute(skip_capture_diff_note_position: false)
note = Notes::BuildService.new(project, current_user, params.except(:merge_request_diff_head_sha)).execute note = Notes::BuildService.new(project, current_user, params.except(:merge_request_diff_head_sha)).execute
# n+1: https://gitlab.com/gitlab-org/gitlab-foss/issues/37440 # n+1: https://gitlab.com/gitlab-org/gitlab-foss/issues/37440
...@@ -34,7 +34,7 @@ module Notes ...@@ -34,7 +34,7 @@ module Notes
end end
end end
when_saved(note) if note_saved when_saved(note, skip_capture_diff_note_position: skip_capture_diff_note_position) if note_saved
end end
note note
...@@ -68,14 +68,14 @@ module Notes ...@@ -68,14 +68,14 @@ module Notes
end end
end end
def when_saved(note) def when_saved(note, skip_capture_diff_note_position: false)
todo_service.new_note(note, current_user) todo_service.new_note(note, current_user)
clear_noteable_diffs_cache(note) clear_noteable_diffs_cache(note)
Suggestions::CreateService.new(note).execute Suggestions::CreateService.new(note).execute
increment_usage_counter(note) increment_usage_counter(note)
track_event(note, current_user) track_event(note, current_user)
if note.for_merge_request? && note.diff_note? && note.start_of_discussion? if !skip_capture_diff_note_position && note.for_merge_request? && note.diff_note? && note.start_of_discussion?
Discussions::CaptureDiffNotePositionService.new(note.noteable, note.diff_file&.paths).execute(note.discussion) Discussions::CaptureDiffNotePositionService.new(note.noteable, note.diff_file&.paths).execute(note.discussion)
end end
end end
......
...@@ -66,8 +66,8 @@ RSpec.describe DraftNotes::PublishService do ...@@ -66,8 +66,8 @@ RSpec.describe DraftNotes::PublishService do
let(:commit_id) { nil } let(:commit_id) { nil }
before do before do
create(:draft_note, merge_request: merge_request, author: user, note: 'first note', commit_id: commit_id, position: position) create(:draft_note_on_text_diff, merge_request: merge_request, author: user, note: 'first note', commit_id: commit_id, position: position)
create(:draft_note, merge_request: merge_request, author: user, note: 'second note', commit_id: commit_id, position: position) create(:draft_note_on_text_diff, merge_request: merge_request, author: user, note: 'second note', commit_id: commit_id, position: position)
end end
context 'when review fails to create' do context 'when review fails to create' do
...@@ -127,6 +127,30 @@ RSpec.describe DraftNotes::PublishService do ...@@ -127,6 +127,30 @@ RSpec.describe DraftNotes::PublishService do
publish publish
end end
context 'capturing diff notes positions' do
before do
# Need to execute this to ensure that we'll be able to test creation of
# DiffNotePosition records as that only happens when the `MergeRequest#merge_ref_head`
# is present. This service creates that for the specified merge request.
MergeRequests::MergeToRefService.new(project: project, current_user: user).execute(merge_request)
end
it 'creates diff_note_positions for diff notes' do
publish
notes = merge_request.notes.order(id: :asc)
expect(notes.first.diff_note_positions).to be_any
expect(notes.last.diff_note_positions).to be_any
end
it 'does not requests a lot from Gitaly', :request_store do
# NOTE: This should be reduced as we work on reducing Gitaly calls.
# Gitaly requests shouldn't go above this threshold as much as possible
# as it may add more to the Gitaly N+1 issue we are experiencing.
expect { publish }.to change { Gitlab::GitalyClient.get_request_count }.by(11)
end
end
context 'commit_id is set' do context 'commit_id is set' do
let(:commit_id) { commit.id } let(:commit_id) { commit.id }
......
...@@ -185,6 +185,14 @@ RSpec.describe Notes::CreateService do ...@@ -185,6 +185,14 @@ RSpec.describe Notes::CreateService do
expect(note.note_diff_file).to be_present expect(note.note_diff_file).to be_present
expect(note.diff_note_positions).to be_present expect(note.diff_note_positions).to be_present
end end
context 'when skip_capture_diff_note_position execute option is set to true' do
it 'does not execute Discussions::CaptureDiffNotePositionService' do
expect(Discussions::CaptureDiffNotePositionService).not_to receive(:new)
described_class.new(project_with_repo, user, new_opts).execute(skip_capture_diff_note_position: true)
end
end
end end
context 'when DiffNote is a reply' do context 'when DiffNote is a reply' do
......
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