Skip to content

Commit 59053c8

Browse files
author
GitLab Bot
committed
Add latest changes from gitlab-org/gitlab@master
1 parent b1c736e commit 59053c8

File tree

26 files changed

+1069
-70
lines changed

26 files changed

+1069
-70
lines changed

CHANGELOG.md

+765
Large diffs are not rendered by default.

GITALY_SERVER_VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
58bf41c6a0d6024402551506cf1a40b340662453
1+
c45474cf95ee58efeeebe7adf6a6892b511db5ef

GITLAB_KAS_VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
95b8e6a28986f6b4aaaa20283212259b1938e948
1+
b583acae369d671df2cb8c2a8b6fd42a2351e6bf

app/assets/javascripts/super_sidebar/components/organization_switcher.vue

+2-2
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ export default {
132132
<gl-disclosure-dropdown :items="items" class="gl-block" placement="bottom" @shown="onShown">
133133
<template #toggle>
134134
<button
135-
class="user-bar-button organization-switcher-button gl-flex gl-w-full gl-items-center gl-gap-3 gl-rounded-base gl-border-none gl-p-3 gl-text-left gl-leading-1"
135+
class="user-bar-button organization-switcher-button gl-flex gl-w-full gl-items-center gl-gap-3 gl-rounded-base gl-border-none gl-p-2 gl-text-left gl-leading-1"
136136
data-testid="toggle-button"
137137
>
138138
<gl-avatar
@@ -150,7 +150,7 @@ export default {
150150
<template #list-item="{ item }">
151151
<gl-loading-icon v-if="item.id === $options.ITEM_LOADING.id" />
152152
<span v-else-if="item.id === $options.ITEM_EMPTY.id">{{ item.text }}</span>
153-
<div v-else class="gl-flex gl-items-center gl-gap-3">
153+
<div v-else class="-gl-m-2 gl-flex gl-items-center gl-gap-3">
154154
<gl-avatar
155155
:size="24"
156156
:shape="$options.AVATAR_SHAPE_OPTION_RECT"

app/assets/javascripts/work_items/components/work_item_development/work_item_development_mr_item.vue

+2-5
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,11 @@ export default {
7979
}
8080
return '';
8181
},
82-
mrFullPath() {
83-
return `${this.itemContent.project.namespace.path}/${this.itemContent.project.path}`;
84-
},
8582
showPath() {
86-
return this.mrFullPath !== this.workItemFullPath;
83+
return this.itemContent.project.fullPath !== this.workItemFullPath;
8784
},
8885
fullReferenceWithPath() {
89-
return `${this.mrFullPath}${this.itemContent?.reference}`;
86+
return `${this.itemContent.project.fullPath}${this.itemContent?.reference}`;
9087
},
9188
detailedStatus() {
9289
return this.itemContent?.headPipeline?.detailedStatus;

app/assets/javascripts/work_items/graphql/merge_request.fragment.graphql

+1-3
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@ fragment MergeRequestFragment on MergeRequest {
2424
id
2525
name
2626
path
27-
namespace {
28-
path
29-
}
27+
fullPath
3028
}
3129
assignees {
3230
nodes {

app/graphql/types/tree/tree_type.rb

+4-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ class TreeType < BaseObject
2525
calls_gitaly: true
2626

2727
field :permalink_path, GraphQL::Types::String, null: true,
28-
description: 'Web path to tree permalink.',
28+
description: "Web path to tree permalink. " \
29+
"The `permalinkPath` field returns a string that represents the web path to a specific version of " \
30+
"a directory, identified by its commit SHA. Use this path to create permanent links to directories at " \
31+
"specific points in your repository's history.",
2932
calls_gitaly: true,
3033
experiment: { milestone: '17.11' }
3134

app/models/diff_note.rb

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ class DiffNote < Note
88
include DiffPositionableNote
99
include Gitlab::Utils::StrongMemoize
1010

11+
# Duplicate ignore_column from Note to make the db:check-migrations job pass
12+
ignore_column :attachment, remove_with: '18.1', remove_after: '2025-05-15'
13+
1114
self.allow_legacy_sti_class = true
1215

1316
def self.noteable_types

app/models/project_group_link.rb

+17-1
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ class ProjectGroupLink < ApplicationRecord
88
belongs_to :project
99
belongs_to :group
1010

11+
before_validation :prevent_concurrent_inserts
12+
1113
validates :project_id, presence: true
1214
validates :group, presence: true
13-
validates :group_id, uniqueness: { scope: [:project_id], message: N_("already shared with this group") }
15+
validates :project_id, uniqueness: { scope: [:group_id], message: N_("already shared with this group") }
1416
validates :group_access, inclusion: { in: Gitlab::Access.all_values }, presence: true
1517
validate :different_group
1618

@@ -35,6 +37,20 @@ def owner_access?
3537

3638
private
3739

40+
# This method will block while another database transaction attempts to insert the same data.
41+
# After the lock is released by the other transaction, the uniqueness validation may fail
42+
# with record not unique validation error.
43+
44+
# Without this block the uniqueness validation wouldn't be able to detect duplicated
45+
# records as transactions can't see each other's changes.
46+
def prevent_concurrent_inserts
47+
return if project_id.nil? || group_id.nil?
48+
49+
lock_key = ['project_group_links', project_id, group_id].join('-')
50+
lock_expression = "hashtext(#{connection.quote(lock_key)})"
51+
connection.execute("SELECT pg_advisory_xact_lock(#{lock_expression})")
52+
end
53+
3854
def different_group
3955
return unless self.group && self.project
4056

config/coverband.rb

+3
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,7 @@
1212

1313
config.verbose = false # this spams logfile a lot, set to true for debugging locally
1414
config.logger = Gitlab::AppLogger.primary_logger
15+
# By default Puma starts in the tmp directory to mimic Omnibus GitLab, but
16+
# this root path needs to be set for Coverband to identify application code.
17+
config.root = Rails.root.to_s
1518
end

config/initializers/coverband.rb

+10
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,13 @@
77
ENV["COVERBAND_CONFIG"] = Rails.root.join("config/coverband.rb").to_s
88

99
require 'coverband'
10+
11+
# Normally with a Rails Web app Coverband defines a Railtie, which
12+
# is responsible for inserting a middleware that launches a background
13+
# thread. However, since we dynamically require Coverband in this file,
14+
# it is too late for Railties to be defined now so we need to manually
15+
# start the background threads. In addition, each Puma process needs
16+
# its own background thread to report which code paths were hit.
17+
Gitlab::Cluster::LifecycleEvents.on_worker_start do
18+
::Coverband::Background.start
19+
end

data/deprecations/16-9-deprecate-terraform-cicd-templates.yml

+5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
announcement_milestone: "16.9"
55
# Change breaking_change to false if needed.
66
breaking_change: true
7+
window: 3
8+
scope: project
9+
impact: medium
10+
resolution_role: developer
11+
manual_task: true
712
# The stage and GitLab username of the person reporting the change,
813
# and a link to the deprecation issue
914
reporter: timofurrer
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# frozen_string_literal: true
2+
3+
# This index is being added so that we can backfill the namespace where project
4+
# id is NULL
5+
class AddTempIndexOnNotesForProjectsNullAndId < Gitlab::Database::Migration[2.2]
6+
disable_ddl_transaction!
7+
milestone '17.11'
8+
NEW_INDEX_NAME = 'tmp_index_null_project_id_on_notes'
9+
10+
# Remove index issue: gitlab.com/gitlab-org/gitlab/-/issues/535969
11+
# Make the index async issue: gitlab.com/gitlab-org/gitlab/-/issues/535970
12+
def up
13+
# rubocop:disable Migration/PreventIndexCreation -- Will be removed once the backfilling for note is complete
14+
prepare_async_index(:notes,
15+
:id,
16+
name: NEW_INDEX_NAME,
17+
where: 'project_id is NULL')
18+
# rubocop:enable Migration/PreventIndexCreation
19+
end
20+
21+
def down
22+
unprepare_async_index :notes, NEW_INDEX_NAME
23+
end
24+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# frozen_string_literal: true
2+
3+
class RemoveNotesAttachment < Gitlab::Database::Migration[2.2]
4+
milestone '18.0'
5+
6+
def change
7+
remove_column :notes, :attachment, :string
8+
end
9+
end

db/schema_migrations/20250411043427

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
db462f63722bba9d2bfdecd0a18ea3ecc0c6eba68a0ba4107752d8b133bcb487

db/schema_migrations/20250414145659

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
f22e3a9f4396a13cf673acd69124c3cc8800c180f0669dc9abf04acbe9064116

db/structure.sql

-1
Original file line numberDiff line numberDiff line change
@@ -18348,7 +18348,6 @@ CREATE TABLE notes (
1834818348
created_at timestamp without time zone,
1834918349
updated_at timestamp without time zone,
1835018350
project_id bigint,
18351-
attachment character varying,
1835218351
line_code character varying,
1835318352
commit_id character varying,
1835418353
noteable_id bigint,

doc/administration/gitaly/concurrency_limiting.md

+113-17
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,43 @@ When the pack-object cache is enabled, pack-objects limiting kicks in only if th
135135
You can observe the behavior of this queue using Gitaly logs and Prometheus. For more information, see
136136
[Monitor Gitaly pack-objects concurrency limiting](monitoring.md#monitor-gitaly-pack-objects-concurrency-limiting).
137137

138+
## Calibrating concurrency limits
139+
140+
When setting concurrency limits, you should choose appropriate values based on your specific workload patterns. This section provides guidance on how to calibrate these limits effectively.
141+
142+
### Using Prometheus metrics and logs for calibration
143+
144+
Prometheus metrics provide quantitative insights into usage patterns and the impact of each type of RPC on Gitaly node resources. Several key metrics are particularly valuable for this analysis:
145+
146+
- Resource consumption metrics per-RPC. Gitaly offloads most heavy operations to `git` processes and so the command usually shelled out to is the Git binary.
147+
Gitaly exposes collected metrics from those commands as logs and Prometheus metrics.
148+
- `gitaly_command_cpu_seconds_total` - Sum of CPU time spent by shelling out, with labels for `grpc_service`, `grpc_method`, `cmd`, and `subcmd`.
149+
- `gitaly_command_real_seconds_total` - Sum of real time spent by shelling out, with similar labels.
150+
- Recent limiting metrics per-RPC:
151+
- `gitaly_concurrency_limiting_in_progress` - Number of concurrent requests being processed.
152+
- `gitaly_concurrency_limiting_queued` - Number of requests for an RPC for a given repository in waiting state.
153+
- `gitaly_concurrency_limiting_acquiring_seconds` - Duration a request waits due to concurrency limits before processing.
154+
155+
These metrics provide a high-level view of resource utilization at a given point in time. The `gitaly_command_cpu_seconds_total` metric is particularly effective for
156+
identifying specific RPCs that consume substantial CPU resources. Additional metrics are available for more detailed analysis as described in
157+
[Monitoring Gitaly](monitoring.md).
158+
159+
While metrics capture overall resource usage patterns, they typically do not provide per-repository breakdowns. Therefore, logs serve as a complementary data source. To analyze logs:
160+
161+
1. Filter logs by identified high-impact RPCs.
162+
1. Aggregate filtered logs by repository or project.
163+
1. Visualize aggregated results on a time-series graph.
164+
165+
This combined approach of using both metrics and logs provides comprehensive visibility into both system-wide resource usage and repository-specific patterns. Analysis tools such as Kibana or similar log aggregation platforms can facilitate this process.
166+
167+
### Adjusting limits
168+
169+
If you find that your initial limits are not efficient enough, you might need to adjust them. With adaptive limiting, precise limits are less critical because the system
170+
automatically adjusts based on resource usage.
171+
172+
Remember that concurrency limits are scoped by repository. A limit of 30 means allowing at most 30 simultaneous in-flight requests per repository. If the limit is reached,
173+
requests are queued and only rejected if the queue is full or the maximum waiting time is reached.
174+
138175
## Adaptive concurrency limiting
139176

140177
{{< history >}}
@@ -181,7 +218,12 @@ The adaptive limiter calibrates the limits every 30 seconds and:
181218
Otherwise, the limits increase by one until reaching the upper bound. For more information about technical implementation
182219
of this system, refer to [the related design document](https://handbook.gitlab.com/handbook/engineering/architecture/design-documents/gitaly_adaptive_concurrency_limit/).
183220

184-
Adaptive limiting is enabled for each RPC or pack-objects cache individually. However, limits are calibrated at the same time.
221+
Adaptive limiting is enabled for each RPC or pack-objects cache individually. However, limits are calibrated at the same time. Adaptive limiting has the following configurations:
222+
223+
- `adaptive` sets whether the adaptiveness is enabled.
224+
- `max_limit` is the maximum concurrency limit. Gitaly increases the current limit until it reaches this number. This should be a generous value that the system can fully support under typical conditions.
225+
- `min_limit` is the is the minimum concurrency limit of the configured RPC. When the host machine has a resource problem, Gitaly quickly reduces the limit until reaching this value. Setting `min_limit` to 0 could completely shut down processing, which is typically undesirable.
226+
- `initial_limit` provides a reasonable starting point between these extremes.
185227

186228
### Enable adaptiveness for RPC concurrency
187229

@@ -224,15 +266,6 @@ gitaly['configuration'] = {
224266
}
225267
```
226268

227-
In this example:
228-
229-
- `adaptive` sets whether the adaptiveness is enabled. If set, the `max_per_repo` value is ignored in favor of the following configuration.
230-
- `initial_limit` is the per-repository concurrency limit to use when Gitaly starts.
231-
- `max_limit` is the minimum per-repository concurrency limit of the configured RPC. Gitaly increases the current limit
232-
until it reaches this number.
233-
- `min_limit` is the is the minimum per-repository concurrency limit of the configured RPC. When the host machine has a resource problem,
234-
Gitaly quickly reduces the limit until reaching this value.
235-
236269
For more information, see [RPC concurrency](#limit-rpc-concurrency).
237270

238271
### Enable adaptiveness for pack-objects concurrency
@@ -255,12 +288,75 @@ gitaly['pack_objects_limiting'] = {
255288
}
256289
```
257290

258-
In this example:
291+
For more information, see [pack-objects concurrency](#limit-pack-objects-concurrency).
292+
293+
### Calibrating adaptive concurrency limits
259294

260-
- `adaptive` sets whether the adaptiveness is enabled. If set, the value of `max_concurrency` is ignored in favor of the following configuration.
261-
- `initial_limit` is the per-IP concurrency limit to use when Gitaly starts.
262-
- `max_limit` is the minimum per-IP concurrency limit for pack-objects. Gitaly increases the current limit until it reaches this number.
263-
- `min_limit` is the is the minimum per-IP concurrency limit for pack-objects. When the host machine has a resources problem, Gitaly quickly
264-
reduces the limit until it reaches this value.
295+
Adaptive concurrency limiting is very different from the usual way that GitLab protects Gitaly resources. Rather than relying on static thresholds that may be either too restrictive or too permissive, adaptive limiting intelligently responds to actual resource conditions in real-time.
265296

266-
For more information, see [pack-objects concurrency](#limit-pack-objects-concurrency).
297+
This approach eliminates the need to find "perfect" threshold values through extensive calibration as described in
298+
[Calibrating concurrency limits](#calibrating-concurrency-limits). During failure scenarios, the adaptive limiter reduces limits exponentially (for example, 60 → 30 → 15 → 10)
299+
and then automatically recovers by incrementally raising limits when the system stabilizes.
300+
301+
When calibrating adaptive limits, you can prioritize flexibility over precision.
302+
303+
#### RPC categories and configuration examples
304+
305+
Expensive Gitaly RPCs, which should be protected, can be categorized into two general types:
306+
307+
- Pure Git data operations.
308+
- Time sensitive RPCs.
309+
310+
Each type has distinct characteristics that influence how concurrency limits should be configured. The following examples illustrate the reasoning behind
311+
limit configuration. They can also be used as a starting point.
312+
313+
##### Pure Git data operations
314+
315+
These RPCs involve Git pull, push, and fetch operations, and possess the following characteristics:
316+
317+
- Long-running processes.
318+
- Significant resource utilization.
319+
- Computationally expensive.
320+
- Not time-sensitive. Additional latency is generally acceptable.
321+
322+
RPCs in `SmartHTTPService` and `SSHService` fall into the pure Git data operations category. A configuration example:
323+
324+
```ruby
325+
{
326+
rpc: "/gitaly.SmartHTTPService/PostUploadPackWithSidechannel", # or `/gitaly.SmartHTTPService/SSHUploadPackWithSidechannel`
327+
adaptive: true,
328+
min_limit: 10, # Minimum concurrency to maintain even under extreme load
329+
initial_limit: 40, # Starting concurrency when service initializes
330+
max_limit: 60, # Maximum concurrency under ideal conditions
331+
max_queue_wait: "60s",
332+
max_queue_size: 300
333+
}
334+
```
335+
336+
##### Time-sensitive RPCs
337+
338+
These RPCs serve GitLab itself and other clients with different characteristics:
339+
340+
- Typically part of online HTTP requests or Sidekiq background jobs.
341+
- Shorter latency profiles.
342+
- Generally less resource-intensive.
343+
344+
For these RPCs, the timeout configuration in GitLab should inform the `max_queue_wait` parameter. For instance, `get_tree_entries` typically has a medium timeout of 30 seconds in GitLab:
345+
346+
```ruby
347+
{
348+
rpc: "/gitaly.CommitService/GetTreeEntries",
349+
adaptive: true,
350+
min_limit: 5, # Minimum throughput maintained under resource pressure
351+
initial_limit: 10, # Initial concurrency setting
352+
max_limit: 20, # Maximum concurrency under optimal conditions
353+
max_queue_size: 50,
354+
max_queue_wait: "30s"
355+
}
356+
```
357+
358+
### Monitoring adaptive limiting
359+
360+
To observe how adaptive limits are behaving in production environments, refer to the monitoring tools and metrics described in
361+
[Monitor Gitaly adaptive concurrency limiting](monitoring.md#monitor-gitaly-adaptive-concurrency-limiting). Observing adaptive limit behavior helps confirm that limits
362+
are properly responding to resource pressures and adjusting as expected.

0 commit comments

Comments
 (0)