Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/issues/rebalancing/state.rb')
-rw-r--r--lib/gitlab/issues/rebalancing/state.rb154
1 files changed, 154 insertions, 0 deletions
diff --git a/lib/gitlab/issues/rebalancing/state.rb b/lib/gitlab/issues/rebalancing/state.rb
new file mode 100644
index 00000000000..dce165a3489
--- /dev/null
+++ b/lib/gitlab/issues/rebalancing/state.rb
@@ -0,0 +1,154 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Issues
+ module Rebalancing
+ class State
+ REDIS_EXPIRY_TIME = 10.days
+ MAX_NUMBER_OF_CONCURRENT_REBALANCES = 5
+ NAMESPACE = 1
+ PROJECT = 2
+
+ def initialize(root_namespace, projects)
+ @root_namespace = root_namespace
+ @projects = projects
+ @rebalanced_container_type = @root_namespace.is_a?(Group) ? NAMESPACE : PROJECT
+ @rebalanced_container_id = @rebalanced_container_type == NAMESPACE ? @root_namespace.id : projects.take.id # rubocop:disable CodeReuse/ActiveRecord
+ end
+
+ def track_new_running_rebalance
+ with_redis do |redis|
+ redis.multi do |multi|
+ # we trigger re-balance for namespaces(groups) or specific user project
+ value = "#{rebalanced_container_type}/#{rebalanced_container_id}"
+ multi.sadd(concurrent_running_rebalances_key, value)
+ multi.expire(concurrent_running_rebalances_key, REDIS_EXPIRY_TIME)
+ end
+ end
+ end
+
+ def concurrent_running_rebalances_count
+ with_redis { |redis| redis.scard(concurrent_running_rebalances_key).to_i }
+ end
+
+ def rebalance_in_progress?
+ all_rebalanced_containers = with_redis { |redis| redis.smembers(concurrent_running_rebalances_key) }
+
+ is_running = case rebalanced_container_type
+ when NAMESPACE
+ namespace_ids = all_rebalanced_containers.map {|string| string.split("#{NAMESPACE}/").second.to_i }.compact
+ namespace_ids.include?(root_namespace.id)
+ when PROJECT
+ project_ids = all_rebalanced_containers.map {|string| string.split("#{PROJECT}/").second.to_i }.compact
+ project_ids.include?(projects.take.id) # rubocop:disable CodeReuse/ActiveRecord
+ else
+ false
+ end
+
+ refresh_keys_expiration if is_running
+
+ is_running
+ end
+
+ def can_start_rebalance?
+ rebalance_in_progress? || too_many_rebalances_running?
+ end
+
+ def cache_issue_ids(issue_ids)
+ with_redis do |redis|
+ values = issue_ids.map { |issue| [issue.relative_position, issue.id] }
+
+ redis.multi do |multi|
+ multi.zadd(issue_ids_key, values) unless values.blank?
+ multi.expire(issue_ids_key, REDIS_EXPIRY_TIME)
+ end
+ end
+ end
+
+ def get_cached_issue_ids(index, limit)
+ with_redis do |redis|
+ redis.zrange(issue_ids_key, index, index + limit - 1)
+ end
+ end
+
+ def cache_current_index(index)
+ with_redis { |redis| redis.set(current_index_key, index, ex: REDIS_EXPIRY_TIME) }
+ end
+
+ def get_current_index
+ with_redis { |redis| redis.get(current_index_key).to_i }
+ end
+
+ def cache_current_project_id(project_id)
+ with_redis { |redis| redis.set(current_project_key, project_id, ex: REDIS_EXPIRY_TIME) }
+ end
+
+ def get_current_project_id
+ with_redis { |redis| redis.get(current_project_key) }
+ end
+
+ def issue_count
+ @issue_count ||= with_redis { |redis| redis.zcard(issue_ids_key)}
+ end
+
+ def remove_current_project_id_cache
+ with_redis { |redis| redis.del(current_project_key)}
+ end
+
+ def refresh_keys_expiration
+ with_redis do |redis|
+ redis.multi do |multi|
+ multi.expire(issue_ids_key, REDIS_EXPIRY_TIME)
+ multi.expire(current_index_key, REDIS_EXPIRY_TIME)
+ multi.expire(current_project_key, REDIS_EXPIRY_TIME)
+ multi.expire(concurrent_running_rebalances_key, REDIS_EXPIRY_TIME)
+ end
+ end
+ end
+
+ def cleanup_cache
+ with_redis do |redis|
+ redis.multi do |multi|
+ multi.del(issue_ids_key)
+ multi.del(current_index_key)
+ multi.del(current_project_key)
+ multi.srem(concurrent_running_rebalances_key, "#{rebalanced_container_type}/#{rebalanced_container_id}")
+ end
+ end
+ end
+
+ private
+
+ attr_accessor :root_namespace, :projects, :rebalanced_container_type, :rebalanced_container_id
+
+ def too_many_rebalances_running?
+ concurrent_running_rebalances_count <= MAX_NUMBER_OF_CONCURRENT_REBALANCES
+ end
+
+ def redis_key_prefix
+ "gitlab:issues-position-rebalances"
+ end
+
+ def issue_ids_key
+ "#{redis_key_prefix}:#{root_namespace.id}"
+ end
+
+ def current_index_key
+ "#{issue_ids_key}:current_index"
+ end
+
+ def current_project_key
+ "#{issue_ids_key}:current_project_id"
+ end
+
+ def concurrent_running_rebalances_key
+ "#{redis_key_prefix}:running_rebalances"
+ end
+
+ def with_redis(&blk)
+ Gitlab::Redis::SharedState.with(&blk) # rubocop: disable CodeReuse/ActiveRecord
+ end
+ end
+ end
+ end
+end