Почему Redis обрезает конечные пробелы перед вычислением хэша SHA1 сценария? - PullRequest
0 голосов
/ 11 мая 2018

Redis позволяет загружать сценарии Lua с помощью команды SCRIPT LOAD, а в документации говорит, что возвращенный "хэш SHA-1" может быть вызван через EVALSHA. Это работает, как и ожидалось.

Затем я «оптимизировал» часть процесса развертывания, так что у нас есть отдельная программа, которая загружает сценарии Lua. Он генерирует хэши SHA-1 с помощью команды Unix sha1sum, поскольку я (наивно) предположил, что Redis фактически использовал SHA-1 файла, как указано. Но после этого я продолжал получать NOSCRIPT ошибок при попытке EVAL скриптов в Redis.

Очевидно, Redis (я использую v3.0.6) изменяет скрипт перед генерацией хэша SHA-1 (демонстрация ниже).


Перейдя к самому простому тестовому примеру, я начал с этого сценария:

test.lua:

return nil

Я убедился, что файл сценария соответствует тому, что я думаю, и что оболочка (Bash) ничего странного с ним не сделала:

$ hexdump -C test.lua
00000000  72 65 74 75 72 6e 20 6e  69 6c 0a                 |return nil.|
0000000b

$ sha1sum test.lua
6f65c1b09395aee959e644fa26d4c6ca6f0d462d  test.lua

$ echo "$(cat test.lua)" | sha1sum
6f65c1b09395aee959e644fa26d4c6ca6f0d462d  -

И чтобы быть уверенным, я сравнил хеш SHA-1 с онлайн-реализацией SHA-1 на JavaScript:

6F65C1B09395AEE959E644FA26D4C6CA6F0D462D

Итак, я загрузил его в Redis:

$ redis-cli SCRIPT LOAD "$(cat test.lua)"
"79cefb99366d8809d2e903c5f36f50c2b731913f"

В попытке угадать, что Redis может делать со сценарием, я также попробовал тот же сценарий с CRLF в стиле Windows вместо LF-строк в стиле Unix, но это также не соответствовало результату Redis:

$ hexdump -C test.lua
00000000  72 65 74 75 72 6e 20 6e  69 6c 0d 0a              |return nil..|
0000000c

$ sha1sum test.lua
98260fd830c34607e437f5e418683c2a644b0d82  test.lua

Наконец, в раздражении я попытался удалить все пустое пространство, и вот! и вот, результаты совпали.

Пройдя немного дальше, я обнаружил, что по какой-то причине завершающие пробельные символы в последней строке удаляются с помощью Redis !

В качестве доказательства приведенный ниже пример работает либо с LF, либо с CRLF, внутренне, но завершается неудачно, если вы добавляете LF или CRLF в последнюю строку:

$ hexdump -C test.lua
00000000  69 66 20 74 72 75 65 20  74 68 65 6e 0a 72 65 74  |if true then.ret|
00000010  75 72 6e 20 6e 69 6c 0a  65 6e 64                 |urn nil.end|
0000001b

$ sha1sum test.lua
ee9d1de0dae159d76a57ecb8e7e8c8c75283ef1d  test.lua

$ redis-cli SCRIPT LOAD "$(cat test.lua)"
ee9d1de0dae159d76a57ecb8e7e8c8c75283ef1d

Так что дает? Почему Redis изменяет последнюю строку файла сценария перед вычислением хэша файла?


Редактировать: Решение, любезно предоставленное mwp , Итамар Хабер и проблема GitHub :

  1. По-видимому, это проблема Bash, которая может иметь какое-то отношение к таинственной переменной оболочки IFS , хотя, похоже, затрагивается только trailing-newline.

  2. Не используйте "$(...)" для загрузки скрипта, хотя StackOverflow рекомендует использовать форму .

  3. Используйте redis-cli -x SCRIPT LOAD < script.lua, который направляет файл через stdin к redis-cli, избегая мутаций. Флаг -x указывает redis-cli прочитать следующий аргумент из stdin.

1 Ответ

0 голосов
/ 11 мая 2018

Не знаю, но, к счастью, есть решение, данное здесь :

CHECKSUM=$(redis-cli -x script load < test.lua)

Преимущество такого подхода состоит в том, что, если алгоритм когда-либо изменится в будущем, вы все равно получите «правильную» контрольную сумму.

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