Глубокая отладка или Минус на минус — это плюс, но только первый раз.

Последнюю неделю провел в глубокой отладке 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  Метки: , , , , , ,   Рубрики: Интернет, Разработка

Написать комментарий