Глубокая отладка или Минус на минус — это плюс, но только первый раз.
Последнюю неделю провел в глубокой отладке Semantic MediaWiki. Очень непросто искать нетривиальную ошибку в незнакомой системе. Обычно бросаю довольно быстро, если не удаётся разобраться сходу. Но тут, что называется «закусил удила». Попробовал несколько новых инструментов, немного разобрался с устройством Semantic MediaWiki и нашел причину странного поведения.
Всё началось с того, что понадобился удобный способ выполнять вычисления на страницах MediaWiki. Установил расширение Scribuntu, немного почитал про Lua и реализовал необходимые функции. Дальше началось странное — функция возвращает число, которое становится значением свойства. Все значения выводятся нормально за исключением '1'
— вместо него появляется ссылка на совершенно непричастную страницу. Чудеса начались.
Задаю вопрос в списке рассылки, параллельно пытаюсь повторить неправильное поведение. В процессе выясняется, что в нашей wiki была страница '1'
, которую затем переименовали в «совершенно непричастную страницу» без перенаправления с '1'
на новую страницу. Из списка рассылки отвечают, что действительно, была такая ошибка и перенаправление в базе данных устанавливалось, даже если эта галочка при переименовании страницы была снята, надо проверить на последней версии.
Устанавливаю MediaWiki последней версии. Пытаюсь повторить странное поведение — сначала всё в порядке, но после нескольких переименований значение свойства таки меняется.
Лезу в исходники и базу данных старой wiki — действительно, в исходниках проблема есть, перенаправления в базе данных установлены. Если бы я не успел попробовать на последней версии — успокоился бы. Но в последней версии-то ошибка исправлена, а с переименованиями всё равно что-то неладно!
После долгих поисков нашлась последовательность действий, приводящая к странному результату:
- cоздать страницу ‘1’
- создать страницу ‘S’ с определением подобъекта, имеющего свойство P=1
- создать страницу ‘Q’ с запросом, выводящим подобъект и его свойство.
- переименовать ‘1’ в ‘One без установки перенаправления
- перейти на страницу ‘Q’
- убедиться, что значение P по-прежнему 1
- заново создать страницу 1 и переименовать её в ‘Two’
- перейти на страницу ‘Q’
- убедиться, что значение P изменилось на Two
Чудеса продолжаются. Точно не знаю, какое поведение правильное, но оба варианта правильными быть не могут, значит ошибка точно есть!
Включаю MediaWiki debug toolbar:
$wgDebugToolbar = true;
И с помощью отладочной печати пытаюсь разобраться, что происходит. Когда надоело повторять одни и те же действия, установил Selenium IDE и записал скрипт — «вкалывают роботы, счастлив человек».
Когда отладочной печати стало не хватать и появились мечты о нормальном отладчике PHP кода на удалённом веб-сервере, разобрался в вопросе, установил xdebug и Eclipse с PHP Development Tools. Наставил себе точек останова и нашел, что после первого переименования страницы значение семантического свойства в таблице smw_di_wikipage
тоже меняется, но по окончании транзакции этих изменений в базе данных нет! Оттрассировал все операции с этой таблицей и понял, что изменения откатываются с помощью задания на обновление информации о странице 'S'
, которое выполняется уже после обработки переименования страницы '1'
, поэтому-то я его в отладчике и не поймал.
А почему же после второго переименования не произошло обновления страницы 'S'
и отката изменений в семантической информации? Оказывается, есть ещё поле smw_proptable_hash
в таблице smw_object_ids
, в котором хранится хэш сериализованного массива свойств. Перед обновлением свойств считается новый хэш и, если он совпадает со старым, изменения не записываются, потому что они уже в базе. В этом случае данные точно не соответствовали тому, что лежало в базе, а хэши были одинаковые.
Вот и первая ошибка: при переименовании страницы таблица со значениями свойств изменяется, а её хэш не обновляется, поэтому и отката изменений не происходит — хэш не изменился, значит и изменений не было.
Но почему эта ошибка проявляется только при втором переименовании? А потому что
Вторая ошибка: при сериализации массива свойств первый раз ключами в нём являются числа, а во втором и последующих — строковое представление этих чисел. Привет поклонникам динамической типизации!
Поэтому хэши как бы одинаковых массивов оказываются разными и изменения в семантическая информации откатываются, создавая иллюзию правильного поведения. А на самом деле просто компенсировались эффекты от двух ошибок. К счастью, только при первом переименовании, потому и удалось выловить их обе. Пойду писать баг-репорты.
18.08.2013
Метки: mediawiki, PHP, scribuntu, selenium, semantic mediawiki, xdebug, отладка Рубрики: Интернет, Разработка
Написать комментарий