Commit 52f68e9c authored by Aakriti Gupta's avatar Aakriti Gupta

Improve performance of Geo verification queries

Adapt Geo verification queries to conditionally
use replicable model table or a separate
verification details table.

With the use of separate tables for verification
information, we want to adapt verification queries
such that they don't use extra filters that were
already used to backfill the separate tables.

This is done by splitting the original scope on
replicable models, `available_verifiables` into
two new scopes, `verifiables` and
`with_verification_state_record`.

EE: true
parent d43ba95f
...@@ -29,6 +29,7 @@ module EE ...@@ -29,6 +29,7 @@ module EE
scope :has_external_diffs, -> { with_files.where(stored_externally: true) } scope :has_external_diffs, -> { with_files.where(stored_externally: true) }
scope :project_id_in, ->(ids) { where(merge_request_id: ::MergeRequest.where(target_project_id: ids)) } scope :project_id_in, ->(ids) { where(merge_request_id: ::MergeRequest.where(target_project_id: ids)) }
scope :available_replicables, -> { has_external_diffs } scope :available_replicables, -> { has_external_diffs }
scope :available_verifiables, -> { joins(:merge_request_diff_detail) }
scope :with_verification_state, ->(state) { joins(:merge_request_diff_detail).where(merge_request_diff_details: { verification_state: verification_state_value(state) }) } scope :with_verification_state, ->(state) { joins(:merge_request_diff_detail).where(merge_request_diff_details: { verification_state: verification_state_value(state) }) }
scope :checksummed, -> { joins(:merge_request_diff_detail).where.not(merge_request_diff_details: { verification_checksum: nil } ) } scope :checksummed, -> { joins(:merge_request_diff_detail).where.not(merge_request_diff_details: { verification_checksum: nil } ) }
scope :not_checksummed, -> { joins(:merge_request_diff_detail).where(merge_request_diff_details: { verification_checksum: nil } ) } scope :not_checksummed, -> { joins(:merge_request_diff_detail).where(merge_request_diff_details: { verification_checksum: nil } ) }
......
...@@ -40,13 +40,17 @@ module Geo ...@@ -40,13 +40,17 @@ module Geo
end end
# This method creates or deletes verification details records. # This method creates or deletes verification details records.
# It creates for available verifiables where records don't exist yet. #
# It looks for replicable records that are eligible for verification (scoped
# as `verifiables`) but whose corresponding verification details record doesn't
# exist yet.
# These would be replicable records that have recently become scoped as # These would be replicable records that have recently become scoped as
# available_verifiables. # `verifiables`, but were not so at the time of creation.
# New replicable records will automatically create child records in the # New replicable records will automatically create child records in the
# verification details table, hence not created in this method. # verification details table, hence not created in this method.
#
# When a replicable record is no longer a part of the scope # When a replicable record is no longer a part of the scope
# available_veriables, it is deleted. # `verifiables`, the corresponding verification state record needs to be deleted.
# When a replicable record is deleted, the child record in the verification # When a replicable record is deleted, the child record in the verification
# details table is automatically removed, hence not deleted in this method. # details table is automatically removed, hence not deleted in this method.
# #
......
...@@ -21,7 +21,28 @@ module Gitlab ...@@ -21,7 +21,28 @@ module Gitlab
# These scopes are intended to be overridden as needed # These scopes are intended to be overridden as needed
scope :available_replicables, -> { all } scope :available_replicables, -> { all }
scope :available_verifiables, -> { self.respond_to?(:with_files_stored_locally) ? available_replicables.with_files_stored_locally : available_replicables }
# On primary, `verifiables` are records that can be checksummed and/or are replicable.
# On secondary, `verifiables` are records that have already been replicated
# and (ideally) have been checksummed on the primary
scope :verifiables, -> { self.respond_to?(:with_files_stored_locally) ? available_replicables.with_files_stored_locally : available_replicables }
# When storing verification details in the same table as the model,
# the scope `available_verifiables` returns only those records
# that are eligible for verification, i.e. the same as the scope
# `verifiables`.
# When using a separate table to store verification details,
# the scope `available_verifiables` should return all records
# from the separate table because the separate table will
# always only have records corresponding to replicables that are verifiable.
# For this, override the scope in the replicable model, e.g. like so in
# `MergeRequestDiff`,
# `scope :available_verifiables, -> { joins(:merge_request_diff_detail) }`
scope :available_verifiables, -> { verifiables }
end end
class_methods do class_methods do
......
...@@ -95,7 +95,7 @@ module Gitlab ...@@ -95,7 +95,7 @@ module Gitlab
def save_verification_details def save_verification_details
return unless self.class.separate_verification_state_table? return unless self.class.separate_verification_state_table?
return unless self.class.available_verifiables.primary_key_in(self).exists? return unless self.class.verifiables.primary_key_in(self).exists?
# During a transaction, `verification_state_object` could be built before # During a transaction, `verification_state_object` could be built before
# a value for `verification_state_model_key` exists. So we check for that # a value for `verification_state_model_key` exists. So we check for that
...@@ -306,7 +306,7 @@ module Gitlab ...@@ -306,7 +306,7 @@ module Gitlab
def pluck_verifiable_ids_in_range(range) def pluck_verifiable_ids_in_range(range)
self self
.available_verifiables .verifiables
.primary_key_in(range) .primary_key_in(range)
.pluck_primary_key .pluck_primary_key
end end
......
...@@ -3,15 +3,14 @@ ...@@ -3,15 +3,14 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe Geo::VerificationStateBackfillService, :geo do RSpec.describe Geo::VerificationStateBackfillService, :geo do
let(:replicable_1) { FactoryBot.create(:merge_request_diff, :external) } let_it_be(:replicable) { create(:merge_request_diff, :external) }
let(:verifiable_1) { FactoryBot.create(:merge_request_diff_detail, merge_request_diff: replicable_1) }
subject(:job) { described_class.new(MergeRequestDiff, batch_size: 1000) } subject(:job) { described_class.new(MergeRequestDiff, batch_size: 1000) }
describe '#execute' do describe '#execute' do
context 'when a replicable is missing a corresponding verifiable' do context 'when a replicable is missing a corresponding verifiable' do
before do before do
replicable_1.merge_request_diff_detail.destroy! replicable.merge_request_diff_detail.destroy!
end end
it 'adds a new verifiable' do it 'adds a new verifiable' do
...@@ -20,8 +19,10 @@ RSpec.describe Geo::VerificationStateBackfillService, :geo do ...@@ -20,8 +19,10 @@ RSpec.describe Geo::VerificationStateBackfillService, :geo do
end end
context 'when some replicables were removed from scope' do context 'when some replicables were removed from scope' do
let(:verifiable) { create(:merge_request_diff_detail, merge_request_diff: replicable) }
before do before do
replicable_1.update_attribute(:stored_externally, false) replicable.update_attribute(:stored_externally, false)
end end
it 'deletes the verifiable' do it 'deletes the verifiable' 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