问题
I'm using Redis to create an algorithm for claiming unused integers from a range. My solution is based on the answer I got for this SO question.
This solution uses BITPOS
and BITSET
, and to avoid race conditions, I also use WATCH
/MULTI
/EXEC
. In order to test the concurrency aspects I created a bash script that concurrently attempts to find a free number 10 times in parallel, to investigate the possible outcomes of the EXEC
command.
What I found was that EXEC
never returned null, even when the watched key was modified by another client. I added delays such that there was plenty of time to provoke a concurrent modification that should trigger the watch mechanism so that EXEC
fails, but it didn't.
So basically I had this piece of code:
while (true) {
WATCH mykey
number = BITPOS mykey, 0
if (number > maxNumber) THROW ERROR
(deliberate delay)
MULTI
SETBIT mykey, number, 1
if EXEC != null return number
}
and also a loop that calls SETBIT mykey, N, 1
for N = 1..10
, in 10 different processes.
What I found was that EXEC
never returned null, even when the key was definitely modified by another process during the watched period of time.
Questions:
- Is
WATCH
simply not supported for BIT based Redis commands? - If it is supported, why wasn't it triggered under these circumstances? Am I testing/provoking it incorrectly? As I understand it,
WATCH
should makeEXEC
fail if the key has been modified by another client/connection during the watched period of time, and calling this from 10 different Linux processes, each creating its own connection, seems to fit that requirement? - In this particular case, does
WATCH
andMULTI
actually offer anything?BITSET
returns the previous value of that bit, so shouldn't atomicity be guaranteed simply by the following pseudo-code algorithm:
while (true) {
number = BITPOS mykey, 0
if (number > maxNumber) THROW ERROR
wasUsed = SETBIT mykey, number, 1
if (!wasUsed) {
return number
}
}
回答1:
There's no documentation suggesting that
WATCH
doesn't support the bit setting commands.Your code looks right to me, so it's hard to say why it isn't working. To investigate it further you'd have to provide a MCVE rather than pseudocode. However...
You're right, you don't need a transaction here, this algorithm should guarantee atomicity.
来源:https://stackoverflow.com/questions/54568723/redis-bitset-and-watch