Module: Gitlab::Cache::Import::Caching
- Defined in:
- lib/gitlab/cache/import/caching.rb
Constant Summary collapse
- TIMEOUT =
The default timeout of the cache keys.
24.hours.to_i
- LONGER_TIMEOUT =
72.hours.to_i
- SHORTER_TIMEOUT =
15.minutes.to_i
- WRITE_IF_GREATER_SCRIPT =
<<-EOF.strip_heredoc.freeze local key, value, ttl = KEYS[1], tonumber(ARGV[1]), ARGV[2] local existing = tonumber(redis.call("get", key)) if existing == nil or value > existing then redis.call("set", key, value) redis.call("expire", key, ttl) return true else return false end EOF
Class Method Summary collapse
- .cache_key_for(raw_key) ⇒ Object
-
.expire(raw_key, timeout) ⇒ Object
Sets the expiration time of a key.
-
.hash_add(raw_key, field, value, timeout: TIMEOUT) ⇒ Object
Adds a value to a hash.
-
.increment(raw_key, timeout: TIMEOUT) ⇒ Object
Increment the integer value of a key by one.
-
.increment_by(raw_key, value, timeout: TIMEOUT) ⇒ Object
Increment the integer value of a key by the given value.
-
.read(raw_key, timeout: TIMEOUT) ⇒ Object
Reads a cache key.
-
.read_integer(raw_key, timeout: TIMEOUT) ⇒ Object
Reads an integer from the cache, or returns nil if no value was found.
-
.set_add(raw_key, value, timeout: TIMEOUT) ⇒ Object
Adds a value to a set.
-
.set_includes?(raw_key, value) ⇒ Boolean
Returns true if the given value is present in the set.
- .validate_redis_value!(value) ⇒ Object
-
.values_from_hash(raw_key) ⇒ Object
Returns the values of the given hash.
-
.values_from_set(raw_key) ⇒ Object
Returns the values of the given set.
- .with_redis(&block) ⇒ Object
-
.write(raw_key, value, timeout: TIMEOUT) ⇒ Object
Sets a cache key to the given value.
-
.write_if_greater(raw_key, value, timeout: TIMEOUT) ⇒ Object
Sets a key to the given integer but only if the existing value is smaller than the given value.
-
.write_multiple(mapping, key_prefix: nil, timeout: TIMEOUT) ⇒ Object
Sets multiple keys to given values.
Class Method Details
.cache_key_for(raw_key) ⇒ Object
242 243 244 |
# File 'lib/gitlab/cache/import/caching.rb', line 242 def self.cache_key_for(raw_key) "#{Redis::Cache::CACHE_NAMESPACE}:#{raw_key}" end |
.expire(raw_key, timeout) ⇒ Object
Sets the expiration time of a key.
raw_key - The key for which to change the timeout. timeout - The new timeout.
182 183 184 185 186 187 188 |
# File 'lib/gitlab/cache/import/caching.rb', line 182 def self.expire(raw_key, timeout) key = cache_key_for(raw_key) with_redis do |redis| redis.expire(key, timeout) end end |
.hash_add(raw_key, field, value, timeout: TIMEOUT) ⇒ Object
Adds a value to a hash.
raw_key - The key of the hash to add to. field - The field to add to the hash. value - The field value to add to the hash. timeout - The new timeout of the key.
218 219 220 221 222 223 224 225 226 227 228 229 |
# File 'lib/gitlab/cache/import/caching.rb', line 218 def self.hash_add(raw_key, field, value, timeout: TIMEOUT) validate_redis_value!(value) key = cache_key_for(raw_key) with_redis do |redis| redis.multi do |m| m.hset(key, field, value) m.expire(key, timeout) end end end |
.increment(raw_key, timeout: TIMEOUT) ⇒ Object
Increment the integer value of a key by one. Sets the value to zero if missing before incrementing
raw_key - The cache key to increment. timeout - The time after which the cache key should expire.
85 86 87 88 89 90 91 92 93 94 |
# File 'lib/gitlab/cache/import/caching.rb', line 85 def self.increment(raw_key, timeout: TIMEOUT) key = cache_key_for(raw_key) with_redis do |redis| value = redis.incr(key) redis.expire(key, timeout) value end end |
.increment_by(raw_key, value, timeout: TIMEOUT) ⇒ Object
Increment the integer value of a key by the given value. Sets the value to zero if missing before incrementing
raw_key - The cache key to increment. value - The value to increment the key timeout - The time after which the cache key should expire.
103 104 105 106 107 108 109 110 111 112 |
# File 'lib/gitlab/cache/import/caching.rb', line 103 def self.increment_by(raw_key, value, timeout: TIMEOUT) validate_redis_value!(value) key = cache_key_for(raw_key) with_redis do |redis| redis.incrby(key, value) redis.expire(key, timeout) end end |
.read(raw_key, timeout: TIMEOUT) ⇒ Object
Reads a cache key.
If the key exists and has a non-empty value its TTL is refreshed automatically.
raw_key - The cache key to read. timeout - The new timeout of the key if the key is to be refreshed.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/gitlab/cache/import/caching.rb', line 34 def self.read(raw_key, timeout: TIMEOUT) key = cache_key_for(raw_key) value = with_redis { |redis| redis.get(key) } if value.present? # We refresh the expiration time so frequently used keys stick # around, removing the need for querying the database as much as # possible. # # A key may be empty when we looked up a GitHub user (for example) but # did not find a matching GitLab user. In that case we _don't_ want to # refresh the TTL so we automatically pick up the right data when said # user were to register themselves on the GitLab instance. with_redis { |redis| redis.expire(key, timeout) } end value end |
.read_integer(raw_key, timeout: TIMEOUT) ⇒ Object
Reads an integer from the cache, or returns nil if no value was found.
See Caching.read for more information.
56 57 58 59 60 |
# File 'lib/gitlab/cache/import/caching.rb', line 56 def self.read_integer(raw_key, timeout: TIMEOUT) value = read(raw_key, timeout: timeout) value.to_i if value.present? end |
.set_add(raw_key, value, timeout: TIMEOUT) ⇒ Object
Adds a value to a set.
raw_key - The key of the set to add the value to. value - The value to add to the set. timeout - The new timeout of the key.
119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/gitlab/cache/import/caching.rb', line 119 def self.set_add(raw_key, value, timeout: TIMEOUT) validate_redis_value!(value) key = cache_key_for(raw_key) with_redis do |redis| redis.multi do |m| m.sadd?(key, value) m.expire(key, timeout) end end end |
.set_includes?(raw_key, value) ⇒ Boolean
Returns true if the given value is present in the set.
raw_key - The key of the set to check. value - The value to check for.
136 137 138 139 140 141 142 143 144 |
# File 'lib/gitlab/cache/import/caching.rb', line 136 def self.set_includes?(raw_key, value) validate_redis_value!(value) key = cache_key_for(raw_key) Redis::Cache.with do |redis| redis.sismember(key, value) end end |
.validate_redis_value!(value) ⇒ Object
250 251 252 253 254 255 |
# File 'lib/gitlab/cache/import/caching.rb', line 250 def self.validate_redis_value!(value) value_as_string = value.to_s return if value_as_string.is_a?(String) raise "Value '#{value_as_string}' of type '#{value_as_string.class}' for '#{value.inspect}' is not a String" end |
.values_from_hash(raw_key) ⇒ Object
Returns the values of the given hash.
raw_key - The key of the set to check.
234 235 236 237 238 239 240 |
# File 'lib/gitlab/cache/import/caching.rb', line 234 def self.values_from_hash(raw_key) key = cache_key_for(raw_key) with_redis do |redis| redis.hgetall(key) end end |
.values_from_set(raw_key) ⇒ Object
Returns the values of the given set.
raw_key - The key of the set to check.
149 150 151 152 153 154 155 |
# File 'lib/gitlab/cache/import/caching.rb', line 149 def self.values_from_set(raw_key) key = cache_key_for(raw_key) with_redis do |redis| redis.smembers(key) end end |
.with_redis(&block) ⇒ Object
246 247 248 |
# File 'lib/gitlab/cache/import/caching.rb', line 246 def self.with_redis(&block) Redis::Cache.with(&block) # rubocop:disable CodeReuse/ActiveRecord end |
.write(raw_key, value, timeout: TIMEOUT) ⇒ Object
Sets a cache key to the given value.
raw_key - The cache key to write. value - The value to set. timeout - The time after which the cache key should expire.
67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/gitlab/cache/import/caching.rb', line 67 def self.write(raw_key, value, timeout: TIMEOUT) validate_redis_value!(value) key = cache_key_for(raw_key) with_redis do |redis| redis.set(key, value, ex: timeout) end value end |
.write_if_greater(raw_key, value, timeout: TIMEOUT) ⇒ Object
Sets a key to the given integer but only if the existing value is smaller than the given value.
This method uses a Lua script to ensure the read and write are atomic.
raw_key - The key to set. value - The new value for the key. timeout - The key timeout in seconds.
Returns true when the key was overwritten, false otherwise.
200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/gitlab/cache/import/caching.rb', line 200 def self.write_if_greater(raw_key, value, timeout: TIMEOUT) validate_redis_value!(value) key = cache_key_for(raw_key) val = with_redis do |redis| redis .eval(WRITE_IF_GREATER_SCRIPT, keys: [key], argv: [value, timeout]) end val ? true : false end |
.write_multiple(mapping, key_prefix: nil, timeout: TIMEOUT) ⇒ Object
Sets multiple keys to given values.
mapping - A Hash mapping the cache keys to their values. key_prefix - prefix inserted before each key timeout - The time after which the cache key should expire.
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/gitlab/cache/import/caching.rb', line 162 def self.write_multiple(mapping, key_prefix: nil, timeout: TIMEOUT) with_redis do |redis| Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do Gitlab::Redis::CrossSlot::Pipeline.new(redis).pipelined do |pipeline| mapping.each do |raw_key, value| key = cache_key_for("#{key_prefix}#{raw_key}") validate_redis_value!(value) pipeline.set(key, value, ex: timeout) end end end end end |