2

I am looking to make an efficient function to clear out a redis-based cache.

I have a method call that returns a number of keys from redis:

$redis.keys("foo:*")

That returns all the keys that start with "foo:". Next, I'd like to delete all the values for these keys.

One (memory-intensive) way to do this is:

$redis.keys("foo:*").each do |key|
  $redis.del(key)
end

I'd like to avoid loading all the keys into memory, and then making numerous requests to the redis server.

Another way that I like is to use the splat operator:

keys = $redis.keys("foo:*")
$redis.del(*keys)

The problem is that I don't know what the maximum arity of the $redis.del method, nor of any ruby method, I can't seem to find it online.

What is the maximum arity?

tlehman
  • 5,125
  • 2
  • 33
  • 51
  • I get a `SystemStackError: stack level too deep` for more than 130_000 arguments on my machine. – Patrick Oscity Aug 15 '13 at 19:03
  • Same for me. And sometimes ruby crashes badly: https://gist.github.com/DNNX/6243859 – DNNX Aug 15 '13 at 19:16
  • 1
    There's probably room for improvement in the implementation... Specifically, when just a single splat argument has been provided, it could just be assigned to the `args` variable instead of doing some recursive stuff under the hood. – Patrick Oscity Aug 15 '13 at 19:21
  • 1
    Does the redis driver perhaps know what to do with an array argument? `*keys` will be an array when it `del` sees it anyway so maybe `del` is smart enough to auto-flatten it (and if it isn't, maybe you could monkey patch some sense into it). – mu is too short Aug 15 '13 at 19:25
  • And one more interesting fact. When I don't use the splat operator, ruby works fine when I define and call a function with 6892 arguments, but fails with SO error if the number of arguments is 6893. See the updated gist. – DNNX Aug 15 '13 at 19:31
  • I am getting `SystemStackError` when I run `$redis.del(*$redis.keys("foo:*")) # => SystemStackError: stack level too deep`, I seeded redis with 1,000,000 keys `"foo:1", ... "foo:1000000"`. This is a realistic number of keys, one way I could do this is break up the keys into chunks of 1000 and splat each one. Is the overhead associated with slicing ruby arrays low enough that it would be worth it? Or should I stick with my original solution? – tlehman Aug 15 '13 at 20:53
  • @muistooshort it turns out the redis driver does know what to do with an array argument, that worked. – tlehman Aug 15 '13 at 21:23

1 Answers1

0

@muistooshort in the comments had a good suggestion that turned out to be right, the redis driver knows what to do with an array argument:

 # there are 1,000,000 keys of the form "foo:#{number}"
 keys = $redis.keys("foo:*")
 $redis.del(keys) # => 1000000

Simply pass an array of keys to $redis.del

tlehman
  • 5,125
  • 2
  • 33
  • 51