I am trying to use BITFIELD as counter in my rate limiter application by defining its lowest and highest bounds but not sure how to achieve it. What exactly I need it is that, counter starts from 0 and can go up to 30 at max (or any other number I need in future such as 10,000).
The one below goes up to 15 and then responds with null
. Not sure how to specify these limits.
BITFIELD k-19 OVERFLOW FAIL INCRBY u4 1 1
Note: I can achieve this using a Lua script but I am not sure if it would cause performance issues.
local key = KEYS[1]
local inc = ARGV[1]
local max = tonumber(ARGV[2])
local val = redis.call("GET", key) or 0
val = val + inc
if (val >= 0 and val < max) then
redis.call("SET", key, val)
return val
end
return max
UPDATE:
As per Guy Royse and Lior Kogan’s answers, I think BITFIELD may not be the best fit for the purpose for this case. It is mainly because the upper limit won’t always be "power of 2 minus 1" or anything close to it in my case.
2
Answers
I don’t think you can do better than this. Unless, of course, you can change
max
from 30 to 31 (or any other 2^n-1 where n is an integer value). If so, you can simply assign n bits and setOVERFLOW
toSAT
.One note about your code:
val = val + inc
may be sensitive to lost of integral precision, but it is not a real issue if you control these values.The command you are issuing says to increment the 4-bit unsigned integer located at position 1 (i.e the second position as BITFIELD is zero-based) by a value of 1. If this 4-bit number—which as a 4-bit number can only have values between 0 and 15—overflows (i.e exceeds the maximum value of a 4-bit number), then error by returning null and do not increment the value.
This is just how it works. There is no way to set an upper or lower bound that isn’t a power of 2 minus 1 as these are binary numbers. You could use a unsigned 5-bit number and then the upper bound would be 31. Or a 6-bit number and then we’re at 63.
However, I think you might be overthinking this. I would just use INCR and DECR for this instead. Both return the new value of the key. Both are atomic. And internally, Redis stores numbers in Strings as integers so it’s not even taking up more space.
It would look like this:
And to show that it is indeed a number and not a string: