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:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-01-14 15:18:55 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-01-14 15:18:55 +0300
commit8a70817cd9327a4cdfbd71a11f9aa22e838fabf6 (patch)
tree33ea54e2a4cfaa0f0b7e2a65e433d99f28dbf4cf /lib/gitlab/redis
parent7bd8f9822b05eb2e8c8279678e38e7513c3612f6 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'lib/gitlab/redis')
-rw-r--r--lib/gitlab/redis/multi_store.rb232
-rw-r--r--lib/gitlab/redis/sessions.rb36
2 files changed, 3 insertions, 265 deletions
diff --git a/lib/gitlab/redis/multi_store.rb b/lib/gitlab/redis/multi_store.rb
deleted file mode 100644
index ff7758f3e53..00000000000
--- a/lib/gitlab/redis/multi_store.rb
+++ /dev/null
@@ -1,232 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
- module Redis
- class MultiStore
- include Gitlab::Utils::StrongMemoize
-
- class ReadFromPrimaryError < StandardError
- def message
- 'Value not found on the redis primary store. Read from the redis secondary store successful.'
- end
- end
- class MethodMissingError < StandardError
- def message
- 'Method missing. Falling back to execute method on the redis secondary store.'
- end
- end
-
- attr_reader :primary_store, :secondary_store, :instance_name
-
- FAILED_TO_READ_ERROR_MESSAGE = 'Failed to read from the redis primary_store.'
- FAILED_TO_WRITE_ERROR_MESSAGE = 'Failed to write to the redis primary_store.'
-
- SKIP_LOG_METHOD_MISSING_FOR_COMMANDS = %i(info).freeze
-
- READ_COMMANDS = %i(
- get
- mget
- smembers
- scard
- ).freeze
-
- WRITE_COMMANDS = %i(
- set
- setnx
- setex
- sadd
- srem
- del
- pipelined
- flushdb
- ).freeze
-
- def initialize(primary_store, secondary_store, instance_name)
- @primary_store = primary_store
- @secondary_store = secondary_store
- @instance_name = instance_name
-
- validate_stores!
- end
- # rubocop:disable GitlabSecurity/PublicSend
- READ_COMMANDS.each do |name|
- define_method(name) do |*args, &block|
- if use_primary_and_secondary_stores?
- read_command(name, *args, &block)
- else
- default_store.send(name, *args, &block)
- end
- end
- end
-
- WRITE_COMMANDS.each do |name|
- define_method(name) do |*args, &block|
- if use_primary_and_secondary_stores?
- write_command(name, *args, &block)
- else
- default_store.send(name, *args, &block)
- end
- end
- end
-
- def method_missing(...)
- return @instance.send(...) if @instance
-
- log_method_missing(...)
-
- default_store.send(...)
- end
- # rubocop:enable GitlabSecurity/PublicSend
-
- def respond_to_missing?(command_name, include_private = false)
- true
- end
-
- # This is needed because of Redis::Rack::Connection is requiring Redis::Store
- # https://github.com/redis-store/redis-rack/blob/a833086ba494083b6a384a1a4e58b36573a9165d/lib/redis/rack/connection.rb#L15
- # Done similarly in https://github.com/lsegal/yard/blob/main/lib/yard/templates/template.rb#L122
- def is_a?(klass)
- return true if klass == default_store.class
-
- super(klass)
- end
- alias_method :kind_of?, :is_a?
-
- def to_s
- use_primary_and_secondary_stores? ? primary_store.to_s : default_store.to_s
- end
-
- def use_primary_and_secondary_stores?
- feature_table_exists? && Feature.enabled?("use_primary_and_secondary_stores_for_#{instance_name.underscore}", default_enabled: :yaml) && !same_redis_store?
- end
-
- def use_primary_store_as_default?
- feature_table_exists? && Feature.enabled?("use_primary_store_as_default_for_#{instance_name.underscore}", default_enabled: :yaml) && !same_redis_store?
- end
-
- private
-
- # @return [Boolean]
- def feature_table_exists?
- Feature::FlipperFeature.table_exists?
- rescue StandardError
- false
- end
-
- def default_store
- use_primary_store_as_default? ? primary_store : secondary_store
- end
-
- def log_method_missing(command_name, *_args)
- return if SKIP_LOG_METHOD_MISSING_FOR_COMMANDS.include?(command_name)
-
- log_error(MethodMissingError.new, command_name)
- increment_method_missing_count(command_name)
- end
-
- def read_command(command_name, *args, &block)
- if @instance
- send_command(@instance, command_name, *args, &block)
- else
- read_one_with_fallback(command_name, *args, &block)
- end
- end
-
- def write_command(command_name, *args, &block)
- if @instance
- send_command(@instance, command_name, *args, &block)
- else
- write_both(command_name, *args, &block)
- end
- end
-
- def read_one_with_fallback(command_name, *args, &block)
- begin
- value = send_command(primary_store, command_name, *args, &block)
- rescue StandardError => e
- log_error(e, command_name,
- multi_store_error_message: FAILED_TO_READ_ERROR_MESSAGE)
- end
-
- value ||= fallback_read(command_name, *args, &block)
-
- value
- end
-
- def fallback_read(command_name, *args, &block)
- value = send_command(secondary_store, command_name, *args, &block)
-
- if value
- log_error(ReadFromPrimaryError.new, command_name)
- increment_read_fallback_count(command_name)
- end
-
- value
- end
-
- def write_both(command_name, *args, &block)
- begin
- send_command(primary_store, command_name, *args, &block)
- rescue StandardError => e
- log_error(e, command_name,
- multi_store_error_message: FAILED_TO_WRITE_ERROR_MESSAGE)
- end
-
- send_command(secondary_store, command_name, *args, &block)
- end
-
- def same_redis_store?
- strong_memoize(:same_redis_store) do
- # <Redis client v4.4.0 for redis:///path_to/redis/redis.socket/5>"
- primary_store.inspect == secondary_store.inspect
- end
- end
-
- # rubocop:disable GitlabSecurity/PublicSend
- def send_command(redis_instance, command_name, *args, &block)
- if block_given?
- # Make sure that block is wrapped and executed only on the redis instance that is executing the block
- redis_instance.send(command_name, *args) do |*params|
- with_instance(redis_instance, *params, &block)
- end
- else
- redis_instance.send(command_name, *args)
- end
- end
- # rubocop:enable GitlabSecurity/PublicSend
-
- def with_instance(instance, *params)
- @instance = instance
-
- yield(*params)
- ensure
- @instance = nil
- end
-
- def increment_read_fallback_count(command_name)
- @read_fallback_counter ||= Gitlab::Metrics.counter(:gitlab_redis_multi_store_read_fallback_total, 'Client side Redis MultiStore reading fallback')
- @read_fallback_counter.increment(command: command_name, instance_name: instance_name)
- end
-
- def increment_method_missing_count(command_name)
- @method_missing_counter ||= Gitlab::Metrics.counter(:gitlab_redis_multi_store_method_missing_total, 'Client side Redis MultiStore method missing')
- @method_missing_counter.increment(command: command_name, instance_name: instance_name)
- end
-
- def validate_stores!
- raise ArgumentError, 'primary_store is required' unless primary_store
- raise ArgumentError, 'secondary_store is required' unless secondary_store
- raise ArgumentError, 'instance_name is required' unless instance_name
- raise ArgumentError, 'invalid primary_store' unless primary_store.is_a?(::Redis)
- raise ArgumentError, 'invalid secondary_store' unless secondary_store.is_a?(::Redis)
- end
-
- def log_error(exception, command_name, extra = {})
- Gitlab::ErrorTracking.log_exception(
- exception,
- command_name: command_name,
- extra: extra.merge(instance_name: instance_name))
- end
- end
- end
-end
diff --git a/lib/gitlab/redis/sessions.rb b/lib/gitlab/redis/sessions.rb
index c547828d907..ddcfdf6e798 100644
--- a/lib/gitlab/redis/sessions.rb
+++ b/lib/gitlab/redis/sessions.rb
@@ -9,39 +9,9 @@ module Gitlab
IP_SESSIONS_LOOKUP_NAMESPACE = 'session:lookup:ip:gitlab2'
OTP_SESSIONS_NAMESPACE = 'session:otp'
- class << self
- # The data we store on Sessions used to be stored on SharedState.
- def config_fallback
- SharedState
- end
-
- private
-
- def redis
- # Don't use multistore if redis.sessions configuration is not provided
- return super if config_fallback?
-
- primary_store = ::Redis.new(params)
- secondary_store = ::Redis.new(config_fallback.params)
-
- MultiStore.new(primary_store, secondary_store, store_name)
- end
- end
-
- def store(extras = {})
- # Don't use multistore if redis.sessions configuration is not provided
- return super if self.class.config_fallback?
-
- primary_store = create_redis_store(redis_store_options, extras)
- secondary_store = create_redis_store(self.class.config_fallback.params, extras)
-
- MultiStore.new(primary_store, secondary_store, self.class.store_name)
- end
-
- private
-
- def create_redis_store(options, extras)
- ::Redis::Store.new(options.merge(extras))
+ # The data we store on Sessions used to be stored on SharedState.
+ def self.config_fallback
+ SharedState
end
end
end