aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support/cache/redis_cache_store.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport/lib/active_support/cache/redis_cache_store.rb')
-rw-r--r--activesupport/lib/active_support/cache/redis_cache_store.rb25
1 files changed, 16 insertions, 9 deletions
diff --git a/activesupport/lib/active_support/cache/redis_cache_store.rb b/activesupport/lib/active_support/cache/redis_cache_store.rb
index 64bc77cf22..11c574258f 100644
--- a/activesupport/lib/active_support/cache/redis_cache_store.rb
+++ b/activesupport/lib/active_support/cache/redis_cache_store.rb
@@ -62,8 +62,9 @@ module ActiveSupport
end
end
- DELETE_GLOB_LUA = "for i, name in ipairs(redis.call('KEYS', ARGV[1])) do redis.call('DEL', name); end"
- private_constant :DELETE_GLOB_LUA
+ # The maximum number of entries to receive per SCAN call.
+ SCAN_BATCH_SIZE = 1000
+ private_constant :SCAN_BATCH_SIZE
# Support raw values in the local cache strategy.
module LocalCacheWithRaw # :nodoc:
@@ -118,7 +119,7 @@ module ActiveSupport
def build_redis(redis: nil, url: nil, **redis_options) #:nodoc:
urls = Array(url)
- if redis.respond_to?(:call)
+ if redis.is_a?(Proc)
redis.call
elsif redis
redis
@@ -154,7 +155,7 @@ module ActiveSupport
# :url Array -> Redis::Distributed.new([{ url: … }, { url: … }, …])
#
# No namespace is set by default. Provide one if the Redis cache
- # server is shared with other apps: <tt>namespace: 'myapp-cache'<tt>.
+ # server is shared with other apps: <tt>namespace: 'myapp-cache'</tt>.
#
# Compression is enabled by default with a 1kB threshold, so cached
# values larger than 1kB are automatically compressed. Disable by
@@ -231,12 +232,18 @@ module ActiveSupport
# Failsafe: Raises errors.
def delete_matched(matcher, options = nil)
instrument :delete_matched, matcher do
- case matcher
- when String
- redis.with { |c| c.eval DELETE_GLOB_LUA, [], [namespace_key(matcher, options)] }
- else
+ unless String === matcher
raise ArgumentError, "Only Redis glob strings are supported: #{matcher.inspect}"
end
+ redis.with do |c|
+ pattern = namespace_key(matcher, options)
+ cursor = "0"
+ # Fetch keys in batches using SCAN to avoid blocking the Redis server.
+ begin
+ cursor, keys = c.scan(cursor, match: pattern, count: SCAN_BATCH_SIZE)
+ c.del(*keys) unless keys.empty?
+ end until cursor == "0"
+ end
end
end
@@ -286,7 +293,7 @@ module ActiveSupport
# Failsafe: Raises errors.
def clear(options = nil)
failsafe :clear do
- if namespace = merged_options(options)[namespace]
+ if namespace = merged_options(options)[:namespace]
delete_matched "*", namespace: namespace
else
redis.with { |c| c.flushdb }