Skip to content

Commit d0675bd

Browse files
author
GitLab Bot
committed
Add latest changes from gitlab-org/gitlab@master
[skip secret push protection]
1 parent b4982ae commit d0675bd

File tree

4 files changed

+56
-9
lines changed

4 files changed

+56
-9
lines changed

lib/gitlab/database/load_balancing/sticking.rb

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,19 @@ class Sticking
1010
# the primary.
1111
EXPIRATION = 30
1212

13+
UNSTICK_IF_CAUGHT_UP_SCRIPT = <<~LUA
14+
local key = KEYS[1]
15+
local expected_location = ARGV[1]
16+
local current_location = redis.call('GET', key)
17+
18+
if current_location == expected_location then
19+
redis.call('DEL', key)
20+
return 1
21+
else
22+
return 0
23+
end
24+
LUA
25+
1326
attr_reader :load_balancer
1427

1528
def initialize(load_balancer)
@@ -35,7 +48,7 @@ def find_caught_up_replica(
3548
result = if location
3649
up_to_date_result = @load_balancer.select_up_to_date_host(location)
3750

38-
unstick(namespace, id) if up_to_date_result == LoadBalancer::ALL_CAUGHT_UP
51+
unstick_if_caught_up(namespace, id, location) if up_to_date_result == LoadBalancer::ALL_CAUGHT_UP
3952

4053
up_to_date_result != LoadBalancer::NONE_CAUGHT_UP
4154
else
@@ -100,6 +113,17 @@ def unstick(namespace, id)
100113
end
101114
end
102115

116+
# Atomically unstick only if the sticking point hasn't changed since we read it.
117+
# This prevents a race condition where a concurrent request sets a new sticking point
118+
# after we've verified all replicas are caught up but before we unstick.
119+
#
120+
# Returns 1 if unstick was performed, 0 if the value changed (indicating a new write).
121+
def unstick_if_caught_up(namespace, id, expected_location)
122+
with_redis do |redis|
123+
redis.eval(UNSTICK_IF_CAUGHT_UP_SCRIPT, keys: [redis_key_for(namespace, id)], argv: [expected_location])
124+
end
125+
end
126+
103127
def set_write_location_for(namespace, id, location)
104128
with_redis do |redis|
105129
redis.set(redis_key_for(namespace, id), location, ex: EXPIRATION)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@
237237
"url-loader": "^4.1.1",
238238
"uuid": "8.1.0",
239239
"visibilityjs": "^1.2.4",
240-
"vite": "7.2.2",
240+
"vite": "7.2.7",
241241
"vite-plugin-ruby": "^5.1.1",
242242
"vue-loader-vue3": "npm:vue-loader@17.4.2",
243243
"vue": "2.7.16",

spec/lib/gitlab/database/load_balancing/sticking_spec.rb

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,39 @@
5757
end
5858

5959
context 'when all replicas have caught up' do
60-
it 'returns true and unsticks' do
60+
it 'returns true and attempts to unstick if location matches' do
6161
expect(load_balancer).to receive(:select_up_to_date_host).with(last_write_location)
6262
.and_return(::Gitlab::Database::LoadBalancing::LoadBalancer::ALL_CAUGHT_UP)
6363

6464
expect(redis)
65-
.to receive(:del)
66-
.with("database-load-balancing/write-location/#{load_balancer.name}/user/42")
65+
.to receive(:eval)
66+
.with(
67+
described_class::UNSTICK_IF_CAUGHT_UP_SCRIPT,
68+
keys: ["database-load-balancing/write-location/#{load_balancer.name}/user/42"],
69+
argv: [last_write_location]
70+
)
71+
.and_return(1)
6772

6873
expect(sticking.find_caught_up_replica(:user, 42)).to eq(true)
6974
end
75+
76+
context 'when the sticking point has changed (concurrent write)' do
77+
it 'returns true but does not unstick' do
78+
expect(load_balancer).to receive(:select_up_to_date_host).with(last_write_location)
79+
.and_return(::Gitlab::Database::LoadBalancing::LoadBalancer::ALL_CAUGHT_UP)
80+
81+
expect(redis)
82+
.to receive(:eval)
83+
.with(
84+
described_class::UNSTICK_IF_CAUGHT_UP_SCRIPT,
85+
keys: ["database-load-balancing/write-location/#{load_balancer.name}/user/42"],
86+
argv: [last_write_location]
87+
)
88+
.and_return(0)
89+
90+
expect(sticking.find_caught_up_replica(:user, 42)).to eq(true)
91+
end
92+
end
7093
end
7194

7295
context 'when only some of the replicas have caught up' do

yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15477,10 +15477,10 @@ vite-plugin-ruby@^5.1.1:
1547715477
debug "^4.3.4"
1547815478
fast-glob "^3.3.2"
1547915479

15480-
vite@7.2.2, "vite@^6.0.0 || ^7.0.0":
15481-
version "7.2.2"
15482-
resolved "https://registry.yarnpkg.com/vite/-/vite-7.2.2.tgz#17dd62eac2d0ca0fa90131c5f56e4fefb8845362"
15483-
integrity sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==
15480+
vite@7.2.7, "vite@^6.0.0 || ^7.0.0":
15481+
version "7.2.7"
15482+
resolved "https://registry.yarnpkg.com/vite/-/vite-7.2.7.tgz#0789a4c3206081699f34a9ecca2dda594a07478e"
15483+
integrity sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==
1548415484
dependencies:
1548515485
esbuild "^0.25.0"
1548615486
fdir "^6.5.0"

0 commit comments

Comments
 (0)