разбор полётов
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-14 06:07 pm (UTC)no subject
Date: 2005-04-14 06:09 pm (UTC)у нас, например, работает мониторилка error_log'ов, которая их шлёт в список рассылки, и если туда что-то приходит, то этот вопрос рассматривается и фиксится. Чрезвычайно полезно.
no subject
Date: 2005-04-14 06:33 pm (UTC)Те URLи, которые не .bml/.html (ленты, календари, главные страницы дневников) обрабатываются по-другому, через довольно древний интерфейс, который несколько раз латали, и который плохо сохраняет дополнительную информацию (кроме самого текста страницы), возвращаясь снизу вверх. На самом деле ошибки всё равно идут в базу данных. Но их всегда так много (и некоторые из них вполне рутинные типа несуществующих URLей из-за того, что кто-то ссылку испортил или ещё чего), что трудно отличить зерна от плевел. А когда появляется новый реальный баг, из-за уровня траффика ошибки, с ним связанные, даже если бы их можно было отделить от остальных, текут таким густым потоком, что никакая рассылка не выдержит. Нужно что-то умное, что умело бы группировать ошибки и отсекать мусор, никто не хочет это писать, наверное.
(no subject)
From:(no subject)
From:no subject
Date: 2005-04-14 06:38 pm (UTC)no subject
Date: 2005-04-14 06:15 pm (UTC)no subject
Date: 2005-04-14 06:17 pm (UTC)Я сегодня тоже интересный баг имел (точнее, баг имел меня). Но я не уверен, что этот баг интересен кому-то, кроме меня :).
no subject
Date: 2005-04-14 06:27 pm (UTC)Интересно, а как может быть передана неисправная дата? Я не верю что ОС дата может быть неисправной, ни в Виндах, ни в Юниксолинухах.
Вероятно в каком-то клиенте есть глюк, который позволяя выставлять кастом дату для постинга не проверяет её на корректность.
no subject
Date: 2005-04-14 06:32 pm (UTC)А бага конечно красивая. Её фиг поймаешь слёту.
Всё-таки в вебе часто бывает ощущение, что "само прошло" . F5/Ctrl+F5/restart browser - и нет ошибки
no subject
Date: 2005-04-14 06:36 pm (UTC)Это чисто ЖЖшный глюк!
Если из веб интерфейса ручками исправить дату нового поста на некорректную, то ЖЖ её честно завает.
Правьте короче:)
no subject
Date: 2005-04-14 06:33 pm (UTC)no subject
Date: 2005-04-14 06:34 pm (UTC)(no subject)
From:no subject
Date: 2005-04-14 06:35 pm (UTC)(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:no subject
Date: 2005-04-14 06:48 pm (UTC)no subject
Date: 2005-04-14 06:37 pm (UTC)Вот. Из Веб интерфейса, без каких-либо проблем.
no subject
Date: 2005-04-14 06:38 pm (UTC)(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:no subject
Date: 2005-04-14 07:32 pm (UTC)no subject
Date: 2005-04-14 09:39 pm (UTC)no subject
Date: 2005-04-14 09:56 pm (UTC)no subject
Date: 2005-04-14 11:00 pm (UTC)Видел где-то имплементацию mktime (в BSD-шной libc?), которая проверяет, является ли дата, разбитая на (год, месяц, день, час, мнуту, секунду), "хорошей", путем бинарного поиска по time_t.
no subject
Date: 2005-04-14 11:15 pm (UTC)no subject
Date: 2005-04-15 12:19 am (UTC)отличная бага.
только насколько я помню хотя бы тот же php, затолкать некорректную дату в функции даты/времени практически невозможная задача. Как это в перле интересно получается.
no subject
Date: 2005-04-15 06:28 am (UTC)В PHP при попытке затолкать 31-е апреля, например, мы получим первое мая.
(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:Кто автор?
From:Re: Кто автор?
From:no subject
Date: 2005-04-15 01:32 am (UTC)no subject
Date: 2005-04-15 11:09 pm (UTC)(no subject)
From:no subject
Date: 2005-04-15 09:58 am (UTC)Только я всё равно не понимаю, как можно запихать неправильную дату. Типа, в окошке поста руками исправить?
no subject
Date: 2005-04-15 11:08 pm (UTC)no subject
Date: 2005-04-15 10:18 am (UTC)Кому-то в этот день забраться все-таки удалось :)
"Дорогая редакция, я охуеваю"
Date: 2005-04-15 01:37 pm (UTC)