Commit 81dc37b4 authored by Quang-Minh Nguyen's avatar Quang-Minh Nguyen Committed by Mayra Cabrera

Rename use_replica_if_possible to fallback_to_replicas_for_ambiguous_queries

parent 43c8d4d3
...@@ -10,7 +10,7 @@ module EE ...@@ -10,7 +10,7 @@ module EE
override :with_fast_read_statement_timeout override :with_fast_read_statement_timeout
def with_fast_read_statement_timeout(timeout_ms = 5000) def with_fast_read_statement_timeout(timeout_ms = 5000)
::Gitlab::Database::LoadBalancing::Session.current.use_replica_if_possible do ::Gitlab::Database::LoadBalancing::Session.current.fallback_to_replicas_for_ambiguous_queries do
super super
end end
end end
......
...@@ -60,7 +60,7 @@ module Gitlab ...@@ -60,7 +60,7 @@ module Gitlab
end end
def transaction(*args, &block) def transaction(*args, &block)
if ::Gitlab::Database::LoadBalancing::Session.current.use_replica? if ::Gitlab::Database::LoadBalancing::Session.current.fallback_to_replicas_for_ambiguous_queries?
track_read_only_transaction! track_read_only_transaction!
read_using_load_balancer(:transaction, args, &block) read_using_load_balancer(:transaction, args, &block)
else else
...@@ -73,7 +73,7 @@ module Gitlab ...@@ -73,7 +73,7 @@ module Gitlab
# Delegates all unknown messages to a read-write connection. # Delegates all unknown messages to a read-write connection.
def method_missing(name, *args, &block) def method_missing(name, *args, &block)
if ::Gitlab::Database::LoadBalancing::Session.current.use_replica? if ::Gitlab::Database::LoadBalancing::Session.current.fallback_to_replicas_for_ambiguous_queries?
read_using_load_balancer(name, args, &block) read_using_load_balancer(name, args, &block)
else else
write_using_load_balancer(name, args, &block) write_using_load_balancer(name, args, &block)
......
...@@ -55,22 +55,27 @@ module Gitlab ...@@ -55,22 +55,27 @@ module Gitlab
@ignore_writes = false @ignore_writes = false
end end
# Indicate that all the SQL statements from anywhere inside this block # Indicate that the ambiguous SQL statements from anywhere inside this
# should use a replica. This is a weak enforcement. The queries # block should use a replica. The ambiguous statements include:
# prioritize using a primary over a replica in those cases: # - Transactions.
# - Custom queries (via exec_query, execute, etc.)
# - In-flight connection configuration change (SET LOCAL statement_timeout = 5000)
#
# This is a weak enforcement. This helper incorporates well with
# primary stickiness:
# - If the queries are about to write # - If the queries are about to write
# - The current session already performed writes # - The current session already performed writes
# - It prefers to use primary, aka, use_primary or use_primary! were called # - It prefers to use primary, aka, use_primary or use_primary! were called
def use_replica_if_possible(&blk) def fallback_to_replicas_for_ambiguous_queries(&blk)
used_replica = @use_replica previous_flag = @fallback_to_replicas_for_ambiguous_queries
@use_replica = true @fallback_to_replicas_for_ambiguous_queries = true
yield yield
ensure ensure
@use_replica = used_replica @fallback_to_replicas_for_ambiguous_queries = previous_flag
end end
def use_replica? def fallback_to_replicas_for_ambiguous_queries?
@use_replica == true && !use_primary? && !performed_write? @fallback_to_replicas_for_ambiguous_queries == true && !use_primary? && !performed_write?
end end
def write! def write!
......
...@@ -115,11 +115,11 @@ RSpec.describe Gitlab::Database::LoadBalancing::ConnectionProxy do ...@@ -115,11 +115,11 @@ RSpec.describe Gitlab::Database::LoadBalancing::ConnectionProxy do
.and_return(session) .and_return(session)
end end
context 'session prefers to use a replica' do context 'session fallbacks ambiguous queries to replicas' do
let(:replica) { double(:connection) } let(:replica) { double(:connection) }
before do before do
allow(session).to receive(:use_replica?).and_return(true) allow(session).to receive(:fallback_to_replicas_for_ambiguous_queries?).and_return(true)
allow(session).to receive(:use_primary?).and_return(false) allow(session).to receive(:use_primary?).and_return(false)
allow(replica).to receive(:transaction).and_yield allow(replica).to receive(:transaction).and_yield
allow(replica).to receive(:select) allow(replica).to receive(:select)
...@@ -148,11 +148,11 @@ RSpec.describe Gitlab::Database::LoadBalancing::ConnectionProxy do ...@@ -148,11 +148,11 @@ RSpec.describe Gitlab::Database::LoadBalancing::ConnectionProxy do
end end
end end
context 'session does not prefer to use a replica' do context 'session does not fallback to replicas for ambiguous queries' do
let(:primary) { double(:connection) } let(:primary) { double(:connection) }
before do before do
allow(session).to receive(:use_replica?).and_return(false) allow(session).to receive(:fallback_to_replicas_for_ambiguous_queries?).and_return(false)
allow(session).to receive(:use_primary?).and_return(true) allow(session).to receive(:use_primary?).and_return(true)
allow(primary).to receive(:transaction).and_yield allow(primary).to receive(:transaction).and_yield
allow(primary).to receive(:select) allow(primary).to receive(:select)
...@@ -200,13 +200,13 @@ RSpec.describe Gitlab::Database::LoadBalancing::ConnectionProxy do ...@@ -200,13 +200,13 @@ RSpec.describe Gitlab::Database::LoadBalancing::ConnectionProxy do
.not_to raise_error .not_to raise_error
end end
context 'current session prefers to use a replica' do context 'current session prefers to fallback ambiguous queries to replicas' do
let(:session) { double(:session) } let(:session) { double(:session) }
before do before do
allow(Gitlab::Database::LoadBalancing::Session).to receive(:current) allow(Gitlab::Database::LoadBalancing::Session).to receive(:current)
.and_return(session) .and_return(session)
allow(session).to receive(:use_replica?).and_return(true) allow(session).to receive(:fallback_to_replicas_for_ambiguous_queries?).and_return(true)
allow(session).to receive(:use_primary?).and_return(false) allow(session).to receive(:use_primary?).and_return(false)
end end
......
...@@ -139,37 +139,37 @@ RSpec.describe Gitlab::Database::LoadBalancing::Session do ...@@ -139,37 +139,37 @@ RSpec.describe Gitlab::Database::LoadBalancing::Session do
end end
end end
describe '#use_replica_if_possible' do describe '#fallback_to_replicas_for_ambiguous_queries' do
let(:instance) { described_class.new } let(:instance) { described_class.new }
it 'uses replica during block' do it 'sets the flag inside the block' do
expect do |blk| expect do |blk|
instance.use_replica_if_possible do instance.fallback_to_replicas_for_ambiguous_queries do
expect(instance.use_replica?).to eq(true) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(true)
# call yield probe # call yield probe
blk.to_proc.call blk.to_proc.call
end end
end.to yield_control end.to yield_control
expect(instance.use_replica?).to eq(false) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(false)
end end
it 'restores state after use' do it 'restores state after use' do
expect do |blk| expect do |blk|
instance.use_replica_if_possible do instance.fallback_to_replicas_for_ambiguous_queries do
instance.use_replica_if_possible do instance.fallback_to_replicas_for_ambiguous_queries do
expect(instance.use_replica?).to eq(true) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(true)
# call yield probe # call yield probe
blk.to_proc.call blk.to_proc.call
end end
expect(instance.use_replica?).to eq(true) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(true)
end end
end.to yield_control end.to yield_control
expect(instance.use_replica?).to eq(false) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(false)
end end
context 'when primary was used before' do context 'when primary was used before' do
...@@ -178,18 +178,18 @@ RSpec.describe Gitlab::Database::LoadBalancing::Session do ...@@ -178,18 +178,18 @@ RSpec.describe Gitlab::Database::LoadBalancing::Session do
end end
it 'uses primary during block' do it 'uses primary during block' do
expect(instance.use_replica?).to eq(false) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(false)
expect do |blk| expect do |blk|
instance.use_replica_if_possible do instance.fallback_to_replicas_for_ambiguous_queries do
expect(instance.use_replica?).to eq(false) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(false)
# call yield probe # call yield probe
blk.to_proc.call blk.to_proc.call
end end
end.to yield_control end.to yield_control
expect(instance.use_replica?).to eq(false) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(false)
end end
end end
...@@ -199,82 +199,82 @@ RSpec.describe Gitlab::Database::LoadBalancing::Session do ...@@ -199,82 +199,82 @@ RSpec.describe Gitlab::Database::LoadBalancing::Session do
end end
it 'uses primary during block' do it 'uses primary during block' do
expect(instance.use_replica?).to eq(false) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(false)
expect do |blk| expect do |blk|
instance.use_replica_if_possible do instance.fallback_to_replicas_for_ambiguous_queries do
expect(instance.use_replica?).to eq(false) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(false)
# call yield probe # call yield probe
blk.to_proc.call blk.to_proc.call
end end
end.to yield_control end.to yield_control
expect(instance.use_replica?).to eq(false) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(false)
end end
end end
context 'when primary was used inside the block' do context 'when primary was used inside the block' do
it 'uses primary aterward' do it 'uses primary aterward' do
expect(instance.use_replica?).to eq(false) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(false)
instance.use_replica_if_possible do instance.fallback_to_replicas_for_ambiguous_queries do
expect(instance.use_replica?).to eq(true) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(true)
instance.use_primary! instance.use_primary!
expect(instance.use_replica?).to eq(false) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(false)
end end
expect(instance.use_replica?).to eq(false) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(false)
end end
it 'restores state after use' do it 'restores state after use' do
instance.use_replica_if_possible do instance.fallback_to_replicas_for_ambiguous_queries do
instance.use_replica_if_possible do instance.fallback_to_replicas_for_ambiguous_queries do
expect(instance.use_replica?).to eq(true) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(true)
instance.use_primary! instance.use_primary!
expect(instance.use_replica?).to eq(false) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(false)
end end
expect(instance.use_replica?).to eq(false) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(false)
end end
expect(instance.use_replica?).to eq(false) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(false)
end end
end end
context 'when a write was performed inside the block' do context 'when a write was performed inside the block' do
it 'uses primary aterward' do it 'uses primary aterward' do
expect(instance.use_replica?).to eq(false) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(false)
instance.use_replica_if_possible do instance.fallback_to_replicas_for_ambiguous_queries do
expect(instance.use_replica?).to eq(true) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(true)
instance.write! instance.write!
expect(instance.use_replica?).to eq(false) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(false)
end end
expect(instance.use_replica?).to eq(false) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(false)
end end
it 'restores state after use' do it 'restores state after use' do
instance.use_replica_if_possible do instance.fallback_to_replicas_for_ambiguous_queries do
instance.use_replica_if_possible do instance.fallback_to_replicas_for_ambiguous_queries do
expect(instance.use_replica?).to eq(true) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(true)
instance.write! instance.write!
expect(instance.use_replica?).to eq(false) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(false)
end end
expect(instance.use_replica?).to eq(false) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(false)
end end
expect(instance.use_replica?).to eq(false) expect(instance.fallback_to_replicas_for_ambiguous_queries?).to eq(false)
end end
end end
end end
......
...@@ -561,10 +561,10 @@ RSpec.describe Gitlab::Database::LoadBalancing do ...@@ -561,10 +561,10 @@ RSpec.describe Gitlab::Database::LoadBalancing do
false, [:replica, :primary] false, [:replica, :primary]
], ],
# use_replica_if_possible # fallback_to_replicas_for_ambiguous_queries
[ [
-> { -> {
::Gitlab::Database::LoadBalancing::Session.current.use_replica_if_possible do ::Gitlab::Database::LoadBalancing::Session.current.fallback_to_replicas_for_ambiguous_queries do
model.first model.first
model.where(name: 'test1').to_a model.where(name: 'test1').to_a
end end
...@@ -572,10 +572,10 @@ RSpec.describe Gitlab::Database::LoadBalancing do ...@@ -572,10 +572,10 @@ RSpec.describe Gitlab::Database::LoadBalancing do
false, [:replica, :replica] false, [:replica, :replica]
], ],
# use_replica_if_possible for read-only transaction # fallback_to_replicas_for_ambiguous_queries for read-only transaction
[ [
-> { -> {
::Gitlab::Database::LoadBalancing::Session.current.use_replica_if_possible do ::Gitlab::Database::LoadBalancing::Session.current.fallback_to_replicas_for_ambiguous_queries do
model.transaction do model.transaction do
model.first model.first
model.where(name: 'test1').to_a model.where(name: 'test1').to_a
...@@ -585,20 +585,20 @@ RSpec.describe Gitlab::Database::LoadBalancing do ...@@ -585,20 +585,20 @@ RSpec.describe Gitlab::Database::LoadBalancing do
false, [:replica, :replica] false, [:replica, :replica]
], ],
# A custom read query inside use_replica_if_possible # A custom read query inside fallback_to_replicas_for_ambiguous_queries
[ [
-> { -> {
::Gitlab::Database::LoadBalancing::Session.current.use_replica_if_possible do ::Gitlab::Database::LoadBalancing::Session.current.fallback_to_replicas_for_ambiguous_queries do
model.connection.exec_query("SELECT 1") model.connection.exec_query("SELECT 1")
end end
}, },
false, [:replica] false, [:replica]
], ],
# A custom read query inside a transaction use_replica_if_possible # A custom read query inside a transaction fallback_to_replicas_for_ambiguous_queries
[ [
-> { -> {
::Gitlab::Database::LoadBalancing::Session.current.use_replica_if_possible do ::Gitlab::Database::LoadBalancing::Session.current.fallback_to_replicas_for_ambiguous_queries do
model.transaction do model.transaction do
model.connection.exec_query("SET LOCAL statement_timeout = 5000") model.connection.exec_query("SET LOCAL statement_timeout = 5000")
model.count model.count
...@@ -608,33 +608,33 @@ RSpec.describe Gitlab::Database::LoadBalancing do ...@@ -608,33 +608,33 @@ RSpec.describe Gitlab::Database::LoadBalancing do
true, [:replica, :replica, :replica, :replica] true, [:replica, :replica, :replica, :replica]
], ],
# use_replica_if_possible after a write # fallback_to_replicas_for_ambiguous_queries after a write
[ [
-> { -> {
model.create!(name: 'Test1') model.create!(name: 'Test1')
::Gitlab::Database::LoadBalancing::Session.current.use_replica_if_possible do ::Gitlab::Database::LoadBalancing::Session.current.fallback_to_replicas_for_ambiguous_queries do
model.first model.first
end end
}, },
false, [:primary, :primary] false, [:primary, :primary]
], ],
# use_replica_if_possible after use_primary! # fallback_to_replicas_for_ambiguous_queries after use_primary!
[ [
-> { -> {
::Gitlab::Database::LoadBalancing::Session.current.use_primary! ::Gitlab::Database::LoadBalancing::Session.current.use_primary!
::Gitlab::Database::LoadBalancing::Session.current.use_replica_if_possible do ::Gitlab::Database::LoadBalancing::Session.current.fallback_to_replicas_for_ambiguous_queries do
model.first model.first
end end
}, },
false, [:primary] false, [:primary]
], ],
# use_replica_if_possible inside use_primary # fallback_to_replicas_for_ambiguous_queries inside use_primary
[ [
-> { -> {
::Gitlab::Database::LoadBalancing::Session.current.use_primary do ::Gitlab::Database::LoadBalancing::Session.current.use_primary do
::Gitlab::Database::LoadBalancing::Session.current.use_replica_if_possible do ::Gitlab::Database::LoadBalancing::Session.current.fallback_to_replicas_for_ambiguous_queries do
model.first model.first
end end
end end
...@@ -642,10 +642,10 @@ RSpec.describe Gitlab::Database::LoadBalancing do ...@@ -642,10 +642,10 @@ RSpec.describe Gitlab::Database::LoadBalancing do
false, [:primary] false, [:primary]
], ],
# use_primary inside use_replica_if_possible # use_primary inside fallback_to_replicas_for_ambiguous_queries
[ [
-> { -> {
::Gitlab::Database::LoadBalancing::Session.current.use_replica_if_possible do ::Gitlab::Database::LoadBalancing::Session.current.fallback_to_replicas_for_ambiguous_queries do
::Gitlab::Database::LoadBalancing::Session.current.use_primary do ::Gitlab::Database::LoadBalancing::Session.current.use_primary do
model.first model.first
end end
...@@ -654,10 +654,10 @@ RSpec.describe Gitlab::Database::LoadBalancing do ...@@ -654,10 +654,10 @@ RSpec.describe Gitlab::Database::LoadBalancing do
false, [:primary] false, [:primary]
], ],
# A write query inside use_replica_if_possible # A write query inside fallback_to_replicas_for_ambiguous_queries
[ [
-> { -> {
::Gitlab::Database::LoadBalancing::Session.current.use_replica_if_possible do ::Gitlab::Database::LoadBalancing::Session.current.fallback_to_replicas_for_ambiguous_queries do
model.first model.first
model.delete_all model.delete_all
model.where(name: 'test1').to_a model.where(name: 'test1').to_a
...@@ -758,12 +758,12 @@ RSpec.describe Gitlab::Database::LoadBalancing do ...@@ -758,12 +758,12 @@ RSpec.describe Gitlab::Database::LoadBalancing do
end end
end end
context 'a write inside a transaction inside use_replica_if_possible block' do context 'a write inside a transaction inside fallback_to_replicas_for_ambiguous_queries block' do
include_context 'LoadBalancing setup' include_context 'LoadBalancing setup'
it 'raises an exception' do it 'raises an exception' do
expect do expect do
::Gitlab::Database::LoadBalancing::Session.current.use_replica_if_possible do ::Gitlab::Database::LoadBalancing::Session.current.fallback_to_replicas_for_ambiguous_queries do
model.transaction do model.transaction do
model.first model.first
model.create!(name: 'hello') model.create!(name: 'hello')
......
...@@ -8,7 +8,7 @@ RSpec.describe ApplicationRecord do ...@@ -8,7 +8,7 @@ RSpec.describe ApplicationRecord do
before do before do
allow(::Gitlab::Database::LoadBalancing::Session).to receive(:current).and_return(session) allow(::Gitlab::Database::LoadBalancing::Session).to receive(:current).and_return(session)
allow(session).to receive(:use_replica_if_possible).and_yield allow(session).to receive(:fallback_to_replicas_for_ambiguous_queries).and_yield
end end
it 'yields control' do it 'yields control' 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