Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
22d3d5d4f2
commit
2d0fdb468b
|
|
@ -334,6 +334,10 @@
|
|||
litellm_params:
|
||||
model: ollama/codestral
|
||||
mock_response: "Mock response from codestral"
|
||||
- model_name: mistral
|
||||
litellm_params:
|
||||
model: ollama/mistral
|
||||
mock_response: "Mock response from mistral"
|
||||
|
||||
.litellm-proxy-services:
|
||||
services:
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ workflow:
|
|||
needs:
|
||||
- build-cng
|
||||
- download-knapsack-report
|
||||
parallel: 5
|
||||
parallel: 10
|
||||
|
||||
# ==========================================
|
||||
# Pre stage
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export default {
|
|||
<div>
|
||||
<gl-card
|
||||
class="gl-rounded-lg"
|
||||
header-class="gl-rounded-lg gl-px-0 gl-py-0 gl-bg-white gl-border-b-0"
|
||||
header-class="gl-rounded-lg gl-px-0 gl-py-0 gl-bg-default gl-border-b-0"
|
||||
body-class="gl-pt-2 gl-pb-0 gl-px-2"
|
||||
>
|
||||
<template #header>
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@
|
|||
@import 'framework/markdown_area';
|
||||
@import 'framework/media_object';
|
||||
@import 'framework/modal';
|
||||
@import 'framework/pagination';
|
||||
@import 'framework/panels';
|
||||
@import 'framework/popup';
|
||||
@import 'framework/secondary_navigation_elements';
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
.gl-pagination {
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.page-item {
|
||||
&.active {
|
||||
.page-link {
|
||||
z-index: 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -307,14 +307,6 @@
|
|||
&,
|
||||
.gl-new-dropdown-custom-toggle {
|
||||
width: 100%;
|
||||
|
||||
// stylelint-disable-next-line gitlab/no-gl-class
|
||||
.gl-badge.badge-muted {
|
||||
// stylelint-disable-next-line gitlab/no-gl-class
|
||||
.gl-dark & {
|
||||
@apply gl-bg-gray-100;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset padding, as inner element will
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@ module Import
|
|||
feature_category :importers
|
||||
|
||||
def accept
|
||||
result = ::Import::SourceUsers::AcceptReassignmentService.new(source_user, current_user: current_user).execute
|
||||
result = ::Import::SourceUsers::AcceptReassignmentService.new(
|
||||
source_user, current_user: current_user, reassignment_token: params[:reassignment_token]
|
||||
).execute
|
||||
|
||||
if result.success?
|
||||
flash[:raw] = banner('accept_invite')
|
||||
|
|
@ -21,7 +23,9 @@ module Import
|
|||
end
|
||||
|
||||
def decline
|
||||
result = ::Import::SourceUsers::RejectReassignmentService.new(source_user, current_user: current_user).execute
|
||||
result = ::Import::SourceUsers::RejectReassignmentService.new(
|
||||
source_user, current_user: current_user, reassignment_token: params[:reassignment_token]
|
||||
).execute
|
||||
|
||||
if result.success?
|
||||
flash[:raw] = banner('reject_invite')
|
||||
|
|
@ -36,7 +40,7 @@ module Import
|
|||
private
|
||||
|
||||
def check_source_user_valid!
|
||||
return if source_user.awaiting_approval? && current_user_matches_invite?
|
||||
return if source_user&.awaiting_approval? && current_user_matches_invite?
|
||||
|
||||
flash[:raw] = banner('invalid_invite')
|
||||
redirect_to(root_path)
|
||||
|
|
@ -47,12 +51,12 @@ module Import
|
|||
end
|
||||
|
||||
def source_user
|
||||
Import::SourceUser.find(params[:id])
|
||||
Import::SourceUser.find_by_reassignment_token(params[:reassignment_token])
|
||||
end
|
||||
strong_memoize_attr :source_user
|
||||
|
||||
def check_feature_flag!
|
||||
not_found unless Feature.enabled?(:importer_user_mapping, source_user.reassigned_by_user)
|
||||
not_found unless source_user.nil? || Feature.enabled?(:importer_user_mapping, source_user.reassigned_by_user)
|
||||
end
|
||||
|
||||
def banner(partial)
|
||||
|
|
|
|||
|
|
@ -100,10 +100,15 @@ class RegistrationsController < Devise::RegistrationsController
|
|||
def after_successful_create_hook(user)
|
||||
accept_pending_invitations
|
||||
persist_accepted_terms_if_required(user)
|
||||
execute_system_hooks(user)
|
||||
notify_new_instance_access_request(user)
|
||||
track_successful_user_creation(user)
|
||||
end
|
||||
|
||||
def execute_system_hooks(user)
|
||||
SystemHooksService.new.execute_hooks_for(user, :create)
|
||||
end
|
||||
|
||||
def notify_new_instance_access_request(user)
|
||||
return unless pending_approval?
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ module Emails
|
|||
@project = Project.find project_id
|
||||
@target_url = project_url(@project)
|
||||
@old_path_with_namespace = old_path_with_namespace
|
||||
mail_with_locale(
|
||||
email_with_layout(
|
||||
to: @user.notification_email_for(@project.group),
|
||||
subject: subject("Project was moved")
|
||||
)
|
||||
|
|
@ -15,7 +15,7 @@ module Emails
|
|||
|
||||
def project_was_exported_email(current_user, project)
|
||||
@project = project
|
||||
mail_with_locale(
|
||||
email_with_layout(
|
||||
to: current_user.notification_email_for(project.group),
|
||||
subject: subject("Project was exported")
|
||||
)
|
||||
|
|
@ -24,7 +24,7 @@ module Emails
|
|||
def project_was_not_exported_email(current_user, project, errors)
|
||||
@project = project
|
||||
@errors = errors
|
||||
mail_with_locale(
|
||||
email_with_layout(
|
||||
to: current_user.notification_email_for(@project.group),
|
||||
subject: subject("Project export error")
|
||||
)
|
||||
|
|
|
|||
|
|
@ -330,6 +330,10 @@ class NotifyPreview < ActionMailer::Preview
|
|||
Notify.project_was_exported_email(user, project).message
|
||||
end
|
||||
|
||||
def repository_cleanup_success_email
|
||||
Notify.repository_cleanup_success_email(project, user).message
|
||||
end
|
||||
|
||||
def request_review_merge_request_email
|
||||
Notify.request_review_merge_request_email(user.id, merge_request.id, user.id).message
|
||||
end
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ class ApplicationRecord < ActiveRecord::Base
|
|||
# to allow callers gracefully handling the errors to still complete within
|
||||
# the 5s target duration of a low urgency request.
|
||||
def self.with_fast_read_statement_timeout(timeout_ms = 4500)
|
||||
::Gitlab::Database::LoadBalancing::SessionMap.current(load_balancer).fallback_to_replicas_for_ambiguous_queries do
|
||||
::Gitlab::Database::LoadBalancing::Session.current.fallback_to_replicas_for_ambiguous_queries do
|
||||
transaction(requires_new: true) do # rubocop:disable Performance/ActiveRecordSubtransactions
|
||||
connection.exec_query("SET LOCAL statement_timeout = #{timeout_ms}")
|
||||
|
||||
|
|
|
|||
|
|
@ -469,7 +469,7 @@ module Ci
|
|||
# not want to upgrade database connection proxy to use the primary
|
||||
# database after heartbeat write happens.
|
||||
#
|
||||
::Gitlab::Database::LoadBalancing::SessionMap.current(connection.load_balancer).without_sticky_writes do
|
||||
::Gitlab::Database::LoadBalancing::Session.without_sticky_writes do
|
||||
values = { contacted_at: Time.current, creation_state: :finished }
|
||||
|
||||
merge_cache_attributes(values)
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ module Ci
|
|||
# not want to upgrade database connection proxy to use the primary
|
||||
# database after heartbeat write happens.
|
||||
#
|
||||
::Gitlab::Database::LoadBalancing::SessionMap.current(connection.load_balancer).without_sticky_writes do
|
||||
::Gitlab::Database::LoadBalancing::Session.without_sticky_writes do
|
||||
values = values&.slice(:version, :revision, :platform, :architecture, :ip_address, :config, :executor) || {}
|
||||
|
||||
values.merge!(contacted_at: Time.current, creation_state: :finished) if update_contacted_at
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ module Packages
|
|||
extend ActiveSupport::Concern
|
||||
|
||||
def touch_last_downloaded_at
|
||||
::Gitlab::Database::LoadBalancing::SessionMap.current(load_balancer).without_sticky_writes do
|
||||
::Gitlab::Database::LoadBalancing::Session.without_sticky_writes do
|
||||
update_column(:last_downloaded_at, Time.zone.now)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ module UseSqlFunctionForPrimaryKeyLookups
|
|||
return unless verification_arel.ast == arel.ast
|
||||
|
||||
if table_name == "namespaces" && Feature.enabled?(:log_sql_function_namespace_lookups, Feature.current_request)
|
||||
using_primary = Gitlab::Database::LoadBalancing::SessionMap.current(load_balancer).use_primary?
|
||||
using_primary = Gitlab::Database::LoadBalancing::Session.current.use_primary?
|
||||
Gitlab::AppLogger.info(
|
||||
message: "Namespaces lookup using function",
|
||||
backtrace: caller,
|
||||
|
|
|
|||
|
|
@ -48,8 +48,7 @@ module Users
|
|||
LIMIT #{limit}
|
||||
SQL
|
||||
|
||||
::Gitlab::Database::LoadBalancing::SessionMap
|
||||
.current(connection.load_balancer).fallback_to_replicas_for_ambiguous_queries do
|
||||
::Gitlab::Database::LoadBalancing::Session.current.fallback_to_replicas_for_ambiguous_queries do
|
||||
connection.execute(sql).to_a
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ module Import
|
|||
validates :namespace_id, :import_type, :source_hostname, :source_user_identifier, :status, presence: true
|
||||
validates :source_user_identifier, uniqueness: { scope: [:namespace_id, :source_hostname, :import_type] }
|
||||
validates :placeholder_user_id, presence: true, unless: :completed?
|
||||
validates :reassignment_token, absence: true, unless: :awaiting_approval?
|
||||
validates :reassignment_token, length: { is: 32 }, if: :awaiting_approval?
|
||||
validates :reassign_to_user_id, presence: true, if: -> {
|
||||
awaiting_approval? || reassignment_in_progress? || completed?
|
||||
}
|
||||
|
|
@ -61,6 +63,14 @@ module Import
|
|||
state status_name, value: value
|
||||
end
|
||||
|
||||
before_transition awaiting_approval: any do |source_user|
|
||||
source_user.reassignment_token = nil
|
||||
end
|
||||
|
||||
before_transition any => :awaiting_approval do |source_user|
|
||||
source_user.reassignment_token = SecureRandom.hex
|
||||
end
|
||||
|
||||
event :reassign do
|
||||
transition REASSIGNABLE_STATUSES => :awaiting_approval
|
||||
end
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ class InternalId < ApplicationRecord
|
|||
|
||||
# `init` computes the maximum based on actual records. We use the
|
||||
# primary to make sure we have up to date results
|
||||
Gitlab::Database::LoadBalancing::SessionMap.current(subject.load_balancer).use_primary do
|
||||
Gitlab::Database::LoadBalancing::Session.current.use_primary do
|
||||
instance = subject.is_a?(::Class) ? nil : subject
|
||||
|
||||
init.call(instance, scope) || 0
|
||||
|
|
|
|||
|
|
@ -60,6 +60,18 @@ class Issue < ApplicationRecord
|
|||
# prevent caching this column by rails, as we want to easily remove it after the backfilling
|
||||
ignore_column :tmp_epic_id, remove_with: '16.11', remove_after: '2024-03-31'
|
||||
|
||||
# Interim columns to convert integer IDs to bigint
|
||||
ignore_column :author_id_convert_to_bigint, remove_with: '17.7', remove_after: '2024-11-17'
|
||||
ignore_column :closed_by_id_convert_to_bigint, remove_with: '17.7', remove_after: '2024-11-17'
|
||||
ignore_column :duplicated_to_id_convert_to_bigint, remove_with: '17.7', remove_after: '2024-11-17'
|
||||
ignore_column :id_convert_to_bigint, remove_with: '17.7', remove_after: '2024-11-17'
|
||||
ignore_column :last_edited_by_id_convert_to_bigint, remove_with: '17.7', remove_after: '2024-11-17'
|
||||
ignore_column :milestone_id_convert_to_bigint, remove_with: '17.7', remove_after: '2024-11-17'
|
||||
ignore_column :moved_to_id_convert_to_bigint, remove_with: '17.7', remove_after: '2024-11-17'
|
||||
ignore_column :project_id_convert_to_bigint, remove_with: '17.7', remove_after: '2024-11-17'
|
||||
ignore_column :promoted_to_epic_id_convert_to_bigint, remove_with: '17.7', remove_after: '2024-11-17'
|
||||
ignore_column :updated_by_id_convert_to_bigint, remove_with: '17.7', remove_after: '2024-11-17'
|
||||
|
||||
belongs_to :project
|
||||
belongs_to :namespace, inverse_of: :issues
|
||||
|
||||
|
|
|
|||
|
|
@ -1491,8 +1491,7 @@ class Project < ApplicationRecord
|
|||
job_type = type.to_s.capitalize
|
||||
|
||||
if job_id
|
||||
use_primary = ::Gitlab::Database::LoadBalancing::SessionMap.current(load_balancer).use_primary?
|
||||
Gitlab::AppLogger.info("#{job_type} job scheduled for #{full_path} with job ID #{job_id} (primary: #{use_primary}).")
|
||||
Gitlab::AppLogger.info("#{job_type} job scheduled for #{full_path} with job ID #{job_id} (primary: #{::Gitlab::Database::LoadBalancing::Session.current.use_primary?}).")
|
||||
else
|
||||
Gitlab::AppLogger.error("#{job_type} job failed to create for #{full_path}.")
|
||||
end
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class SentNotification < ApplicationRecord
|
|||
|
||||
# Non-sticky write is used as `.record` is only used in ActionMailer
|
||||
# where there are no queries to SentNotification.
|
||||
::Gitlab::Database::LoadBalancing::SessionMap.current(load_balancer).without_sticky_writes do
|
||||
::Gitlab::Database::LoadBalancing::Session.without_sticky_writes do
|
||||
create(attrs)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ module Ci
|
|||
|
||||
# Prevent parallel jobs
|
||||
in_lock("#{self.class.name.underscore}/worker/#{@worker_index}", ttl: MAX_TTL, retries: 0) do
|
||||
::Gitlab::Database::LoadBalancing::SessionMap.without_sticky_writes do
|
||||
::Gitlab::Database::LoadBalancing::Session.without_sticky_writes do
|
||||
report = insert_new_finished_pipelines
|
||||
|
||||
ServiceResponse.success(payload: report.merge(service_payload))
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ module Ci
|
|||
# We want to reset a load balancing session to discard the side
|
||||
# effects of writes that could have happened prior to this moment.
|
||||
#
|
||||
::Gitlab::Database::LoadBalancing::SessionMap.clear_session
|
||||
::Gitlab::Database::LoadBalancing::Session.clear_session
|
||||
|
||||
@metrics.observe_queue_time(:retrieve, @runner.runner_type) do
|
||||
queue_query_proc.call
|
||||
|
|
|
|||
|
|
@ -3,15 +3,25 @@
|
|||
module Import
|
||||
module SourceUsers
|
||||
class AcceptReassignmentService < BaseService
|
||||
def initialize(import_source_user, current_user:)
|
||||
def initialize(import_source_user, current_user:, reassignment_token:)
|
||||
@import_source_user = import_source_user
|
||||
@current_user = current_user
|
||||
@reassignment_token = reassignment_token
|
||||
end
|
||||
|
||||
def execute
|
||||
return error_invalid_permissions unless current_user_matches_reassign_to_user
|
||||
invalid_permissions = false
|
||||
accept_successful = false
|
||||
|
||||
if import_source_user.accept
|
||||
import_source_user.with_lock do
|
||||
next invalid_permissions = true unless current_user_matches_reassign_to_user? && reassignment_token_is_valid?
|
||||
|
||||
accept_successful = import_source_user.accept
|
||||
end
|
||||
|
||||
return error_invalid_permissions if invalid_permissions
|
||||
|
||||
if accept_successful
|
||||
Import::ReassignPlaceholderUserRecordsWorker.perform_async(import_source_user.id)
|
||||
ServiceResponse.success(payload: import_source_user)
|
||||
else
|
||||
|
|
@ -21,11 +31,17 @@ module Import
|
|||
|
||||
private
|
||||
|
||||
def current_user_matches_reassign_to_user
|
||||
attr_reader :reassignment_token
|
||||
|
||||
def current_user_matches_reassign_to_user?
|
||||
return false if current_user.nil?
|
||||
|
||||
current_user.id == import_source_user.reassign_to_user_id
|
||||
end
|
||||
|
||||
def reassignment_token_is_valid?
|
||||
reassignment_token == import_source_user.reassignment_token
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,9 +10,21 @@ module Import
|
|||
|
||||
def execute
|
||||
return error_invalid_permissions unless current_user.can?(:admin_import_source_user, import_source_user)
|
||||
return error_invalid_status unless import_source_user.cancelable_status?
|
||||
|
||||
if cancel_reassignment
|
||||
invalid_status = false
|
||||
cancel_successful = false
|
||||
|
||||
import_source_user.with_lock do
|
||||
if import_source_user.cancelable_status?
|
||||
cancel_successful = cancel_reassignment
|
||||
else
|
||||
invalid_status = true
|
||||
end
|
||||
end
|
||||
|
||||
return error_invalid_status if invalid_status
|
||||
|
||||
if cancel_successful
|
||||
ServiceResponse.success(payload: import_source_user)
|
||||
else
|
||||
ServiceResponse.error(payload: import_source_user, message: import_source_user.errors.full_messages)
|
||||
|
|
|
|||
|
|
@ -11,10 +11,22 @@ module Import
|
|||
|
||||
def execute
|
||||
return error_invalid_permissions unless current_user.can?(:admin_import_source_user, import_source_user)
|
||||
return error_invalid_status unless import_source_user.reassignable_status?
|
||||
return error_invalid_assignee unless valid_assignee?(assignee_user)
|
||||
|
||||
if reassign_user
|
||||
invalid_status = false
|
||||
reassign_successful = false
|
||||
|
||||
import_source_user.with_lock do
|
||||
if import_source_user.reassignable_status?
|
||||
reassign_successful = reassign_user
|
||||
else
|
||||
invalid_status = true
|
||||
end
|
||||
end
|
||||
|
||||
return error_invalid_status if invalid_status
|
||||
|
||||
if reassign_successful
|
||||
send_user_reassign_email
|
||||
|
||||
ServiceResponse.success(payload: import_source_user)
|
||||
|
|
|
|||
|
|
@ -3,16 +3,27 @@
|
|||
module Import
|
||||
module SourceUsers
|
||||
class RejectReassignmentService < BaseService
|
||||
def initialize(import_source_user, current_user:)
|
||||
def initialize(import_source_user, current_user:, reassignment_token:)
|
||||
@import_source_user = import_source_user
|
||||
@current_user = current_user
|
||||
@reassignment_token = reassignment_token
|
||||
end
|
||||
|
||||
def execute
|
||||
return error_invalid_permissions unless current_user_matches_reassign_to_user
|
||||
return error_invalid_status unless import_source_user.awaiting_approval?
|
||||
|
||||
if reject
|
||||
invalid_permissions = false
|
||||
reject_successful = false
|
||||
|
||||
import_source_user.with_lock do
|
||||
next invalid_permissions = true unless current_user_matches_reassign_to_user? && reassignment_token_is_valid?
|
||||
|
||||
reject_successful = import_source_user.reject
|
||||
end
|
||||
|
||||
return error_invalid_permissions if invalid_permissions
|
||||
|
||||
if reject_successful
|
||||
send_user_reassign_rejected_email
|
||||
|
||||
ServiceResponse.success(payload: import_source_user)
|
||||
|
|
@ -27,14 +38,16 @@ module Import
|
|||
|
||||
private
|
||||
|
||||
def current_user_matches_reassign_to_user
|
||||
attr_reader :reassignment_token
|
||||
|
||||
def current_user_matches_reassign_to_user?
|
||||
return false if current_user.nil?
|
||||
|
||||
current_user.id == import_source_user.reassign_to_user_id
|
||||
end
|
||||
|
||||
def reject
|
||||
import_source_user.reject
|
||||
def reassignment_token_is_valid?
|
||||
reassignment_token == import_source_user.reassignment_token
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ class IssuableBaseService < ::BaseContainerService
|
|||
|
||||
# rubocop:disable Metrics/AbcSize -- Method is only slightly over the limit due to decomposition method
|
||||
def update(issuable)
|
||||
::Gitlab::Database::LoadBalancing::SessionMap.current(issuable.load_balancer).use_primary!
|
||||
::Gitlab::Database::LoadBalancing::Session.current.use_primary!
|
||||
|
||||
old_associations = associations_before_update(issuable)
|
||||
|
||||
|
|
|
|||
|
|
@ -18,9 +18,8 @@ module PersonalAccessTokens
|
|||
# would be updated when using #touch).
|
||||
return unless update?
|
||||
|
||||
lb = @personal_access_token.load_balancer
|
||||
try_obtain_lease do
|
||||
::Gitlab::Database::LoadBalancing::SessionMap.current(lb).without_sticky_writes do
|
||||
::Gitlab::Database::LoadBalancing::Session.without_sticky_writes do
|
||||
@personal_access_token.update_column(:last_used_at, Time.zone.now)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -20,8 +20,7 @@ module Users
|
|||
return unless user
|
||||
return if user.last_activity_on == Date.today
|
||||
|
||||
::Gitlab::Database::LoadBalancing::SessionMap.current(user.load_balancer)
|
||||
.without_sticky_writes { record_activity }
|
||||
::Gitlab::Database::LoadBalancing::Session.without_sticky_writes { record_activity }
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@
|
|||
|
||||
- c.with_footer do
|
||||
.gl-flex.gl-gap-3
|
||||
= render Pajamas::ButtonComponent.new(variant: :danger, method: :post, href: accept_import_source_user_path(@source_user)) do
|
||||
= render Pajamas::ButtonComponent.new(variant: :danger, method: :post, href: accept_import_source_user_path(@source_user.reassignment_token)) do
|
||||
= s_('UserMapping|Approve reassignment')
|
||||
= render Pajamas::ButtonComponent.new(method: :post, href: decline_import_source_user_path(@source_user)) do
|
||||
= render Pajamas::ButtonComponent.new(method: :post, href: decline_import_source_user_path(@source_user.reassignment_token)) do
|
||||
= s_('UserMapping|Reject')
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
%li.disabled{ 'aria-disabled': 'true', 'aria-hidden': 'true' }
|
||||
%span.gl-pagination-item{ data: { testid: testid } }
|
||||
= yield
|
||||
|
|
@ -4,5 +4,5 @@
|
|||
-# total_pages: total number of pages
|
||||
-# per_page: number of items to fetch per page
|
||||
-# remote: data-remote
|
||||
%li.page-item.disabled.gl-hidden.md:gl-block
|
||||
= link_to raw(t('views.pagination.truncate')), '#', class: 'page-link'
|
||||
%li.disabled.gl-hidden.md:gl-block
|
||||
= link_to raw(t('views.pagination.truncate')), '#', class: 'gl-pagination-item'
|
||||
|
|
|
|||
|
|
@ -6,25 +6,25 @@
|
|||
|
||||
- if paginator.has_previous_page?
|
||||
- unless without_first_and_last_pages
|
||||
%li.page-item
|
||||
%li
|
||||
- first_page_path = url_for(page_params.merge(cursor: paginator.cursor_for_first_page))
|
||||
= link_to first_page_path, rel: 'first', class: 'page-link' do
|
||||
= link_to first_page_path, rel: 'first', class: 'gl-pagination-item' do
|
||||
= sprite_icon('chevron-double-lg-left', size: 8)
|
||||
= s_('Pagination|First')
|
||||
|
||||
%li.page-item.prev
|
||||
= link_to previous_path, rel: 'prev', class: 'page-link' do
|
||||
= sprite_icon('chevron-lg-left', size: 8)
|
||||
%li
|
||||
= link_to previous_path, rel: 'prev', class: 'gl-pagination-item' do
|
||||
= sprite_icon('chevron-left')
|
||||
= s_('Pagination|Prev')
|
||||
|
||||
- if paginator.has_next_page?
|
||||
%li.page-item.next
|
||||
= link_to next_path, rel: 'next', class: 'page-link' do
|
||||
%li
|
||||
= link_to next_path, rel: 'next', class: 'gl-pagination-item' do
|
||||
= s_('Pagination|Next')
|
||||
= sprite_icon('chevron-lg-right', size: 8)
|
||||
= sprite_icon('chevron-right')
|
||||
- unless without_first_and_last_pages
|
||||
%li.page-item
|
||||
%li
|
||||
- last_page_path = url_for(page_params.merge(cursor: paginator.cursor_for_last_page))
|
||||
= link_to last_page_path, rel: 'last', class: 'page-link' do
|
||||
= link_to last_page_path, rel: 'last', class: 'gl-pagination-item' do
|
||||
= s_('Pagination|Last')
|
||||
= sprite_icon('chevron-double-lg-right', size: 8)
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@
|
|||
-# per_page: number of items to fetch per page
|
||||
-# remote: data-remote
|
||||
|
||||
- page_url = current_page.last? ? '#' : url
|
||||
- is_last_page = current_page.last?
|
||||
- view = is_last_page ? 'kaminari/gitlab/disabled_page_cursor_nav' : 'kaminari/gitlab/page_cursor_nav'
|
||||
|
||||
%li.page-item.js-next-button{ class: ('disabled' if current_page.last?) }
|
||||
= link_to page_url, rel: 'next', remote: remote, class: 'page-link' do
|
||||
= s_('Pagination|Next')
|
||||
= sprite_icon('chevron-lg-right', size: 8)
|
||||
= render view, testid: 'kaminari-pagination-next', rel: 'next', url: url, remote: remote do
|
||||
= s_('Pagination|Next')
|
||||
= sprite_icon('chevron-right')
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@
|
|||
-# total_pages: total number of pages
|
||||
-# per_page: number of items to fetch per page
|
||||
-# remote: data-remote
|
||||
%li.page-item.js-pagination-page{ class: [active_when(page.current?),
|
||||
%li.js-pagination-page{ class: [active_when(page.current?),
|
||||
('sibling' if page.next? || page.prev?),
|
||||
('js-first-button' if page.first?),
|
||||
('js-last-button' if page.last?),
|
||||
('!gl-hidden md:!gl-block' if !page.current?)] }
|
||||
= link_to page, url, { remote: remote, rel: page.next? ? 'next' : page.prev? ? 'prev' : nil, class: ['page-link', active_when(page.current?)] }
|
||||
= link_to page, url, { remote: remote, rel: page.next? ? 'next' : page.prev? ? 'prev' : nil, class: ['gl-pagination-item', active_when(page.current?)], 'data-testid': 'kaminari-pagination-item' }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
%li
|
||||
= link_to url, rel: rel, remote: local_assigns[:remote], class: 'gl-pagination-item', data: { testid: testid } do
|
||||
= yield
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
-# paginator: the paginator that renders the pagination tags inside
|
||||
= paginator.render do
|
||||
.gl-pagination.gl-mt-3
|
||||
%ul.pagination.justify-content-center
|
||||
%ul.gl-justify-center
|
||||
= prev_page_tag
|
||||
- each_page do |page|
|
||||
- if page.left_outer? || page.right_outer? || page.inside_window? || page.first? || page.last?
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@
|
|||
-# per_page: number of items to fetch per page
|
||||
-# remote: data-remote
|
||||
|
||||
- page_url = current_page.first? ? '#' : url
|
||||
- is_first_page = current_page.first?
|
||||
- view = is_first_page ? 'kaminari/gitlab/disabled_page_cursor_nav' : 'kaminari/gitlab/page_cursor_nav'
|
||||
|
||||
%li.page-item.js-previous-button{ class: ('disabled' if current_page.first?) }
|
||||
= link_to page_url, rel: 'prev', remote: remote, class: 'page-link' do
|
||||
= sprite_icon('chevron-lg-left', size: 8)
|
||||
= s_('Pagination|Prev')
|
||||
= render view, testid: 'kaminari-pagination-prev', rel: 'prev', url: url, remote: remote do
|
||||
= sprite_icon('chevron-left')
|
||||
= s_('Pagination|Prev')
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
.gl-pagination.gl-mt-3
|
||||
%ul.pagination.justify-content-center
|
||||
- if previous_path
|
||||
%li.page-item.prev
|
||||
= link_to previous_path, rel: 'prev', class: 'page-link', data: paginate_event_tracking_data_attributes(event_tracking: event_tracking, event_label: 'prev') do
|
||||
= sprite_icon('chevron-lg-left', size: 8)
|
||||
= s_('Pagination|Prev')
|
||||
- if next_path
|
||||
%li.page-item.next
|
||||
= link_to next_path, rel: 'next', class: 'page-link', data: paginate_event_tracking_data_attributes(event_tracking: event_tracking, event_label: 'next') do
|
||||
= s_('Pagination|Next')
|
||||
= sprite_icon('chevron-lg-right', size: 8)
|
||||
- prev_view = previous_path ? 'kaminari/gitlab/page_cursor_nav' : 'kaminari/gitlab/disabled_page_cursor_nav'
|
||||
- next_view = next_path ? 'kaminari/gitlab/page_cursor_nav' : 'kaminari/gitlab/disabled_page_cursor_nav'
|
||||
|
||||
- if previous_path || next_path
|
||||
.gl-pagination.gl-mt-3
|
||||
%ul.gl-justify-center
|
||||
= render prev_view, testid: 'kaminari-pagination-prev', rel: 'prev', url: previous_path, data: paginate_event_tracking_data_attributes(event_tracking: event_tracking, event_label: 'prev') do
|
||||
= sprite_icon('chevron-left')
|
||||
= s_('Pagination|Prev')
|
||||
= render next_view, testid: 'kaminari-pagination-next', rel: 'next', url: next_path, data: paginate_event_tracking_data_attributes(event_tracking: event_tracking, event_label: 'next') do
|
||||
= s_('Pagination|Next')
|
||||
= sprite_icon('chevron-right')
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
destination_group: destination_group)
|
||||
|
||||
%p{ style: text_style }
|
||||
= link_to import_source_user_url(@source_user), target: '_blank', rel: 'noopener noreferrer' do
|
||||
= link_to import_source_user_url(@source_user.reassignment_token), target: '_blank', rel: 'noopener noreferrer' do
|
||||
%button{ type: 'button', style: button_style }
|
||||
= s_('UserMapping|Review reassignment details')
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
source_hostname: source_hostname,
|
||||
destination_group: destination_group } %>
|
||||
|
||||
<%= s_('UserMapping|Review reassignment details') %>: <%= import_source_user_url(@source_user) %>
|
||||
<%= s_('UserMapping|Review reassignment details') %>: <%= import_source_user_url(@source_user.reassignment_token) %>
|
||||
|
||||
<%= s_('UserMapping|Import details:') %>
|
||||
<%= safe_format(s_('UserMapping|Imported from: %{source_hostname}'), source_hostname: source_hostname) %>
|
||||
|
|
|
|||
|
|
@ -3729,6 +3729,15 @@
|
|||
:weight: 1
|
||||
:idempotent: true
|
||||
:tags: []
|
||||
- :name: pages_delete_pages_deployment
|
||||
:worker_name: Pages::DeletePagesDeploymentWorker
|
||||
:feature_category: :pages
|
||||
:has_external_dependencies: false
|
||||
:urgency: :low
|
||||
:resource_boundary: :unknown
|
||||
:weight: 1
|
||||
:idempotent: true
|
||||
:tags: []
|
||||
- :name: pages_domain_ssl_renewal
|
||||
:worker_name: PagesDomainSslRenewalWorker
|
||||
:feature_category: :pages
|
||||
|
|
|
|||
|
|
@ -30,9 +30,7 @@ module AuthorizedProjectUpdate
|
|||
# does not allow us to deduplicate these jobs.
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/325291
|
||||
def use_replica_if_available(&block)
|
||||
::Gitlab::Database::LoadBalancing::SessionMap
|
||||
.with_sessions([::ApplicationRecord, ::Ci::ApplicationRecord])
|
||||
.use_replicas_for_read_queries(&block)
|
||||
::Gitlab::Database::LoadBalancing::Session.current.use_replicas_for_read_queries(&block)
|
||||
end
|
||||
|
||||
def project_authorizations_needs_refresh?(user)
|
||||
|
|
|
|||
|
|
@ -185,9 +185,7 @@ module ContainerExpirationPolicies
|
|||
end
|
||||
|
||||
def use_replica_if_available(&blk)
|
||||
::Gitlab::Database::LoadBalancing::SessionMap
|
||||
.with_sessions([::ApplicationRecord, ::Ci::ApplicationRecord])
|
||||
.use_replicas_for_read_queries(&blk)
|
||||
::Gitlab::Database::LoadBalancing::Session.current.use_replicas_for_read_queries(&blk)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -51,9 +51,7 @@ class ContainerExpirationPolicyWorker # rubocop:disable Scalability/IdempotentWo
|
|||
# not perfomed with a delay
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/merge_requests/63635#note_603771207
|
||||
def use_replica_if_available(&blk)
|
||||
::Gitlab::Database::LoadBalancing::SessionMap
|
||||
.current(ContainerRepository.load_balancer)
|
||||
.use_replicas_for_read_queries(&blk)
|
||||
::Gitlab::Database::LoadBalancing::Session.current.use_replicas_for_read_queries(&blk)
|
||||
end
|
||||
|
||||
def process_stale_ongoing_cleanups
|
||||
|
|
|
|||
|
|
@ -43,9 +43,7 @@ module DependencyProxy
|
|||
end
|
||||
|
||||
def use_replica_if_available(&block)
|
||||
::Gitlab::Database::LoadBalancing::SessionMap
|
||||
.with_sessions([::ApplicationRecord, ::Ci::ApplicationRecord])
|
||||
.use_replicas_for_read_queries(&block)
|
||||
::Gitlab::Database::LoadBalancing::Session.current.use_replicas_for_read_queries(&block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -53,9 +53,7 @@ module Packages
|
|||
end
|
||||
|
||||
def use_replica_if_available(&block)
|
||||
::Gitlab::Database::LoadBalancing::SessionMap
|
||||
.with_sessions([::ApplicationRecord, ::Ci::ApplicationRecord])
|
||||
.use_replicas_for_read_queries(&block)
|
||||
::Gitlab::Database::LoadBalancing::Session.current.use_replicas_for_read_queries(&block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Pages
|
||||
class DeletePagesDeploymentWorker
|
||||
include Gitlab::EventStore::Subscriber
|
||||
|
||||
data_consistency :always
|
||||
feature_category :pages
|
||||
idempotent!
|
||||
|
||||
def handle_event(event)
|
||||
project = Project.find_by_id(event.data['project_id'])
|
||||
return unless project
|
||||
|
||||
::Pages::DeleteService.new(project).execute
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
name: use_load_balancing_session_map
|
||||
feature_issue_url: https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/3834
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/166986
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/496505
|
||||
milestone: '17.5'
|
||||
group: group::scalability
|
||||
type: gitlab_com_derisk
|
||||
default_enabled: false
|
||||
|
|
@ -29,6 +29,8 @@ events:
|
|||
unique: user.id
|
||||
- name: i_package_terraform_module_user
|
||||
unique: user.id
|
||||
- name: i_package_ml_model_user
|
||||
unique: user.id
|
||||
distribution:
|
||||
- ee
|
||||
- ce
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
key_path: counts.count_total_package_ml_model_pulled_monthly
|
||||
description: Monthly count of ml_model packages pulled
|
||||
product_group: package_registry
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: '17.5'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/151919
|
||||
time_frame: 28d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
events:
|
||||
- name: pull_package_from_registry
|
||||
filter:
|
||||
label: ml_model
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
key_path: counts.count_total_push_package_ml_model_monthly
|
||||
description: Monthly count of ml_model packages pushed
|
||||
product_group: package_registry
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: '17.5'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/167298
|
||||
time_frame: 28d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
events:
|
||||
- name: push_package_to_registry
|
||||
filter:
|
||||
label: ml_model
|
||||
|
|
@ -29,6 +29,8 @@ events:
|
|||
unique: user.id
|
||||
- name: i_package_terraform_module_user
|
||||
unique: user.id
|
||||
- name: i_package_ml_model_user
|
||||
unique: user.id
|
||||
distribution:
|
||||
- ee
|
||||
- ce
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
key_path: counts.count_total_package_ml_model_pulled_weekly
|
||||
description: Weekly count of ml_model packages pulled
|
||||
product_group: package_registry
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: '17.5'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/151919
|
||||
time_frame: 7d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
events:
|
||||
- name: pull_package_from_registry
|
||||
filter:
|
||||
label: ml_model
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
key_path: counts.count_total_push_package_ml_model_weekly
|
||||
description: Weekly count of ml_model packages pushed
|
||||
product_group: package_registry
|
||||
performance_indicator_type: []
|
||||
value_type: number
|
||||
status: active
|
||||
milestone: '17.5'
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/167298
|
||||
time_frame: 7d
|
||||
data_source: internal_events
|
||||
data_category: optional
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
tier:
|
||||
- free
|
||||
- premium
|
||||
- ultimate
|
||||
events:
|
||||
- name: push_package_to_registry
|
||||
filter:
|
||||
label: ml_model
|
||||
|
|
@ -89,7 +89,7 @@ namespace :import do
|
|||
post :upload
|
||||
end
|
||||
|
||||
resources :source_users, only: [] do
|
||||
resources :source_users, param: :reassignment_token, only: [] do
|
||||
member do
|
||||
get :show
|
||||
post :accept
|
||||
|
|
|
|||
|
|
@ -595,6 +595,8 @@
|
|||
- 1
|
||||
- - pages_deactivate_mr_deployments
|
||||
- 1
|
||||
- - pages_delete_pages_deployment
|
||||
- 1
|
||||
- - pages_domain_ssl_renewal
|
||||
- 1
|
||||
- - pages_domain_verification
|
||||
|
|
@ -823,6 +825,8 @@
|
|||
- 1
|
||||
- - security_sync_policy_violation_comment
|
||||
- 1
|
||||
- - security_sync_project_policy
|
||||
- 1
|
||||
- - security_sync_scan_policies
|
||||
- 1
|
||||
- - security_unassign_redundant_policy_configurations
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
migration_job_name: BackfillIssuesCorrectWorkItemTypeId
|
||||
description: Backfills column issues.correct_work_item_type_id
|
||||
feature_category: team_planning
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/167972
|
||||
milestone: '17.5'
|
||||
queued_migration_version: 20241002185804
|
||||
finalized_by: # version of the migration that finalized this BBM
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
---
|
||||
migration_job_name: BackfillSbomOccurrencesTraversalIdsAndArchived
|
||||
description: 'Backfills sbom_occurrences.traversal_ids and sbom_occurrences.archived
|
||||
columns with values from sbom_occurrences.project.namespace.traversal_ids and sbom_occurrences.project.archived.
|
||||
|
||||
'
|
||||
feature_category: dependency_management
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/144802
|
||||
milestone: '16.10'
|
||||
queued_migration_version: 20240214203242
|
||||
finalized_by: '20240626231944'
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
migration_job_name: FixPickUpAtCiDeletedObject
|
||||
description: Fix ci_deleted_objects#pick_up_at column so records get purged
|
||||
feature_category: job_artifacts
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/165778
|
||||
milestone: '17.5'
|
||||
queued_migration_version: 20241004064933
|
||||
finalized_by: # version of the migration that finalized this BBM
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddReassignmentTokenToImportSourceUsers < Gitlab::Database::Migration[2.2]
|
||||
disable_ddl_transaction!
|
||||
milestone '17.5'
|
||||
|
||||
def up
|
||||
add_column :import_source_users, :reassignment_token, :text
|
||||
add_concurrent_index :import_source_users, :reassignment_token, unique: true
|
||||
add_text_limit :import_source_users, :reassignment_token, 32
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column :import_source_users, :reassignment_token, :text
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class InitializeConversionOfIssuesIntegerIdsToBigint < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.5'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
TABLE = :issues
|
||||
COLUMNS = %i[author_id closed_by_id duplicated_to_id id last_edited_by_id milestone_id moved_to_id
|
||||
project_id promoted_to_epic_id updated_by_id]
|
||||
|
||||
def up
|
||||
initialize_conversion_of_integer_to_bigint(TABLE, COLUMNS)
|
||||
end
|
||||
|
||||
def down
|
||||
revert_initialize_conversion_of_integer_to_bigint(TABLE, COLUMNS)
|
||||
end
|
||||
end
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class QueueBackfillSbomOccurrencesTraversalIdsAndArchived < Gitlab::Database::Migration[2.2]
|
||||
milestone '16.10'
|
||||
|
||||
MIGRATION = "BackfillSbomOccurrencesTraversalIdsAndArchived"
|
||||
DELAY_INTERVAL = 2.minutes
|
||||
BATCH_SIZE = 10_000
|
||||
SUB_BATCH_SIZE = 100
|
||||
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_sec
|
||||
|
||||
def up
|
||||
queue_batched_background_migration(
|
||||
MIGRATION,
|
||||
:sbom_occurrences,
|
||||
:id,
|
||||
job_interval: DELAY_INTERVAL,
|
||||
batch_size: BATCH_SIZE,
|
||||
sub_batch_size: SUB_BATCH_SIZE
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
delete_batched_background_migration(MIGRATION, :sbom_occurrences, :id, [])
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class QueueBackfillIssuesCorrectWorkItemTypeId < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.5'
|
||||
|
||||
# Select the applicable gitlab schema for your batched background migration
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_main
|
||||
|
||||
MIGRATION = "BackfillIssuesCorrectWorkItemTypeId"
|
||||
DELAY_INTERVAL = 2.minutes
|
||||
BATCH_SIZE = 10_000
|
||||
MAX_BATCH_SIZE = 30_000
|
||||
SUB_BATCH_SIZE = 50
|
||||
|
||||
def up
|
||||
queue_batched_background_migration(
|
||||
MIGRATION,
|
||||
:issues,
|
||||
:id,
|
||||
job_interval: DELAY_INTERVAL,
|
||||
batch_size: BATCH_SIZE,
|
||||
max_batch_size: MAX_BATCH_SIZE,
|
||||
sub_batch_size: SUB_BATCH_SIZE
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
delete_batched_background_migration(MIGRATION, :issues, :id, [])
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class QueueFixPickUpAtCiDeletedObject < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.5'
|
||||
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_ci
|
||||
|
||||
MIGRATION = "FixPickUpAtCiDeletedObject"
|
||||
DELAY_INTERVAL = 2.minutes
|
||||
BATCH_SIZE = 25_000
|
||||
SUB_BATCH_SIZE = 150
|
||||
GITLAB_OPTIMIZED_BATCH_SIZE = 75_000
|
||||
GITLAB_OPTIMIZED_SUB_BATCH_SIZE = 250
|
||||
|
||||
def up
|
||||
queue_batched_background_migration(
|
||||
MIGRATION,
|
||||
:ci_deleted_objects,
|
||||
:id,
|
||||
job_interval: DELAY_INTERVAL,
|
||||
**batch_sizes
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
delete_batched_background_migration(MIGRATION, :ci_deleted_objects, :id, [])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def batch_sizes
|
||||
if Gitlab.com_except_jh?
|
||||
{
|
||||
batch_size: GITLAB_OPTIMIZED_BATCH_SIZE,
|
||||
sub_batch_size: GITLAB_OPTIMIZED_SUB_BATCH_SIZE
|
||||
}
|
||||
else
|
||||
{
|
||||
batch_size: BATCH_SIZE,
|
||||
sub_batch_size: SUB_BATCH_SIZE
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1 +0,0 @@
|
|||
c8fb4783e43e1276a74b0890c35b51ed4dd2fc15ea9855be1def9fca221d7d5f
|
||||
|
|
@ -0,0 +1 @@
|
|||
1a74228cbfeb2795e3ea6c544cfedee3b3f809e86bd379cd89bfec748be17ded
|
||||
|
|
@ -0,0 +1 @@
|
|||
83921a692be7211db743282ff5227815d743ca87c764101fce59a6d4a62a083c
|
||||
|
|
@ -0,0 +1 @@
|
|||
edea1b1c817159aa2440b01d4f070df06e3cb310c988a87324bb4b2da044f8d1
|
||||
|
|
@ -0,0 +1 @@
|
|||
4ae367e0a34f81246d2ff0d7d021447d2ffd01c03f463d07502df186aa708cc4
|
||||
|
|
@ -1065,6 +1065,24 @@ RETURN NEW;
|
|||
END
|
||||
$$;
|
||||
|
||||
CREATE FUNCTION trigger_22262f5f16d8() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
NEW."author_id_convert_to_bigint" := NEW."author_id";
|
||||
NEW."closed_by_id_convert_to_bigint" := NEW."closed_by_id";
|
||||
NEW."duplicated_to_id_convert_to_bigint" := NEW."duplicated_to_id";
|
||||
NEW."id_convert_to_bigint" := NEW."id";
|
||||
NEW."last_edited_by_id_convert_to_bigint" := NEW."last_edited_by_id";
|
||||
NEW."milestone_id_convert_to_bigint" := NEW."milestone_id";
|
||||
NEW."moved_to_id_convert_to_bigint" := NEW."moved_to_id";
|
||||
NEW."project_id_convert_to_bigint" := NEW."project_id";
|
||||
NEW."promoted_to_epic_id_convert_to_bigint" := NEW."promoted_to_epic_id";
|
||||
NEW."updated_by_id_convert_to_bigint" := NEW."updated_by_id";
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE FUNCTION trigger_248cafd363ff() RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
|
|
@ -12278,11 +12296,13 @@ CREATE TABLE import_source_users (
|
|||
import_type text NOT NULL,
|
||||
reassigned_by_user_id bigint,
|
||||
reassignment_error text,
|
||||
reassignment_token text,
|
||||
CONSTRAINT check_05708218cd CHECK ((char_length(reassignment_error) <= 255)),
|
||||
CONSTRAINT check_0d7295a307 CHECK ((char_length(import_type) <= 255)),
|
||||
CONSTRAINT check_199c28ec54 CHECK ((char_length(source_username) <= 255)),
|
||||
CONSTRAINT check_562655155f CHECK ((char_length(source_name) <= 255)),
|
||||
CONSTRAINT check_cc9d4093b5 CHECK ((char_length(source_user_identifier) <= 255)),
|
||||
CONSTRAINT check_cd2edb9334 CHECK ((char_length(reassignment_token) <= 32)),
|
||||
CONSTRAINT check_e2039840c5 CHECK ((char_length(source_hostname) <= 255))
|
||||
);
|
||||
|
||||
|
|
@ -12965,6 +12985,16 @@ CREATE TABLE issues (
|
|||
tmp_epic_id bigint,
|
||||
imported_from smallint DEFAULT 0 NOT NULL,
|
||||
correct_work_item_type_id bigint DEFAULT 0 NOT NULL,
|
||||
author_id_convert_to_bigint bigint,
|
||||
closed_by_id_convert_to_bigint bigint,
|
||||
duplicated_to_id_convert_to_bigint bigint,
|
||||
id_convert_to_bigint bigint DEFAULT 0 NOT NULL,
|
||||
last_edited_by_id_convert_to_bigint bigint,
|
||||
milestone_id_convert_to_bigint bigint,
|
||||
moved_to_id_convert_to_bigint bigint,
|
||||
project_id_convert_to_bigint bigint,
|
||||
promoted_to_epic_id_convert_to_bigint bigint,
|
||||
updated_by_id_convert_to_bigint bigint,
|
||||
CONSTRAINT check_2addf801cd CHECK ((work_item_type_id IS NOT NULL)),
|
||||
CONSTRAINT check_c33362cd43 CHECK ((namespace_id IS NOT NULL)),
|
||||
CONSTRAINT check_fba63f706d CHECK ((lock_version IS NOT NULL))
|
||||
|
|
@ -29284,6 +29314,8 @@ CREATE INDEX index_import_source_users_on_placeholder_user_id ON import_source_u
|
|||
|
||||
CREATE INDEX index_import_source_users_on_reassigned_by_user_id ON import_source_users USING btree (reassigned_by_user_id);
|
||||
|
||||
CREATE UNIQUE INDEX index_import_source_users_on_reassignment_token ON import_source_users USING btree (reassignment_token);
|
||||
|
||||
CREATE INDEX index_imported_projects_on_import_type_creator_id_created_at ON projects USING btree (import_type, creator_id, created_at) WHERE (import_type IS NOT NULL);
|
||||
|
||||
CREATE INDEX index_imported_projects_on_import_type_id ON projects USING btree (import_type, id) WHERE (import_type IS NOT NULL);
|
||||
|
|
@ -33678,6 +33710,8 @@ CREATE TRIGGER trigger_207005e8e995 BEFORE INSERT OR UPDATE ON operations_strate
|
|||
|
||||
CREATE TRIGGER trigger_219952df8fc4 BEFORE INSERT OR UPDATE ON merge_request_blocks FOR EACH ROW EXECUTE FUNCTION trigger_219952df8fc4();
|
||||
|
||||
CREATE TRIGGER trigger_22262f5f16d8 BEFORE INSERT OR UPDATE ON issues FOR EACH ROW EXECUTE FUNCTION trigger_22262f5f16d8();
|
||||
|
||||
CREATE TRIGGER trigger_248cafd363ff BEFORE INSERT OR UPDATE ON packages_npm_metadata FOR EACH ROW EXECUTE FUNCTION trigger_248cafd363ff();
|
||||
|
||||
CREATE TRIGGER trigger_2514245c7fc5 BEFORE INSERT OR UPDATE ON dast_site_profile_secret_variables FOR EACH ROW EXECUTE FUNCTION trigger_2514245c7fc5();
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ To create a thread:
|
|||
> - Resolvable threads for issues [enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/31114) in GitLab 16.4.
|
||||
> - Resolvable threads for issues [generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/31114) in GitLab 16.7. Feature flag `resolvable_issue_threads` removed.
|
||||
> - Resolvable threads for tasks, objectives, and key results [generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/458818) in GitLab 17.3.
|
||||
> - Resolvable threads for epics [introduced](https://gitlab.com/groups/gitlab-org/-/epics/458818) in GitLab 17.5. Your administrator must have [enabled the new look for epics](../group/epics/epic_work_items.md).
|
||||
> - Resolvable threads for epics [introduced](https://gitlab.com/groups/gitlab-org/-/issues/458818) in GitLab 17.5. Your administrator must have [enabled the new look for epics](../group/epics/epic_work_items.md).
|
||||
|
||||
You can resolve a thread when you want to finish a conversation.
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,8 @@ Prerequisites:
|
|||
|
||||
- A custom domain name `example.com` or subdomain `subdomain.example.com`.
|
||||
- Access to your domain's server control panel to set up a DNS `TXT` record to verify your domain's ownership.
|
||||
- A project in the group. This project will be linked to the verified domains, and should not be deleted.
|
||||
- A project in the group. This project will be linked to the verified domains, and should not be deleted.
|
||||
- Ensure that [GitLab Pages](../project/pages/index.md) is enabled for the project. If GitLab Pages is disabled, adding the domain might result in an error.
|
||||
- You must have the Owner role for the top-level group.
|
||||
|
||||
Domain verification applies at the top-level group and to all subgroups and projects
|
||||
|
|
|
|||
|
|
@ -101,10 +101,7 @@ module API
|
|||
end
|
||||
|
||||
def authenticate_job_via_dependent_job!
|
||||
# Use primary for both main and ci database as authenticating in the scope of runners will load
|
||||
# Ci::Build model and other standard authn related models like License, Project and User.
|
||||
::Gitlab::Database::LoadBalancing::SessionMap
|
||||
.with_sessions([::ApplicationRecord, ::Ci::ApplicationRecord]).use_primary { authenticate! }
|
||||
::Gitlab::Database::LoadBalancing::Session.current.use_primary { authenticate! }
|
||||
|
||||
forbidden! unless current_job
|
||||
forbidden! unless can?(current_user, :read_build, current_job)
|
||||
|
|
|
|||
|
|
@ -266,8 +266,7 @@ module API
|
|||
# so we need to skip the second FIPS check here.
|
||||
file_name, format = extract_format(params[:file_name], skip_fips_check: true)
|
||||
|
||||
lb = ::ApplicationRecord.load_balancer
|
||||
::Gitlab::Database::LoadBalancing::SessionMap.current(lb).use_primary do
|
||||
::Gitlab::Database::LoadBalancing::Session.current.use_primary do
|
||||
result = ::Packages::Maven::FindOrCreatePackageService
|
||||
.new(user_project, current_user, params.merge(build: current_authenticated_job)).execute
|
||||
|
||||
|
|
|
|||
|
|
@ -136,6 +136,8 @@ module API
|
|||
|
||||
bad_request!(s_('MlModelRegistry|Artifact file creation failed')) unless package_file
|
||||
|
||||
track_package_event('push_package', :ml_model, project: project, namespace: project.namespace)
|
||||
|
||||
created!
|
||||
rescue ObjectStorage::RemoteStoreError => e
|
||||
Gitlab::ErrorTracking.track_exception(e, extra: { file_name: params[:file_name], project_id: project.id })
|
||||
|
|
@ -157,6 +159,8 @@ module API
|
|||
|
||||
package_file = ::Packages::PackageFileFinder.new(package, file_name).execute!
|
||||
|
||||
track_package_event('pull_package', :ml_model, project: project, namespace: project.namespace)
|
||||
|
||||
present_package_file!(package_file)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -471,8 +471,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def find_build_by_token(token)
|
||||
::Gitlab::Database::LoadBalancing::SessionMap
|
||||
.with_sessions([::ApplicationRecord, ::Ci::ApplicationRecord]).use_primary do
|
||||
::Gitlab::Database::LoadBalancing::Session.current.use_primary do
|
||||
::Ci::AuthJobFinder.new(token: token).execute
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module BackgroundMigration
|
||||
class BackfillIssuesCorrectWorkItemTypeId < BatchedMigrationJob
|
||||
operation_name :update_issues_correct_work_item_type_id
|
||||
feature_category :team_planning
|
||||
|
||||
def perform
|
||||
each_sub_batch do |sub_batch|
|
||||
first, last = sub_batch.pick(Arel.sql('min(id), max(id)'))
|
||||
|
||||
connection.execute(
|
||||
<<~SQL
|
||||
UPDATE
|
||||
"issues"
|
||||
SET
|
||||
"correct_work_item_type_id" = "work_item_types"."correct_id",
|
||||
"author_id_convert_to_bigint" = "issues"."author_id",
|
||||
"closed_by_id_convert_to_bigint" = "issues"."closed_by_id",
|
||||
"duplicated_to_id_convert_to_bigint" = "issues"."duplicated_to_id",
|
||||
"id_convert_to_bigint" = "issues"."id",
|
||||
"last_edited_by_id_convert_to_bigint" = "issues"."last_edited_by_id",
|
||||
"milestone_id_convert_to_bigint" = "issues"."milestone_id",
|
||||
"moved_to_id_convert_to_bigint" = "issues"."moved_to_id",
|
||||
"project_id_convert_to_bigint" = "issues"."project_id",
|
||||
"promoted_to_epic_id_convert_to_bigint" = "issues"."promoted_to_epic_id",
|
||||
"updated_by_id_convert_to_bigint" = "issues"."updated_by_id"
|
||||
FROM
|
||||
"work_item_types"
|
||||
WHERE
|
||||
"issues"."work_item_type_id" = "work_item_types"."id"
|
||||
AND "issues"."id" BETWEEN #{first}
|
||||
AND #{last}
|
||||
SQL
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module BackgroundMigration
|
||||
class BackfillSbomOccurrencesTraversalIdsAndArchived < BatchedMigrationJob
|
||||
feature_category :dependency_management
|
||||
operation_name :backfill_sbom_occurrences_traversal_ids_and_archived
|
||||
|
||||
def perform
|
||||
each_sub_batch do |relation|
|
||||
batch_start_id, batch_end_id = relation.pick(Arel.sql("MIN(#{batch_column}), MAX(#{batch_column})"))
|
||||
::Gitlab::Database.allow_cross_joins_across_databases(
|
||||
url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/477830'
|
||||
) do
|
||||
connection.exec_update(update_sql(batch_start_id, batch_end_id))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_sql(batch_start_id, batch_end_id)
|
||||
<<~SQL
|
||||
UPDATE
|
||||
sbom_occurrences
|
||||
SET
|
||||
traversal_ids = namespaces.traversal_ids,
|
||||
archived = projects.archived
|
||||
FROM
|
||||
projects JOIN namespaces ON namespaces.id = projects.namespace_id
|
||||
WHERE
|
||||
sbom_occurrences.project_id = projects.id AND
|
||||
sbom_occurrences.id >= #{batch_start_id} AND
|
||||
sbom_occurrences.id <= #{batch_end_id}
|
||||
SQL
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module BackgroundMigration
|
||||
class FixPickUpAtCiDeletedObject < BatchedMigrationJob
|
||||
operation_name :fix_pick_up_at_ci_deleted_objects
|
||||
feature_category :job_artifacts
|
||||
|
||||
def perform
|
||||
each_sub_batch do |sub_batch|
|
||||
sub_batch
|
||||
.where('pick_up_at > ?', 15.minutes.from_now)
|
||||
.update_all("pick_up_at = least(pick_up_at, now() + '1 hour'::interval)")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -28,7 +28,7 @@ module Gitlab
|
|||
# the write location to ensure the replica can make this query.
|
||||
# Adding use_primary_on_empty_location: true for extra precaution in case there happens to be
|
||||
# no LSN saved for the project then we will use the primary.
|
||||
track_session_metrics(::ApplicationRecord.load_balancer) do
|
||||
track_session_metrics do
|
||||
::ApplicationRecord.sticking.find_caught_up_replica(:project, @project.id, use_primary_on_empty_location: true)
|
||||
end
|
||||
|
||||
|
|
@ -42,12 +42,12 @@ module Gitlab
|
|||
|
||||
private
|
||||
|
||||
def track_session_metrics(lb)
|
||||
before = ::Gitlab::Database::LoadBalancing::SessionMap.current(lb).use_primary?
|
||||
def track_session_metrics
|
||||
before = ::Gitlab::Database::LoadBalancing::Session.current.use_primary?
|
||||
|
||||
yield
|
||||
|
||||
after = ::Gitlab::Database::LoadBalancing::SessionMap.current(lb).use_primary?
|
||||
after = ::Gitlab::Database::LoadBalancing::Session.current.use_primary?
|
||||
|
||||
increment_attempt_count
|
||||
|
||||
|
|
|
|||
|
|
@ -214,10 +214,10 @@ module Gitlab
|
|||
# Calls to #uncached only disable caching for the current connection. Since the load balancer
|
||||
# can potentially upgrade from read to read-write mode (using a different connection), we specify
|
||||
# up-front that we'll explicitly use the primary for the duration of the operation.
|
||||
base_models = database_base_models_using_load_balancing.values
|
||||
base_models.reduce(block) do |blk, model|
|
||||
-> { Gitlab::Database::LoadBalancing::SessionMap.current(model.load_balancer).use_primary { model.uncached(&blk) } }
|
||||
end.call
|
||||
Gitlab::Database::LoadBalancing::Session.current.use_primary do
|
||||
base_models = database_base_models_using_load_balancing.values
|
||||
base_models.reduce(block) { |blk, model| -> { model.uncached(&blk) } }.call
|
||||
end
|
||||
end
|
||||
|
||||
def self.allow_cross_joins_across_databases(url:)
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@ module Gitlab
|
|||
DEFAULT_INDEXES_PER_INVOCATION = 2
|
||||
|
||||
def self.create_pending_indexes!(how_many: DEFAULT_INDEXES_PER_INVOCATION)
|
||||
PostgresAsyncIndex.to_create.order(:id).limit(how_many).each do |async_index|
|
||||
PostgresAsyncIndex.to_create.ordered.limit(how_many).each do |async_index|
|
||||
IndexCreator.new(async_index).perform
|
||||
end
|
||||
end
|
||||
|
||||
def self.drop_pending_indexes!(how_many: DEFAULT_INDEXES_PER_INVOCATION)
|
||||
PostgresAsyncIndex.to_drop.order(:id).limit(how_many).each do |async_index|
|
||||
PostgresAsyncIndex.to_drop.ordered.limit(how_many).each do |async_index|
|
||||
IndexDestructor.new(async_index).perform
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,9 +13,8 @@ module Gitlab
|
|||
# require read consistency after recent writes.
|
||||
#
|
||||
def self.with_read_consistency(&block)
|
||||
::Gitlab::Database::LoadBalancing::SessionMap
|
||||
.with_sessions(Gitlab::Database::LoadBalancing.base_models)
|
||||
.use_primary(&block)
|
||||
::Gitlab::Database::LoadBalancing::Session
|
||||
.current.use_primary(&block)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ module Gitlab
|
|||
|
||||
# Returns number of WAL segments pending archival
|
||||
def pending_wal_count
|
||||
Gitlab::Database::LoadBalancing::SessionMap.current(connection.load_balancer).use_primary do
|
||||
Gitlab::Database::LoadBalancing::Session.current.use_primary do
|
||||
connection.execute(PENDING_WAL_COUNT_SQL).to_a.first&.fetch('pending_wal_count')
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -34,10 +34,6 @@ module Gitlab
|
|||
each_load_balancer.all?(&:primary_only?)
|
||||
end
|
||||
|
||||
def self.primary?(name)
|
||||
each_load_balancer.find { |c| c.name == name }&.primary_only?
|
||||
end
|
||||
|
||||
def self.release_hosts
|
||||
each_load_balancer(&:release_host)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ module Gitlab
|
|||
inner.call
|
||||
ensure
|
||||
::Gitlab::Database::LoadBalancing.release_hosts
|
||||
::Gitlab::Database::LoadBalancing::SessionMap.clear_session
|
||||
::Gitlab::Database::LoadBalancing::Session.clear_session
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ module Gitlab
|
|||
private
|
||||
|
||||
def current_session
|
||||
::Gitlab::Database::LoadBalancing::SessionMap.current(@load_balancer)
|
||||
::Gitlab::Database::LoadBalancing::Session.current
|
||||
end
|
||||
|
||||
def track_read_only_transaction!
|
||||
|
|
|
|||
|
|
@ -45,17 +45,18 @@ module Gitlab
|
|||
|
||||
# Determine if we need to stick after handling a request.
|
||||
def stick_if_necessary(env)
|
||||
return unless ::Gitlab::Database::LoadBalancing::Session.current.performed_write?
|
||||
|
||||
namespaces_and_ids = sticking_namespaces(env)
|
||||
|
||||
namespaces_and_ids.each do |sticking, namespace, id|
|
||||
lb = sticking.load_balancer
|
||||
sticking.stick(namespace, id) if ::Gitlab::Database::LoadBalancing::SessionMap.current(lb).performed_write?
|
||||
sticking.stick(namespace, id)
|
||||
end
|
||||
end
|
||||
|
||||
def clear
|
||||
::Gitlab::Database::LoadBalancing.release_hosts
|
||||
::Gitlab::Database::LoadBalancing::SessionMap.clear_session
|
||||
::Gitlab::Database::LoadBalancing::Session.clear_session
|
||||
end
|
||||
|
||||
# Determines the sticking namespace and identifier based on the Rack
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ module Gitlab
|
|||
ensure
|
||||
@ignore_writes = false
|
||||
end
|
||||
alias_method :without_sticky_writes, :ignore_writes
|
||||
|
||||
# Indicates that the read SQL statements from anywhere inside this
|
||||
# blocks should use a replica, regardless of the current primary
|
||||
|
|
|
|||
|
|
@ -1,128 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module Database
|
||||
module LoadBalancing
|
||||
class SessionMap
|
||||
CACHE_KEY = :gitlab_load_balancer_session_map
|
||||
|
||||
InvalidLoadBalancerNameError = Class.new(StandardError)
|
||||
|
||||
# lb - Gitlab::Database::LoadBalancing::LoadBalancer instance
|
||||
def self.current(lb)
|
||||
return cached_instance.lookup(lb) if use_session_map?
|
||||
|
||||
Session.current
|
||||
end
|
||||
|
||||
# models - Array<ActiveRecord::Base>
|
||||
def self.with_sessions(models)
|
||||
dbs = models.map { |m| m.load_balancer.name }.uniq
|
||||
dbs.each { |db| cached_instance.validate_db_name(db) }
|
||||
ScopedSessions.new(dbs, cached_instance.session_map)
|
||||
end
|
||||
|
||||
def self.clear_session
|
||||
return RequestStore.delete(CACHE_KEY) if use_session_map?
|
||||
|
||||
Session.clear_session
|
||||
end
|
||||
|
||||
def self.without_sticky_writes(&)
|
||||
return with_sessions(Gitlab::Database::LoadBalancing.base_models).ignore_writes(&) if use_session_map?
|
||||
|
||||
Session.without_sticky_writes(&)
|
||||
end
|
||||
|
||||
def self.use_session_map?
|
||||
::Feature.enabled?(:use_load_balancing_session_map, :current_request, type: :gitlab_com_derisk)
|
||||
rescue ActiveRecord::StatementInvalid,
|
||||
Gitlab::Database::QueryAnalyzers::Base::QueryAnalyzerError
|
||||
# If the feature_gates table is missing, we should default to a false.
|
||||
# In a migration scope, we also rescue and default to false.
|
||||
false
|
||||
end
|
||||
private_class_method :use_session_map?
|
||||
|
||||
def self.cached_instance
|
||||
RequestStore[CACHE_KEY] ||= new
|
||||
end
|
||||
private_class_method :cached_instance
|
||||
|
||||
attr_reader :session_map
|
||||
|
||||
def initialize
|
||||
@session_map = Gitlab::Database.all_database_names.to_h do |k|
|
||||
[k.to_sym, Gitlab::Database::LoadBalancing::Session.new]
|
||||
end
|
||||
|
||||
@session_map[:primary] = Gitlab::Database::LoadBalancing::Session.new
|
||||
end
|
||||
|
||||
def lookup(lb)
|
||||
name = lb.name
|
||||
validate_db_name(name)
|
||||
session_map[name]
|
||||
end
|
||||
|
||||
def validate_db_name(db)
|
||||
# Allow :primary only for rake task db migrations as ActiveRecord::Tasks::PostgresqlDatabaseTasks calls
|
||||
# .establish_connection using a hash which resets the name from :main/:ci to :primary.
|
||||
# See
|
||||
# https://github.com/rails/rails/blob/v7.0.8.4/activerecord/lib/active_record/tasks/postgresql_database_tasks.rb#L97
|
||||
#
|
||||
# In the case of derailed test in memory-on-boot job, the runtime is unknown.
|
||||
return if db == :primary && (Gitlab::Runtime.rake? || Gitlab::Runtime.safe_identify.nil?)
|
||||
|
||||
# Disallow :primary usage outside of rake or unknown runtimes as the db config should be
|
||||
# main/ci/embedding/ci/geo.
|
||||
return if db != :primary && session_map[db]
|
||||
|
||||
raise InvalidLoadBalancerNameError, "Invalid load balancer name #{db} in #{Gitlab::Runtime.safe_identify}."
|
||||
end
|
||||
end
|
||||
|
||||
class ScopedSessions
|
||||
attr_reader :scoped_sessions
|
||||
|
||||
def initialize(scope, session_map)
|
||||
@scope = scope
|
||||
@scoped_sessions = session_map.slice(*@scope).values
|
||||
end
|
||||
|
||||
def use_primary!
|
||||
scoped_sessions.each(&:use_primary!)
|
||||
end
|
||||
|
||||
def ignore_writes(&)
|
||||
nest_sessions(scoped_sessions, :without_sticky_writes, &)
|
||||
end
|
||||
|
||||
def use_primary(&)
|
||||
nest_sessions(scoped_sessions, :use_primary, &)
|
||||
end
|
||||
|
||||
def use_replicas_for_read_queries(&)
|
||||
nest_sessions(scoped_sessions, :use_replicas_for_read_queries, &)
|
||||
end
|
||||
|
||||
def fallback_to_replicas_for_ambiguous_queries(&)
|
||||
nest_sessions(scoped_sessions, :fallback_to_replicas_for_ambiguous_queries, &)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def nest_sessions(sessions, method, &block)
|
||||
if sessions.empty?
|
||||
yield if block
|
||||
else
|
||||
session = sessions.shift
|
||||
session.public_send(method) do # rubocop: disable GitlabSecurity/PublicSend -- methods are verified
|
||||
nest_sessions(sessions, method, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -34,7 +34,19 @@ module Gitlab
|
|||
|
||||
def set_data_consistency_locations!(job)
|
||||
job['wal_locations'] = wal_locations_by_db_name
|
||||
job['wal_location_sources'] = wal_location_sources_by_db_name
|
||||
job['wal_location_source'] = wal_location_source
|
||||
end
|
||||
|
||||
def wal_location_source
|
||||
if ::Gitlab::Database::LoadBalancing.primary_only? || uses_primary?
|
||||
::Gitlab::Database::LoadBalancing::ROLE_PRIMARY
|
||||
else
|
||||
::Gitlab::Database::LoadBalancing::ROLE_REPLICA
|
||||
end
|
||||
end
|
||||
|
||||
def uses_primary?
|
||||
::Gitlab::Database::LoadBalancing::Session.current.use_primary?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,9 +22,7 @@ module Gitlab
|
|||
job['load_balancing_strategy'] = strategy.to_s
|
||||
|
||||
if use_primary?(strategy)
|
||||
::Gitlab::Database::LoadBalancing::SessionMap
|
||||
.with_sessions(Gitlab::Database::LoadBalancing.base_models)
|
||||
.use_primary!
|
||||
::Gitlab::Database::LoadBalancing::Session.current.use_primary!
|
||||
elsif strategy == :retry
|
||||
raise JobReplicaNotUpToDate, "Sidekiq job #{resolved_class} JID-#{job['jid']} couldn't use the replica. "\
|
||||
"Replica was not up to date."
|
||||
|
|
@ -41,7 +39,7 @@ module Gitlab
|
|||
|
||||
def clear
|
||||
::Gitlab::Database::LoadBalancing.release_hosts
|
||||
::Gitlab::Database::LoadBalancing::SessionMap.clear_session
|
||||
::Gitlab::Database::LoadBalancing::Session.clear_session
|
||||
end
|
||||
|
||||
def use_primary?(strategy)
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ module Gitlab
|
|||
# the primary.
|
||||
EXPIRATION = 30
|
||||
|
||||
attr_reader :load_balancer
|
||||
|
||||
def initialize(load_balancer)
|
||||
@load_balancer = load_balancer
|
||||
end
|
||||
|
|
@ -37,7 +35,7 @@ module Gitlab
|
|||
!use_primary_on_empty_location
|
||||
end
|
||||
|
||||
use_primary! if !result && use_primary_on_failure
|
||||
::Gitlab::Database::LoadBalancing::Session.current.use_primary! if !result && use_primary_on_failure
|
||||
|
||||
result
|
||||
end
|
||||
|
|
@ -48,7 +46,7 @@ module Gitlab
|
|||
with_primary_write_location do |location|
|
||||
set_write_location_for(namespace, id, location)
|
||||
end
|
||||
use_primary!
|
||||
::Gitlab::Database::LoadBalancing::Session.current.use_primary!
|
||||
end
|
||||
|
||||
def bulk_stick(namespace, ids)
|
||||
|
|
@ -58,7 +56,7 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
|
||||
use_primary!
|
||||
::Gitlab::Database::LoadBalancing::Session.current.use_primary!
|
||||
end
|
||||
|
||||
private
|
||||
|
|
@ -102,10 +100,6 @@ module Gitlab
|
|||
def with_redis(&block)
|
||||
Gitlab::Redis::DbLoadBalancing.with(&block)
|
||||
end
|
||||
|
||||
def use_primary!
|
||||
::Gitlab::Database::LoadBalancing::SessionMap.current(@load_balancer).use_primary!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -18,31 +18,12 @@ module Gitlab
|
|||
# When only using the primary there's no need for any WAL queries.
|
||||
return if load_balancer.primary_only?
|
||||
|
||||
if SessionMap.current(load_balancer).use_primary?
|
||||
if Session.current.use_primary?
|
||||
load_balancer.primary_write_location
|
||||
else
|
||||
load_balancer.host&.database_replica_location || load_balancer.primary_write_location
|
||||
end
|
||||
end
|
||||
|
||||
def wal_location_sources_by_db_name
|
||||
{}.tap do |locations|
|
||||
::Gitlab::Database::LoadBalancing.each_load_balancer do |lb|
|
||||
if (location = wal_location_source(lb))
|
||||
locations[lb.name] = location
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def wal_location_source(lb)
|
||||
if ::Gitlab::Database::LoadBalancing.primary?(lb.name) ||
|
||||
::Gitlab::Database::LoadBalancing::SessionMap.current(lb).use_primary?
|
||||
::Gitlab::Database::LoadBalancing::ROLE_PRIMARY
|
||||
else
|
||||
::Gitlab::Database::LoadBalancing::ROLE_REPLICA
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def primary_transaction(statement_timeout: nil)
|
||||
Gitlab::Database::LoadBalancing::SessionMap.current(connection.load_balancer).use_primary do
|
||||
Gitlab::Database::LoadBalancing::Session.current.use_primary do
|
||||
connection.transaction(requires_new: false) do
|
||||
if statement_timeout.present?
|
||||
connection.execute(
|
||||
|
|
|
|||
|
|
@ -9,9 +9,7 @@ module Gitlab
|
|||
scope :wraparound_prevention, -> { where(wraparound_prevention: true) }
|
||||
|
||||
def self.for_tables(tables)
|
||||
Gitlab::Database::LoadBalancing::SessionMap
|
||||
.current(connection.load_balancer)
|
||||
.use_primary do
|
||||
Gitlab::Database::LoadBalancing::Session.current.use_primary do
|
||||
# calling `.to_a` here to execute the query in the primary's scope
|
||||
# and to avoid having the scope chained and re-executed
|
||||
#
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ module Gitlab
|
|||
actor = ::Group.actor_from_id(event.data[:namespace_id])
|
||||
Feature.enabled?(:track_member_activity, actor)
|
||||
end
|
||||
store.subscribe ::Pages::DeletePagesDeploymentWorker, to: ::Projects::ProjectArchivedEvent
|
||||
end
|
||||
private_class_method :configure!
|
||||
end
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue