Commit 1c731e90 authored by Vitali Tatarintev's avatar Vitali Tatarintev

Merge branch 'yorick/remove-redundant-wal-queries' into 'master'

Don't run WAL queries when not using replicas

See merge request gitlab-org/gitlab!71736
parents f2d4c6ed 9599f866
...@@ -11,6 +11,12 @@ module Gitlab ...@@ -11,6 +11,12 @@ module Gitlab
# balancing is enabled, but no replicas have been configured (= the # balancing is enabled, but no replicas have been configured (= the
# default case). # default case).
class PrimaryHost class PrimaryHost
WAL_ERROR_MESSAGE = <<~MSG.strip
Obtaining WAL information when not using any replicas results in
redundant queries, and may break installations that don't support
streaming replication (e.g. AWS' Aurora database).
MSG
def initialize(load_balancer) def initialize(load_balancer)
@load_balancer = load_balancer @load_balancer = load_balancer
end end
...@@ -51,30 +57,16 @@ module Gitlab ...@@ -51,30 +57,16 @@ module Gitlab
end end
def primary_write_location def primary_write_location
@load_balancer.primary_write_location raise NotImplementedError, WAL_ERROR_MESSAGE
end end
def database_replica_location def database_replica_location
row = query_and_release(<<-SQL.squish) raise NotImplementedError, WAL_ERROR_MESSAGE
SELECT pg_last_wal_replay_lsn()::text AS location
SQL
row['location'] if row.any?
rescue *Host::CONNECTION_ERRORS
nil
end end
def caught_up?(_location) def caught_up?(_location)
true true
end end
def query_and_release(sql)
connection.select_all(sql).first || {}
rescue StandardError
{}
ensure
release_connection
end
end end
end end
end end
......
...@@ -42,6 +42,9 @@ module Gitlab ...@@ -42,6 +42,9 @@ module Gitlab
end end
def wal_location_for(load_balancer) def wal_location_for(load_balancer)
# When only using the primary there's no need for any WAL queries.
return if load_balancer.primary_only?
if ::Gitlab::Database::LoadBalancing::Session.current.use_primary? if ::Gitlab::Database::LoadBalancing::Session.current.use_primary?
load_balancer.primary_write_location load_balancer.primary_write_location
else else
......
...@@ -104,6 +104,10 @@ module Gitlab ...@@ -104,6 +104,10 @@ module Gitlab
end end
def with_primary_write_location def with_primary_write_location
# When only using the primary, there's no point in getting write
# locations, as the primary is always in sync with itself.
return if @load_balancer.primary_only?
location = @load_balancer.primary_write_location location = @load_balancer.primary_write_location
return if location.blank? return if location.blank?
......
...@@ -63,9 +63,8 @@ RSpec.describe Gitlab::Database::LoadBalancing::PrimaryHost do ...@@ -63,9 +63,8 @@ RSpec.describe Gitlab::Database::LoadBalancing::PrimaryHost do
end end
describe '#primary_write_location' do describe '#primary_write_location' do
it 'returns the write location of the primary' do it 'raises NotImplementedError' do
expect(host.primary_write_location).to be_an_instance_of(String) expect { host.primary_write_location }.to raise_error(NotImplementedError)
expect(host.primary_write_location).not_to be_empty
end end
end end
...@@ -76,51 +75,8 @@ RSpec.describe Gitlab::Database::LoadBalancing::PrimaryHost do ...@@ -76,51 +75,8 @@ RSpec.describe Gitlab::Database::LoadBalancing::PrimaryHost do
end end
describe '#database_replica_location' do describe '#database_replica_location' do
let(:connection) { double(:connection) } it 'raises NotImplementedError' do
expect { host.database_replica_location }.to raise_error(NotImplementedError)
it 'returns the write ahead location of the replica', :aggregate_failures do
expect(host)
.to receive(:query_and_release)
.and_return({ 'location' => '0/D525E3A8' })
expect(host.database_replica_location).to be_an_instance_of(String)
end
it 'returns nil when the database query returned no rows' do
expect(host).to receive(:query_and_release).and_return({})
expect(host.database_replica_location).to be_nil
end
it 'returns nil when the database connection fails' do
allow(host).to receive(:connection).and_raise(PG::Error)
expect(host.database_replica_location).to be_nil
end
end
describe '#query_and_release' do
it 'executes a SQL query' do
results = host.query_and_release('SELECT 10 AS number')
expect(results).to be_an_instance_of(Hash)
expect(results['number'].to_i).to eq(10)
end
it 'releases the connection after running the query' do
expect(host)
.to receive(:release_connection)
.once
host.query_and_release('SELECT 10 AS number')
end
it 'returns an empty Hash in the event of an error' do
expect(host.connection)
.to receive(:select_all)
.and_raise(RuntimeError, 'kittens')
expect(host.query_and_release('SELECT 10 AS number')).to eq({})
end end
end end
end end
...@@ -21,7 +21,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqClientMiddleware do ...@@ -21,7 +21,7 @@ RSpec.describe Gitlab::Database::LoadBalancing::SidekiqClientMiddleware do
middleware.call(worker_class, job, nil, nil) {} middleware.call(worker_class, job, nil, nil) {}
end end
describe '#call' do describe '#call', :database_replica do
shared_context 'data consistency worker class' do |data_consistency, feature_flag| shared_context 'data consistency worker class' do |data_consistency, feature_flag|
let(:expected_consistency) { data_consistency } let(:expected_consistency) { data_consistency }
let(:worker_class) do let(:worker_class) do
......
...@@ -188,6 +188,10 @@ RSpec.describe Gitlab::Database::LoadBalancing::Sticking, :redis do ...@@ -188,6 +188,10 @@ RSpec.describe Gitlab::Database::LoadBalancing::Sticking, :redis do
end end
it 'sticks an entity to the primary', :aggregate_failures do it 'sticks an entity to the primary', :aggregate_failures do
allow(ActiveRecord::Base.connection.load_balancer)
.to receive(:primary_only?)
.and_return(false)
ids.each do |id| ids.each do |id|
expect(sticking) expect(sticking)
.to receive(:set_write_location_for) .to receive(:set_write_location_for)
...@@ -199,6 +203,12 @@ RSpec.describe Gitlab::Database::LoadBalancing::Sticking, :redis do ...@@ -199,6 +203,12 @@ RSpec.describe Gitlab::Database::LoadBalancing::Sticking, :redis do
subject subject
end end
it 'does not update the write location when no replicas are used' do
expect(sticking).not_to receive(:set_write_location_for)
subject
end
end end
describe '#stick' do describe '#stick' do
...@@ -221,12 +231,22 @@ RSpec.describe Gitlab::Database::LoadBalancing::Sticking, :redis do ...@@ -221,12 +231,22 @@ RSpec.describe Gitlab::Database::LoadBalancing::Sticking, :redis do
.to receive(:primary_write_location) .to receive(:primary_write_location)
.and_return('foo') .and_return('foo')
allow(ActiveRecord::Base.connection.load_balancer)
.to receive(:primary_only?)
.and_return(false)
expect(sticking) expect(sticking)
.to receive(:set_write_location_for) .to receive(:set_write_location_for)
.with(:user, 42, 'foo') .with(:user, 42, 'foo')
sticking.mark_primary_write_location(:user, 42) sticking.mark_primary_write_location(:user, 42)
end end
it 'does nothing when no replicas are used' do
expect(sticking).not_to receive(:set_write_location_for)
sticking.mark_primary_write_location(:user, 42)
end
end end
describe '#unstick' do describe '#unstick' do
......
...@@ -2791,17 +2791,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do ...@@ -2791,17 +2791,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
extra_update_queries = 4 # transition ... => :canceled, queue pop extra_update_queries = 4 # transition ... => :canceled, queue pop
extra_generic_commit_status_validation_queries = 2 # name_uniqueness_across_types extra_generic_commit_status_validation_queries = 2 # name_uniqueness_across_types
# The number of extra load balancing queries depends on whether or not expect(control2.count).to eq(control1.count + extra_update_queries + extra_generic_commit_status_validation_queries)
# we use a load balancer for CI. That in turn depends on the contents of
# database.yml, so here we support both cases.
extra_load_balancer_queries =
if Gitlab::Database.has_config?(:ci)
6
else
3
end
expect(control2.count).to eq(control1.count + extra_update_queries + extra_generic_commit_status_validation_queries + extra_load_balancer_queries)
end end
end end
......
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