diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-18 11:17:02 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-18 11:17:02 +0300 |
commit | b39512ed755239198a9c294b6a45e65c05900235 (patch) | |
tree | d234a3efade1de67c46b9e5a38ce813627726aa7 /lib/gitlab/utils | |
parent | d31474cf3b17ece37939d20082b07f6657cc79a9 (diff) |
Add latest changes from gitlab-org/gitlab@15-3-stable-eev15.3.0-rc42
Diffstat (limited to 'lib/gitlab/utils')
-rw-r--r-- | lib/gitlab/utils/batch_loader.rb | 23 | ||||
-rw-r--r-- | lib/gitlab/utils/link_header_parser.rb | 46 | ||||
-rw-r--r-- | lib/gitlab/utils/strong_memoize.rb | 73 | ||||
-rw-r--r-- | lib/gitlab/utils/usage_data.rb | 4 |
4 files changed, 144 insertions, 2 deletions
diff --git a/lib/gitlab/utils/batch_loader.rb b/lib/gitlab/utils/batch_loader.rb new file mode 100644 index 00000000000..67ade0633e2 --- /dev/null +++ b/lib/gitlab/utils/batch_loader.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Gitlab + module Utils + module BatchLoader + # Clears batched items under the specified batch key + # https://github.com/exAspArk/batch-loader#batch-key + def self.clear_key(batch_key) + return if ::BatchLoader::Executor.current.nil? + + items_to_clear = ::BatchLoader::Executor.current.items_by_block.select do |k, v| + # The Hash key here is [source_location, batch_key], so we just check k[1] + k[1] == batch_key + end + + items_to_clear.each do |k, v| + ::BatchLoader::Executor.current.items_by_block.delete(k) + ::BatchLoader::Executor.current.loaded_values_by_block.delete(k) + end + end + end + end +end diff --git a/lib/gitlab/utils/link_header_parser.rb b/lib/gitlab/utils/link_header_parser.rb new file mode 100644 index 00000000000..d98c237baf3 --- /dev/null +++ b/lib/gitlab/utils/link_header_parser.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module Gitlab + module Utils + # Parses Link http headers (as defined in https://www.rfc-editor.org/rfc/rfc5988.txt) + # + # The URI-references with their relation type are extracted and returned as a hash + # Example: + # + # header = '<http://test.org/TheBook/chapter2>; rel="previous", <http://test.org/TheBook/chapter4>; rel="next"' + # + # Gitlab::Utils::LinkHeaderParser.new(header).parse + # { + # previous: { + # uri: #<URI::HTTP http://test.org/TheBook/chapter2> + # }, + # next: { + # uri: #<URI::HTTP http://test.org/TheBook/chapter4> + # } + # } + class LinkHeaderParser + REL_PATTERN = %r{rel="(\w+)"}.freeze + # to avoid parse really long URIs we limit the amount of characters allowed + URI_PATTERN = %r{<(.{1,500})>}.freeze + + def initialize(header) + @header = header + end + + def parse + return {} if @header.blank? + + links = @header.split(',') + result = {} + links.each do |link| + direction = link[REL_PATTERN, 1]&.to_sym + uri = link[URI_PATTERN, 1] + + result[direction] = { uri: URI(uri) } if direction && uri + end + + result + end + end + end +end diff --git a/lib/gitlab/utils/strong_memoize.rb b/lib/gitlab/utils/strong_memoize.rb index 3c954f817a7..50b8428113d 100644 --- a/lib/gitlab/utils/strong_memoize.rb +++ b/lib/gitlab/utils/strong_memoize.rb @@ -21,6 +21,20 @@ module Gitlab # end # end # + # Or like: + # + # include Gitlab::Utils::StrongMemoize + # + # def trigger_from_token + # Ci::Trigger.find_by_token(params[:token].to_s) + # end + # strong_memoize_attr :trigger_from_token + # + # strong_memoize_attr :enabled?, :enabled + # def enabled? + # Feature.enabled?(:some_feature) + # end + # def strong_memoize(name) key = ivar(name) @@ -40,6 +54,34 @@ module Gitlab remove_instance_variable(key) if instance_variable_defined?(key) end + module StrongMemoizeClassMethods + def strong_memoize_attr(method_name, member_name = nil) + member_name ||= method_name + + if method_defined?(method_name) || private_method_defined?(method_name) + StrongMemoize.send( # rubocop:disable GitlabSecurity/PublicSend + :do_strong_memoize, self, method_name, member_name) + else + StrongMemoize.send( # rubocop:disable GitlabSecurity/PublicSend + :queue_strong_memoize, self, method_name, member_name) + end + end + + def method_added(method_name) + super + + if member_name = StrongMemoize + .send(:strong_memoize_queue, self).delete(method_name) # rubocop:disable GitlabSecurity/PublicSend + StrongMemoize.send( # rubocop:disable GitlabSecurity/PublicSend + :do_strong_memoize, self, method_name, member_name) + end + end + end + + def self.included(base) + base.singleton_class.prepend(StrongMemoizeClassMethods) + end + private # Convert `"name"`/`:name` into `:@name` @@ -54,6 +96,37 @@ module Gitlab raise ArgumentError, "Invalid type of '#{name}'" end end + + class <<self + private + + def strong_memoize_queue(klass) + klass.instance_variable_get(:@strong_memoize_queue) || klass.instance_variable_set(:@strong_memoize_queue, {}) + end + + def queue_strong_memoize(klass, method_name, member_name) + strong_memoize_queue(klass)[method_name] = member_name + end + + def do_strong_memoize(klass, method_name, member_name) + method = klass.instance_method(method_name) + + # Methods defined within a class method are already public by default, so we don't need to + # explicitly make them public. + scope = %i[private protected].find do |scope| + klass.send("#{scope}_instance_methods") # rubocop:disable GitlabSecurity/PublicSend + .include? method_name + end + + klass.define_method(method_name) do |*args, &block| + strong_memoize(member_name) do + method.bind_call(self, *args, &block) + end + end + + klass.send(scope, method_name) if scope # rubocop:disable GitlabSecurity/PublicSend + end + end end end end diff --git a/lib/gitlab/utils/usage_data.rb b/lib/gitlab/utils/usage_data.rb index 4d1b234ae54..19bdeefed7e 100644 --- a/lib/gitlab/utils/usage_data.rb +++ b/lib/gitlab/utils/usage_data.rb @@ -196,7 +196,7 @@ module Gitlab def alt_usage_data(value = nil, fallback: FALLBACK, &block) with_duration do - if block_given? + if block yield else value @@ -209,7 +209,7 @@ module Gitlab def redis_usage_data(counter = nil, &block) with_duration do - if block_given? + if block redis_usage_counter(&block) elsif counter.present? redis_usage_data_totals(counter) |