Redis BITSET 和 WATCH

Redis BITSET and WATCH

我正在使用 Redis 创建一个算法,用于从一个范围内声明未使用的整数。我的解决方案基于我对 SO 问题的回答。

此解决方案使用 BITPOSBITSET,为了避免竞争条件,我还使用 WATCH/MULTI/EXEC。为了测试并发方面,我创建了一个 bash 脚本,它同时尝试并行查找一个空闲号码 10 次,以调查 EXEC 命令的可能结果。

我发现 EXEC 从未返回 null,即使监视的密钥已被另一个客户端修改。我添加了延迟,以便有足够的时间来触发应该触发监视机制的并发修改,以便 EXEC 失败,但它没有。

所以基本上我有这段代码:

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
}

还有一个在 10 个不同的进程中为 N = 1..10 调用 SETBIT mykey, N, 1 的循环。

我发现 EXEC 从未返回 null,即使在监视的时间段内密钥肯定被另一个进程修改了。

问题:

  1. WATCH 是否根本不支持基于 BIT 的 Redis 命令?
  2. 如果支持,为什么在这种情况下没有触发?我 testing/provoking 是不是写错了?据我了解,WATCH 应该使 EXEC 失败,如果密钥已被修改 被另一个 client/connection 在观看的时间段内,并调用这来自 10 个不同的 Linux 进程,每个进程都创建自己的连接,似乎符合该要求?
  3. 在这种特殊情况下,WATCHMULTI 真的能提供什么吗? BITSET returns 该位的先前值,因此不应该仅通过以下伪代码算法来保证原子性:
    while (true) {
      number = BITPOS mykey, 0
      if (number > maxNumber) THROW ERROR

      wasUsed = SETBIT mykey, number, 1

      if (!wasUsed) {
        return number
      }
    }
  1. 没有文档表明WATCH不支持位设置命令。

  2. 你的代码在我看来是正确的,所以很难说为什么它不起作用。要进一步调查它,您必须提供 MCVE 而不是伪代码。然而...

  3. 你说的对,这里不需要事务,这个算法应该保证原子性。