Я использую Redis для создания алгоритма получения неиспользуемых целых чисел из диапазона.Мое решение основано на ответе, который я получил на этот SO вопрос.
В этом решении используются BITPOS
и BITSET
, и чтобы избежать условий гонки, я также использую WATCH
/MULTI
/ EXEC
.Чтобы протестировать аспекты параллелизма, я создал скрипт bash, который одновременно пытается найти свободное число 10 раз параллельно, чтобы исследовать возможные результаты команды EXEC
.
Я обнаружил, что EXEC
никогда не возвращал ноль, даже если отслеживаемый ключ был изменен другим клиентом.Я добавил задержки, чтобы было достаточно времени, чтобы спровоцировать параллельную модификацию, которая должна запустить механизм наблюдения, так что 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
}
, а также цикл, который вызывает SETBIT mykey, N, 1
для N = 1..10
в 10 различных процессах.
Я обнаружил, что EXEC
никогда не возвращал ноль, даже когда ключ былопределенно изменен другим процессом в течение наблюдаемого периода времени.
Вопросы:
- Не поддерживается ли
WATCH
просто для команд Redis на основе BIT? - Если этоподдерживается, почему это не сработало в этих условиях?Я тестирую / провоцирую это неправильно?Насколько я понимаю,
WATCH
должен вызывать сбой EXEC
, если ключ был изменен другим клиентом / подключением в течение наблюдаемого периода времени, и вызывать его из 10 различных процессов Linux, каждый из которых создает свойсобственное соединение, кажется, соответствует этому требованию? - В этом конкретном случае
WATCH
и MULTI
действительно предлагают что-нибудь?BITSET
возвращает предыдущее значение этого бита, поэтому атомарность не может быть гарантирована простым алгоритмом псевдокода:
while (true) {
number = BITPOS mykey, 0
if (number > maxNumber) THROW ERROR
wasUsed = SETBIT mykey, number, 1
if (!wasUsed) {
return number
}
}