Как сравнить AndSet работает внутри Redis - PullRequest
0 голосов
/ 17 января 2019

spring-data-redis модуль содержит RedisAtomicLong класс.

В этом классе вы можете увидеть

public boolean compareAndSet(long expect, long update) {

    return generalOps.execute(new SessionCallback<Boolean>() {

        @Override
        @SuppressWarnings("unchecked")
        public Boolean execute(RedisOperations operations) {
            for (;;) {
                operations.watch(Collections.singleton(key));
                if (expect == get()) {
                    generalOps.multi();
                    set(update);
                    if (operations.exec() != null) {
                        return true;
                    }
                }
                {
                    return false;
                }
            }
        }
    });
}

У меня вопрос, почему это работает?

generalOps.multi() начинает транзакцию после вызова get(). Это означает, что существует вероятность того, что два разных потока (или даже клиента) могут изменить значение, и оба они преуспеют.

operations.watch это как-то предотвратить? JavaDoc не объясняет назначение этого метода.

PS: незначительный вопрос: почему for (;;)? Всегда есть одна итерация.

Ответы [ 2 ]

0 голосов
/ 17 января 2019

Q: Operations.watch как-то это предотвращает?

YES.

Цитирование из Redis документация о транзакции :

WATCH используется для обеспечения поведения проверки и установки (CAS) для транзакций Redis.

Наблюдаемые ключи отслеживаются для выявления изменений в них. Если хотя бы один отслеживаемый ключ был изменен до выполнения команды EXEC, вся транзакция прерывается, и EXEC возвращает нулевой ответ, чтобы уведомить о сбое транзакции.

Вы можете узнать больше о транзакции Redis из этой документации.

В: почему для (;;)? Всегда есть одна итерация.

Кажется, код, который вы разместили, очень старый. Из кеша Google этого URL я увидел предоставленный вами код, датированный Oct 15th, 2012!

Последние коды выглядят совсем иначе:

0 голосов
/ 17 января 2019

Является ли Operations.Watch каким-то образом предотвратить это?

YES. После просмотра ключа, если ключ был изменен до завершения транзакции, EXEC не удастся. Таким образом, если EXEC успешно, значение гарантированно не изменится другими.

почему для (;;)? Всегда есть одна итерация.

В вашем случае кажется, что бесконечный цикл избыточен.

Однако, если вы хотите реализовать операцию проверки и установки, чтобы изменить значение на старое значение, необходим бесконечный цикл. Проверьте этот пример из redis doc :

WATCH mykey
val = GET mykey
val = val + 1
MULTI
SET mykey $val
EXEC

Поскольку EXEC может дать сбой, вам нужно повторить весь процесс в цикле, пока он не будет успешным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...