Commit 60ac00b0 authored by Nick Thomas's avatar Nick Thomas

Allow repository verification concurrency to be controlled on primary and secondary

parent 8f69639e
...@@ -24,6 +24,8 @@ lib/gitlab/git/tag.rb ...@@ -24,6 +24,8 @@ lib/gitlab/git/tag.rb
ee/db/**/* ee/db/**/*
ee/app/serializers/ee/merge_request_widget_entity.rb ee/app/serializers/ee/merge_request_widget_entity.rb
ee/lib/api/epics.rb
ee/lib/api/geo_nodes.rb
ee/lib/ee/gitlab/ldap/sync/admin_users.rb ee/lib/ee/gitlab/ldap/sync/admin_users.rb
ee/app/workers/geo/file_download_dispatch_worker/job_artifact_job_finder.rb ee/app/workers/geo/file_download_dispatch_worker/job_artifact_job_finder.rb
ee/app/workers/geo/file_download_dispatch_worker/lfs_object_job_finder.rb ee/app/workers/geo/file_download_dispatch_worker/lfs_object_job_finder.rb
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20180608201435) do ActiveRecord::Schema.define(version: 20180612175636) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -1159,6 +1159,7 @@ ActiveRecord::Schema.define(version: 20180608201435) do ...@@ -1159,6 +1159,7 @@ ActiveRecord::Schema.define(version: 20180608201435) do
t.string "url", null: false t.string "url", null: false
t.string "selective_sync_type" t.string "selective_sync_type"
t.text "selective_sync_shards" t.text "selective_sync_shards"
t.integer "verification_max_capacity", default: 100, null: false
end end
add_index "geo_nodes", ["access_key"], name: "index_geo_nodes_on_access_key", using: :btree add_index "geo_nodes", ["access_key"], name: "index_geo_nodes_on_access_key", using: :btree
......
...@@ -25,6 +25,7 @@ Example response: ...@@ -25,6 +25,7 @@ Example response:
"current": true, "current": true,
"files_max_capacity": 10, "files_max_capacity": 10,
"repos_max_capacity": 25, "repos_max_capacity": 25,
"verification_max_capacity": 100,
"clone_protocol": "http" "clone_protocol": "http"
}, },
{ {
...@@ -35,6 +36,7 @@ Example response: ...@@ -35,6 +36,7 @@ Example response:
"current": false, "current": false,
"files_max_capacity": 10, "files_max_capacity": 10,
"repos_max_capacity": 25, "repos_max_capacity": 25,
"verification_max_capacity": 100,
"clone_protocol": "http" "clone_protocol": "http"
} }
] ]
...@@ -61,6 +63,7 @@ Example response: ...@@ -61,6 +63,7 @@ Example response:
"current": true, "current": true,
"files_max_capacity": 10, "files_max_capacity": 10,
"repos_max_capacity": 25, "repos_max_capacity": 25,
"verification_max_capacity": 100,
"clone_protocol": "http" "clone_protocol": "http"
} }
``` ```
...@@ -75,13 +78,14 @@ _This can only be run against a primary Geo node._ ...@@ -75,13 +78,14 @@ _This can only be run against a primary Geo node._
PUT /geo_nodes/:id PUT /geo_nodes/:id
``` ```
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
|----------------------|---------|----------|---------------------------------------------------------------------------| |----------------------|---------|-----------|---------------------------------------------------------------------------|
| `id` | integer | yes | The ID of the Geo node. | | `id` | integer | yes | The ID of the Geo node. |
| `enabled` | boolean | no | Flag indicating if the Geo node is enabled. | | `enabled` | boolean | no | Flag indicating if the Geo node is enabled. |
| `url` | string | no | The URL to connect to the Geo node. | | `url` | string | no | The URL to connect to the Geo node. |
| `files_max_capacity` | integer | no | Control the maximum concurrency of LFS/attachment backfill for this node. | | `files_max_capacity` | integer | no | Control the maximum concurrency of LFS/attachment backfill for this secondary node. |
| `repos_max_capacity` | integer | no | Control the maximum concurrency of repository backfill for this node. | | `repos_max_capacity` | integer | no | Control the maximum concurrency of repository backfill for this secondary node. |
| `verification_max_capacity` | integer | no | Control the maximum concurrency of verification for this node. |
Example response: Example response:
...@@ -94,6 +98,7 @@ Example response: ...@@ -94,6 +98,7 @@ Example response:
"current": true, "current": true,
"files_max_capacity": 10, "files_max_capacity": 10,
"repos_max_capacity": 25, "repos_max_capacity": 25,
"verification_max_capacity": 100,
"clone_protocol": "http" "clone_protocol": "http"
} }
``` ```
...@@ -131,6 +136,7 @@ Example response: ...@@ -131,6 +136,7 @@ Example response:
"current": true, "current": true,
"files_max_capacity": 10, "files_max_capacity": 10,
"repos_max_capacity": 25, "repos_max_capacity": 25,
"verification_max_capacity": 100,
"clone_protocol": "http" "clone_protocol": "http"
} }
``` ```
......
...@@ -47,7 +47,8 @@ class Admin::GeoNodesController < Admin::ApplicationController ...@@ -47,7 +47,8 @@ class Admin::GeoNodesController < Admin::ApplicationController
:selective_sync_shards, :selective_sync_shards,
:namespace_ids, :namespace_ids,
:repos_max_capacity, :repos_max_capacity,
:files_max_capacity :files_max_capacity,
:verification_max_capacity
) )
end end
......
...@@ -29,6 +29,10 @@ class GeoNode < ActiveRecord::Base ...@@ -29,6 +29,10 @@ class GeoNode < ActiveRecord::Base
allow_nil: true allow_nil: true
} }
validates :repos_max_capacity, numericality: { greater_than_or_equal_to: 0 }
validates :files_max_capacity, numericality: { greater_than_or_equal_to: 0 }
validates :verification_max_capacity, numericality: { greater_than_or_equal_to: 0 }
validate :check_not_adding_primary_as_secondary, if: :secondary? validate :check_not_adding_primary_as_secondary, if: :secondary?
after_save :expire_cache! after_save :expire_cache!
......
= form_errors(geo_node) = form_errors(geo_node)
.form-group.row .form-group.row
= form.label :url, 'URL', class: 'col-form-label' .col-sm-2
= form.label :url, 'URL', class: 'col-form-label'
.col-sm-10 .col-sm-10
= form.text_field :url, class: 'form-control' = form.text_field :url, class: 'form-control'
...@@ -13,20 +14,23 @@ ...@@ -13,20 +14,23 @@
.js-hide-if-geo-primary{ class: ('hidden' unless geo_node.secondary?) } .js-hide-if-geo-primary{ class: ('hidden' unless geo_node.secondary?) }
.form-group.row .form-group.row
= form.label :selective_sync_type, s_('Selective synchronization'), class: 'col-form-label' .col-sm-2
= form.label :selective_sync_type, s_('Selective synchronization'), class: 'col-form-label'
.col-sm-10 .col-sm-10
= form.select :selective_sync_type, selective_sync_type_options_for_select(geo_node), = form.select :selective_sync_type, selective_sync_type_options_for_select(geo_node),
{}, { class: "form-control js-geo-node-selective-sync-type" } {}, { class: "form-control js-geo-node-selective-sync-type" }
.form-group.row.js-sync-by-namespace{ class: ('hidden' unless geo_node.selective_sync_by_namespaces?) } .form-group.row.js-sync-by-namespace{ class: ('hidden' unless geo_node.selective_sync_by_namespaces?) }
= form.label :namespace_ids, s_('Geo|Groups to synchronize'), class: 'col-form-label' .col-sm-2
= form.label :namespace_ids, s_('Geo|Groups to synchronize'), class: 'col-form-label'
.col-sm-10 .col-sm-10
= hidden_field_tag "#{form.object_name}[namespace_ids]", geo_node.namespace_ids.join(","), class: 'js-geo-node-namespaces', data: { selected: node_namespaces_options(geo_node.namespaces).to_json } = hidden_field_tag "#{form.object_name}[namespace_ids]", geo_node.namespace_ids.join(","), class: 'js-geo-node-namespaces', data: { selected: node_namespaces_options(geo_node.namespaces).to_json }
.form-text.text-muted .form-text.text-muted
#{ s_("Choose which groups you wish to synchronize to this secondary node.") } #{ s_("Choose which groups you wish to synchronize to this secondary node.") }
.form-group.row.js-sync-by-shard{ class: ('hidden' unless geo_node.selective_sync_by_shards?) } .form-group.row.js-sync-by-shard{ class: ('hidden' unless geo_node.selective_sync_by_shards?) }
= form.label :selective_sync_shards, s_('Geo|Shards to synchronize'), class: 'col-form-label' .col-sm-2
= form.label :selective_sync_shards, s_('Geo|Shards to synchronize'), class: 'col-form-label'
.col-sm-10 .col-sm-10
= form.select :selective_sync_shards, repository_storages_options_for_select(geo_node.selective_sync_shards), = form.select :selective_sync_shards, repository_storages_options_for_select(geo_node.selective_sync_shards),
{ include_hidden: false }, multiple: true, class: 'form-control' { include_hidden: false }, multiple: true, class: 'form-control'
...@@ -34,15 +38,25 @@ ...@@ -34,15 +38,25 @@
#{ s_("Choose which shards you wish to synchronize to this secondary node.") } #{ s_("Choose which shards you wish to synchronize to this secondary node.") }
.form-group.row.js-hide-if-geo-primary{ class: ('hidden' unless geo_node.secondary?) } .form-group.row.js-hide-if-geo-primary{ class: ('hidden' unless geo_node.secondary?) }
= form.label :repos_max_capacity, s_('Geo|Repository sync capacity'), class: 'col-form-label' .col-sm-2
= form.label :repos_max_capacity, s_('Geo|Repository sync capacity'), class: 'col-form-label'
.col-sm-10 .col-sm-10
= form.number_field :repos_max_capacity, class: 'form-control', min: 0 = form.number_field :repos_max_capacity, class: 'form-control', min: 0
.form-text.text-muted .form-text.text-muted
#{ s_('Control the maximum concurrency of repository backfill for this secondary node') } #{ s_('Control the maximum concurrency of repository backfill for this secondary node') }
.form-group.row.js-hide-if-geo-primary{ class: ('hidden' unless geo_node.secondary?) } .form-group.row.js-hide-if-geo-primary{ class: ('hidden' unless geo_node.secondary?) }
= form.label :files_max_capacity, s_('Geo|File sync capacity'), class: 'col-form-label' .col-sm-2
= form.label :files_max_capacity, s_('Geo|File sync capacity'), class: 'col-form-label'
.col-sm-10 .col-sm-10
= form.number_field :files_max_capacity, class: 'form-control', min: 0 = form.number_field :files_max_capacity, class: 'form-control', min: 0
.form-text.text-muted .form-text.text-muted
#{ s_('Control the maximum concurrency of LFS/attachment backfill for this secondary node') } #{ s_('Control the maximum concurrency of LFS/attachment backfill for this secondary node') }
.form-group.row
.col-sm-2
= form.label :verification_max_capacity, s_('Geo|Verification capacity'), class: 'col-form-label'
.col-sm-10
= form.number_field :verification_max_capacity, class: 'form-control', min: 0
.form-text.text-muted
#{ s_('Control the maximum concurrency of verification operations for this Geo node') }
...@@ -4,8 +4,6 @@ module Geo ...@@ -4,8 +4,6 @@ module Geo
class ShardWorker < Geo::Scheduler::Primary::SchedulerWorker class ShardWorker < Geo::Scheduler::Primary::SchedulerWorker
sidekiq_options retry: false sidekiq_options retry: false
MAX_CAPACITY = 100
attr_accessor :shard_name attr_accessor :shard_name
def perform(shard_name) def perform(shard_name)
...@@ -28,7 +26,7 @@ module Geo ...@@ -28,7 +26,7 @@ module Geo
end end
def max_capacity def max_capacity
MAX_CAPACITY current_node.verification_max_capacity
end end
def schedule_job(project_id) def schedule_job(project_id)
......
...@@ -4,8 +4,6 @@ module Geo ...@@ -4,8 +4,6 @@ module Geo
class ShardWorker < Geo::Scheduler::Secondary::SchedulerWorker class ShardWorker < Geo::Scheduler::Secondary::SchedulerWorker
include CronjobQueue include CronjobQueue
MAX_CAPACITY = 1000
attr_accessor :shard_name attr_accessor :shard_name
def perform(shard_name) def perform(shard_name)
...@@ -23,7 +21,7 @@ module Geo ...@@ -23,7 +21,7 @@ module Geo
end end
def max_capacity def max_capacity
MAX_CAPACITY current_node.verification_max_capacity
end end
def load_pending_resources def load_pending_resources
......
---
title: Allow repository verification concurrency to be controlled on primary and secondary
merge_request: 6102
author:
type: added
class AddGeoNodesVerificationMaxCapacity < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
add_column :geo_nodes, :verification_max_capacity, :integer, default: 100, null: false
end
end
...@@ -134,6 +134,7 @@ module API ...@@ -134,6 +134,7 @@ module API
optional :url, type: String, desc: 'The URL to connect to the Geo node' optional :url, type: String, desc: 'The URL to connect to the Geo node'
optional :files_max_capacity, type: Integer, desc: 'Control the maximum concurrency of LFS/attachment backfill for this secondary node' optional :files_max_capacity, type: Integer, desc: 'Control the maximum concurrency of LFS/attachment backfill for this secondary node'
optional :repos_max_capacity, type: Integer, desc: 'Control the maximum concurrency of repository backfill for this secondary node' optional :repos_max_capacity, type: Integer, desc: 'Control the maximum concurrency of repository backfill for this secondary node'
optional :verification_max_capacity, type: Integer, desc: 'Control the maximum concurrency of repository verification for this node'
end end
put do put do
not_found!('GeoNode') unless geo_node not_found!('GeoNode') unless geo_node
......
...@@ -218,6 +218,7 @@ module EE ...@@ -218,6 +218,7 @@ module EE
expose :current?, as: :current expose :current?, as: :current
expose :files_max_capacity expose :files_max_capacity
expose :repos_max_capacity expose :repos_max_capacity
expose :verification_max_capacity
# Retained for backwards compatibility. Remove in API v5 # Retained for backwards compatibility. Remove in API v5
expose :clone_protocol do |_record, _options| expose :clone_protocol do |_record, _options|
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
"current", "current",
"files_max_capacity", "files_max_capacity",
"repos_max_capacity", "repos_max_capacity",
"verification_max_capacity",
"clone_protocol", "clone_protocol",
"_links" "_links"
], ],
...@@ -19,6 +20,7 @@ ...@@ -19,6 +20,7 @@
"current": { "type": "boolean" }, "current": { "type": "boolean" },
"files_max_capacity": { "type": "integer" }, "files_max_capacity": { "type": "integer" },
"repos_max_capacity": { "type": "integer" }, "repos_max_capacity": { "type": "integer" },
"verification_max_capacity": { "type": "integer" },
"clone_protocol": { "type": ["string"] }, "clone_protocol": { "type": ["string"] },
"web_edit_url": { "type": "string" }, "web_edit_url": { "type": "string" },
"_links": { "_links": {
......
...@@ -23,6 +23,9 @@ describe GeoNode, type: :model do ...@@ -23,6 +23,9 @@ describe GeoNode, type: :model do
context 'validations' do context 'validations' do
it { is_expected.to validate_inclusion_of(:selective_sync_type).in_array([nil, *GeoNode::SELECTIVE_SYNC_TYPES]) } it { is_expected.to validate_inclusion_of(:selective_sync_type).in_array([nil, *GeoNode::SELECTIVE_SYNC_TYPES]) }
it { is_expected.to validate_numericality_of(:repos_max_capacity).is_greater_than_or_equal_to(0) }
it { is_expected.to validate_numericality_of(:files_max_capacity).is_greater_than_or_equal_to(0) }
it { is_expected.to validate_numericality_of(:verification_max_capacity).is_greater_than_or_equal_to(0) }
end end
context 'default values' do context 'default values' do
......
...@@ -177,7 +177,8 @@ describe API::GeoNodes, :geo, :prometheus, api: true do ...@@ -177,7 +177,8 @@ describe API::GeoNodes, :geo, :prometheus, api: true do
enabled: false, enabled: false,
url: 'https://updated.example.com/', url: 'https://updated.example.com/',
files_max_capacity: 33, files_max_capacity: 33,
repos_max_capacity: 44 repos_max_capacity: 44,
verification_max_capacity: 55
}.stringify_keys }.stringify_keys
put api("/geo_nodes/#{secondary.id}", admin), params put api("/geo_nodes/#{secondary.id}", admin), params
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment