debian-mirror-gitlab/lib/gitlab/reference_counter.rb

94 lines
2.4 KiB
Ruby
Raw Normal View History

2018-12-13 13:39:08 +05:30
# frozen_string_literal: true
2018-03-17 18:26:18 +05:30
module Gitlab
2020-04-08 14:13:33 +05:30
# Reference Counter
#
# A reference counter is used as a mechanism to identify when
# a repository is being accessed by a writable operation.
#
# Maintenance operations would use this as a clue to when it should
# execute significant changes in order to avoid disrupting running traffic
2018-03-17 18:26:18 +05:30
class ReferenceCounter
REFERENCE_EXPIRE_TIME = 600
attr_reader :gl_repository, :key
2020-04-08 14:13:33 +05:30
# Reference Counter instance
#
# @example
# Gitlab::ReferenceCounter.new('project-1')
#
# @see Gitlab::GlRepository::RepoType.identifier_for_repositorable
# @param [String] gl_repository repository identifier
2018-03-17 18:26:18 +05:30
def initialize(gl_repository)
@gl_repository = gl_repository
@key = "git-receive-pack-reference-counter:#{gl_repository}"
end
2020-04-08 14:13:33 +05:30
# Return the actual counter value
#
# @return [Integer] value
2018-03-17 18:26:18 +05:30
def value
2020-04-08 14:13:33 +05:30
Gitlab::Redis::SharedState.with do |redis|
(redis.get(key) || 0).to_i
end
2018-03-17 18:26:18 +05:30
end
2020-04-08 14:13:33 +05:30
# Increase the counter
#
# @return [Boolean] whether operation was a success
2018-03-17 18:26:18 +05:30
def increase
redis_cmd do |redis|
redis.incr(key)
redis.expire(key, REFERENCE_EXPIRE_TIME)
end
end
2020-04-08 14:13:33 +05:30
# Decrease the counter
#
# @return [Boolean] whether operation was a success
2018-03-17 18:26:18 +05:30
def decrease
redis_cmd do |redis|
current_value = redis.decr(key)
if current_value < 0
2020-11-24 15:15:51 +05:30
Gitlab::AppLogger.warn("Reference counter for #{gl_repository} decreased" \
2020-04-08 14:13:33 +05:30
" when its value was less than 1. Resetting the counter.")
2018-03-17 18:26:18 +05:30
redis.del(key)
end
end
end
2020-04-08 14:13:33 +05:30
# Reset the reference counter
#
# @private Used internally by SRE and debugging purpose
# @return [Boolean] whether reset was a success
def reset!
redis_cmd do |redis|
redis.del(key)
end
end
# When the reference counter would expire
#
# @api private Used internally by SRE and debugging purpose
# @return [Integer] Number in seconds until expiration or false if never
def expires_in
Gitlab::Redis::SharedState.with do |redis|
redis.ttl(key)
end
end
2018-03-17 18:26:18 +05:30
private
def redis_cmd
Gitlab::Redis::SharedState.with { |redis| yield(redis) }
2020-04-08 14:13:33 +05:30
2018-03-17 18:26:18 +05:30
true
rescue => e
2020-11-24 15:15:51 +05:30
Gitlab::AppLogger.warn("GitLab: An unexpected error occurred in writing to Redis: #{e}")
2020-04-08 14:13:33 +05:30
2018-03-17 18:26:18 +05:30
false
end
end
end