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>2021-07-20 12:55:51 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-07-20 12:55:51 +0300
commite8d2c2579383897a1dd7f9debd359abe8ae8373d (patch)
treec42be41678c2586d49a75cabce89322082698334 /lib/gitlab/cache
parentfc845b37ec3a90aaa719975f607740c22ba6a113 (diff)
Add latest changes from gitlab-org/gitlab@14-1-stable-eev14.1.0-rc42
Diffstat (limited to 'lib/gitlab/cache')
-rw-r--r--lib/gitlab/cache/ci/project_pipeline_status.rb8
-rw-r--r--lib/gitlab/cache/helpers.rb111
-rw-r--r--lib/gitlab/cache/import/caching.rb28
3 files changed, 140 insertions, 7 deletions
diff --git a/lib/gitlab/cache/ci/project_pipeline_status.rb b/lib/gitlab/cache/ci/project_pipeline_status.rb
index 9e958eb52fb..137f76bc96d 100644
--- a/lib/gitlab/cache/ci/project_pipeline_status.rb
+++ b/lib/gitlab/cache/ci/project_pipeline_status.rb
@@ -50,8 +50,6 @@ module Gitlab
def load_status
return if loaded?
- return unless Gitlab::Ci::Features.pipeline_status_omit_commit_sha_in_cache_key?(project) || commit
-
if has_cache?
load_from_cache
else
@@ -119,11 +117,7 @@ module Gitlab
end
def cache_key
- if Gitlab::Ci::Features.pipeline_status_omit_commit_sha_in_cache_key?(project)
- "#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:project:#{project.id}:pipeline_status"
- else
- "#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:project:#{project.id}:pipeline_status:#{commit&.sha}"
- end
+ "#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:project:#{project.id}:pipeline_status"
end
def commit
diff --git a/lib/gitlab/cache/helpers.rb b/lib/gitlab/cache/helpers.rb
new file mode 100644
index 00000000000..7b11d6bc9ff
--- /dev/null
+++ b/lib/gitlab/cache/helpers.rb
@@ -0,0 +1,111 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Cache
+ module Helpers
+ # @return [ActiveSupport::Duration]
+ DEFAULT_EXPIRY = 1.day
+
+ # @return [ActiveSupport::Cache::Store]
+ def cache
+ Rails.cache
+ end
+
+ def render_cached(obj_or_collection, with:, cache_context: -> (_) { current_user&.cache_key }, expires_in: Gitlab::Cache::Helpers::DEFAULT_EXPIRY, **presenter_args)
+ json =
+ if obj_or_collection.is_a?(Enumerable)
+ cached_collection(
+ obj_or_collection,
+ presenter: with,
+ presenter_args: presenter_args,
+ context: cache_context,
+ expires_in: expires_in
+ )
+ else
+ cached_object(
+ obj_or_collection,
+ presenter: with,
+ presenter_args: presenter_args,
+ context: cache_context,
+ expires_in: expires_in
+ )
+ end
+
+ render Gitlab::Json::PrecompiledJson.new(json)
+ end
+
+ private
+
+ # Optionally uses a `Proc` to add context to a cache key
+ #
+ # @param object [Object] must respond to #cache_key
+ # @param context [Proc] a proc that will be called with the object as an argument, and which should return a
+ # string or array of strings to be combined into the cache key
+ # @return [String]
+ def contextual_cache_key(presenter, object, context)
+ return object.cache_key if context.nil?
+
+ [presenter.class.name, object.cache_key, context.call(object)].flatten.join(":")
+ end
+
+ # Used for fetching or rendering a single object
+ #
+ # @param object [Object] the object to render
+ # @param presenter [Grape::Entity]
+ # @param presenter_args [Hash] keyword arguments to be passed to the entity
+ # @param context [Proc]
+ # @param expires_in [ActiveSupport::Duration, Integer] an expiry time for the cache entry
+ # @return [String]
+ def cached_object(object, presenter:, presenter_args:, context:, expires_in:)
+ cache.fetch(contextual_cache_key(presenter, object, context), expires_in: expires_in) do
+ Gitlab::Json.dump(presenter.represent(object, **presenter_args).as_json)
+ end
+ end
+
+ # Used for fetching or rendering multiple objects
+ #
+ # @param objects [Enumerable<Object>] the objects to render
+ # @param presenter [Grape::Entity]
+ # @param presenter_args [Hash] keyword arguments to be passed to the entity
+ # @param context [Proc]
+ # @param expires_in [ActiveSupport::Duration, Integer] an expiry time for the cache entry
+ # @return [Array<String>]
+ def cached_collection(collection, presenter:, presenter_args:, context:, expires_in:)
+ json = fetch_multi(presenter, collection, context: context, expires_in: expires_in) do |obj|
+ Gitlab::Json.dump(presenter.represent(obj, **presenter_args).as_json)
+ end
+
+ json.values
+ end
+
+ # An adapted version of ActiveSupport::Cache::Store#fetch_multi.
+ #
+ # The original method only provides the missing key to the block,
+ # not the missing object, so we have to create a map of cache keys
+ # to the objects to allow us to pass the object to the missing value
+ # block.
+ #
+ # The result is that this is functionally identical to `#fetch`.
+ def fetch_multi(presenter, *objs, context:, **kwargs)
+ objs.flatten!
+ map = multi_key_map(presenter, objs, context: context)
+
+ # TODO: `contextual_cache_key` should be constructed based on the guideline https://docs.gitlab.com/ee/development/redis.html#multi-key-commands.
+ Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
+ cache.fetch_multi(*map.keys, **kwargs) do |key|
+ yield map[key]
+ end
+ end
+ end
+
+ # @param objects [Enumerable<Object>] objects which _must_ respond to `#cache_key`
+ # @param context [Proc] a proc that can be called to help generate each cache key
+ # @return [Hash]
+ def multi_key_map(presenter, objects, context:)
+ objects.index_by do |object|
+ contextual_cache_key(presenter, object, context)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/cache/import/caching.rb b/lib/gitlab/cache/import/caching.rb
index 86441973941..4cbc0231bce 100644
--- a/lib/gitlab/cache/import/caching.rb
+++ b/lib/gitlab/cache/import/caching.rb
@@ -173,6 +173,34 @@ module Gitlab
val ? true : false
end
+ # 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.
+ def self.hash_add(raw_key, field, value, timeout: TIMEOUT)
+ key = cache_key_for(raw_key)
+
+ Redis::Cache.with do |redis|
+ redis.multi do |m|
+ m.hset(key, field, value)
+ m.expire(key, timeout)
+ end
+ end
+ end
+
+ # Returns the values of the given hash.
+ #
+ # raw_key - The key of the set to check.
+ def self.values_from_hash(raw_key)
+ key = cache_key_for(raw_key)
+
+ Redis::Cache.with do |redis|
+ redis.hgetall(key)
+ end
+ end
+
def self.cache_key_for(raw_key)
"#{Redis::Cache::CACHE_NAMESPACE}:#{raw_key}"
end