Проектная лаборатория
Собственный Redis
Этап 68 · Оптимистическая блокировка
Отслеживание изменений ключей
Русский перевод заданий CodeCrafters. Примеры подготовлены для Go. Выбор языка меняет команды и результаты, но не текст задания.
На этом этапе вы реализуете EXEC и отмену транзакций.
Напоминание о транзакциях Redis
Транзакции Redis позволяют выполнять несколько команд как одну операцию. Основная последовательность:
MULTI— перейти в режим транзакции (реализовано ранее).SET key value,INCR counterи другие — поставить команды в очередь.EXEC— выполнить все команды очереди.
Сейчас вы реализуете EXEC и отмену транзакций, если их отслеживаемые ключи изменились.
Команда EXEC
Команда EXEC выполняет все команды, поставленные в очередь после MULTI:
$ redis-cli
> SET foo 100
OK
> MULTI
OK
> SET foo 200
QUEUED
> SET bar 300
QUEUED
> EXEC
1) OK
2) OKОтвет — массив RESP, каждый элемент которого содержит результат команды в порядке постановки в очередь.
Отмена транзакций с WATCH
Если соединение отслеживает ключи, EXEC должна проверить, не изменил ли другой клиент любой из них между WATCH и EXEC. Если изменил, транзакция отменяется:
Client A: WATCH foo # Server tracks "foo" for Client A
Client A: MULTI
Client A: SET bar 300 # Queued
Client B: SET foo 999 # Modifies Client A's watched key
Client A: EXEC # Returns *-1\r\n, queued commands discardedEXEC возвращает нулевой массив RESP (*-1\r\n), а команды очереди удаляются без выполнения.
Если отслеживаемые ключи не изменились, EXEC выполняет транзакцию обычным образом.
Тесты
Тестирующая программа запустит вашу программу так:
$ ./your_program.shОна создаст четырёх клиентов и выполнит два сценария.
В первом другой клиент изменяет отслеживаемый ключ:
# Client 1
> SET foo 100 # → +OK
> SET bar 200 # → +OK
> WATCH foo # → +OK
> MULTI # → +OK
> SET bar 300 # → +QUEUED
# Client 2 modifies the watched key
> SET foo 200 # → +OK
# Client 1 tries to execute
> EXEC # → *-1\r\n (null array, transaction aborted)
> GET bar # → "200" (unchanged, SET bar 300 was never executed)Во втором изменяется другой, неотслеживаемый ключ:
# Client 3
> SET baz 100 # → +OK
> SET caz 200 # → +OK
> WATCH baz # → +OK
> MULTI # → +OK
> SET caz 400 # → +QUEUED
# Client 4 modifies a different key (not the watched one)
> SET caz 300 # → +OK
# Client 3 executes successfully
> EXEC # → array of responses (baz was not modified)
# Client 4 verifies the transaction's write took effect
> GET caz # → "400"Будет проверено, что:
EXECвозвращает нулевой массив RESP (*-1\r\n), если другой клиент изменил отслеживаемый ключ.EXECвозвращает массив результатов команд, если отслеживаемые ключи не менялись.- При отмене транзакции команды очереди не выполняются, исходные значения сохраняются.
- Если отслеживаемые ключи не менялись, команды выполняются и их записи вступают в силу.
Примечания
- Недостаточно сравнить значение ключа в момент
WATCHиEXEC. Если ключ изменили, а потом вернули исходное значение, транзакция всё равно должна отмениться. Отслеживайте факт записи в ключ, а не итоговое отличие значения. - После
EXECочищайте состояние наблюдения соединения — ключи и флаг dirty — независимо от успеха или отмены транзакции.
Проверка в вашей IDE
Нужны Node.js, Git, Go 1.24+ для тестеров и инструменты выбранного языка. Тестеры загружаются и запускаются локально; отдельным проектам нужны дополнительные системные зависимости.
Настройка проекта и IDE
1. Создайте проект один раз
node '/opt/graphlms/tools/project-lab/cli.mjs' init redis ./my-redis --language go2. Откройте папку в IDE
cd ./my-redisРеализуйте требования этапа в созданном проекте.
Запустите из папки проекта
node '/opt/graphlms/tools/project-lab/cli.mjs' submit --stage mh8Запускайте submit из папки проекта. Это локальные проверки, а не сертификаты или результаты аккаунта CodeCrafters.
Результат проверки
go / ЛОКАЛЬНОПодключение к локальной проверке…
Здесь появится результат
Запустите submit в терминале. Страница обновляет результаты каждые 8 секунд.