разбор полётов
Apr. 14th, 2005 08:59 pmПару слов о баге, который проявился у многих пользователей в последние сутки-двое, при котором невозможно было посмотреть свою ленту друзей.
Будет интересно программистам, знающим Перл (и не знающим тоже, впрочем).
Баг включался вот при каких обстоятельствах. У кого-то на компьютере неправильно проставлена дата. Но не просто в будущем или в прошлом (это, кстати, бывает очень часто), а настолько всё плохо, что бывают невозможные даты. Скажем, 31-е апреля или 30-е февраля.
Когда сервер ЖЖ принимает дату записи от клиента (или от джаваскрипта пользовательского браузера), он в принципе должен проверять её корректность. В прошлом или в будущем она вполне может быть, это не запрещается, но невозможной быть не должна. Эта провека не срабатывала (почему? ещё проверяется), и невозможная дата попадала в базу данных. Это, однако, до поры до времени никому не мешало. Всё равно ленты друзей, например, сортируются по серверной дате, а не той, которую даёт клиент. Дата, которую даёт клиент, используется только для сортировки главной страницы журнала, а также календарных страниц; и ещё её показывают всюду, ясно.
Итак, в процессе постройки ленты друзей эти даты не используются для сортировки; но они всё равно обрабатываются для показа. В процессе обработки они переводятся из внутреннего формата базы данных MySQL в некий другой формат. Для этого вызывается перловская функция Time::Local::timegm(), которая берёт набор чисел - год, месяц, день, час, минута, секунда - и возвращает число секунд, прошедшее с полуночи первого января 1970-го года до этого времени (так называемое Unix epoch time). Потом это число в свою очередь преобразовывается в нужный формат, позже.
Что случилось? Вчера все серверы, обслуживающие запросы ЖЖ, были все переведены с версии Перла 5.6 на версию 5.8. В обоих версиях Перла фунцкия timegm(), если ей не нравятся переданные ей данные, "умирает" с ошибкой. Однако в перле 5.6 проверка правильности даты, в частности числа дня в месяце, несколько, гм, упрощённая:
(т.е. число, в данном случае $_[3], проверяется только на >31 и <1)
В перле 5.8 проверку ужесточили:
Т.е. число $mday сравнивается не с 31, а с правильной предельной датой для данного месяца, хранящейся в массиве MonthDays. И даже високосные годы учтены (вторая строка).
Поэтому внезапно вчера Перл начал умирать, когда ему передают невозможные даты записей типа 31-го апреля. Т.к. со стороны кода ЖЖ никто такую возможность не учитывал, код ЖЖ в таком случае тоже умирал и обработчик самой внешней оболочки ловил это падение, не понимал, в чём дело, и выдавал пользователю невнятную ошибку вида "Technical difficulties".
Конечно, перед тем как перевести серверы на Perl 5.8, всё проверяли, но эту проблему не отловили, т.к. настолько неверные даты встречаются очень-очень редко (зато когда всё же встречаются, то сразу хлопаются френд-ленты всех друзей данного юзера или сообщества, поэтому очень заметно). Собственно, довольно долгое время часть серверов ЖЖ, примерно четверть, бежали под Perl 5.8, и у них случалась эта проблема, значит; но т.к. пользователи, после нажатия Reload в браузере, попадали на другой случайный сервер, который с большой вероятностью был Perl 5.6 и всё показывал, они считали, что это просто проблемы с нагрузкой или чем-нибудь таким.
Будет интересно программистам, знающим Перл (и не знающим тоже, впрочем).
Баг включался вот при каких обстоятельствах. У кого-то на компьютере неправильно проставлена дата. Но не просто в будущем или в прошлом (это, кстати, бывает очень часто), а настолько всё плохо, что бывают невозможные даты. Скажем, 31-е апреля или 30-е февраля.
Когда сервер ЖЖ принимает дату записи от клиента (или от джаваскрипта пользовательского браузера), он в принципе должен проверять её корректность. В прошлом или в будущем она вполне может быть, это не запрещается, но невозможной быть не должна. Эта провека не срабатывала (почему? ещё проверяется), и невозможная дата попадала в базу данных. Это, однако, до поры до времени никому не мешало. Всё равно ленты друзей, например, сортируются по серверной дате, а не той, которую даёт клиент. Дата, которую даёт клиент, используется только для сортировки главной страницы журнала, а также календарных страниц; и ещё её показывают всюду, ясно.
Итак, в процессе постройки ленты друзей эти даты не используются для сортировки; но они всё равно обрабатываются для показа. В процессе обработки они переводятся из внутреннего формата базы данных MySQL в некий другой формат. Для этого вызывается перловская функция Time::Local::timegm(), которая берёт набор чисел - год, месяц, день, час, минута, секунда - и возвращает число секунд, прошедшее с полуночи первого января 1970-го года до этого времени (так называемое Unix epoch time). Потом это число в свою очередь преобразовывается в нужный формат, позже.
Что случилось? Вчера все серверы, обслуживающие запросы ЖЖ, были все переведены с версии Перла 5.6 на версию 5.8. В обоих версиях Перла фунцкия timegm(), если ей не нравятся переданные ей данные, "умирает" с ошибкой. Однако в перле 5.6 проверка правильности даты, в частности числа дня в месяце, несколько, гм, упрощённая:
croak "Day '$_[3]' out of range 1..31" if $_[3] > 31 || $_[3] < 1;(т.е. число, в данном случае $_[3], проверяется только на >31 и <1)
В перле 5.8 проверку ужесточили:
my $md = $MonthDays[$month];
++$md unless $month != 1 or $year % 4 or !($year % 400);
croak "Day '$mday' out of range 1..$md" if $mday > $md or $mday < 1;
Т.е. число $mday сравнивается не с 31, а с правильной предельной датой для данного месяца, хранящейся в массиве MonthDays. И даже високосные годы учтены (вторая строка).
Поэтому внезапно вчера Перл начал умирать, когда ему передают невозможные даты записей типа 31-го апреля. Т.к. со стороны кода ЖЖ никто такую возможность не учитывал, код ЖЖ в таком случае тоже умирал и обработчик самой внешней оболочки ловил это падение, не понимал, в чём дело, и выдавал пользователю невнятную ошибку вида "Technical difficulties".
Конечно, перед тем как перевести серверы на Perl 5.8, всё проверяли, но эту проблему не отловили, т.к. настолько неверные даты встречаются очень-очень редко (зато когда всё же встречаются, то сразу хлопаются френд-ленты всех друзей данного юзера или сообщества, поэтому очень заметно). Собственно, довольно долгое время часть серверов ЖЖ, примерно четверть, бежали под Perl 5.8, и у них случалась эта проблема, значит; но т.к. пользователи, после нажатия Reload в браузере, попадали на другой случайный сервер, который с большой вероятностью был Perl 5.6 и всё показывал, они считали, что это просто проблемы с нагрузкой или чем-нибудь таким.
no subject
Date: 2005-04-15 11:09 pm (UTC)no subject
Date: 2005-04-16 12:42 am (UTC)