Обновление на новую версию Leader Task при abnormal program termination (восстановление базы LT)
By: Date: 27.12.2011 Categories: !RUS,LeaderTask,SOFTWARE
ENG: Upgrading to a new version of the Leader Task in abnormal program termination (database recovery LT)

На примере обновления с версии 7.3.3.1 на 7.3.7.6

Все используемые в статье утилиты описаны здесь — Шпаргалка по sqlite.

ВНИМАНИЕ:

Перед началом каких-либо действий нужно сделать ПОЛНУЮ копию рабочей папки LT (на всякий случай). Например для меня это копия всей папки U:\ProgramFiles\LeaderTask.

Все манипуляции нужно производить на копии БД. Для этого нужно скопировать файл БД, у меня он находиться в U:\ProgramFiles\LeaderTask\Data\ltmain.dbase в какую-нибудь другую папку, например m:\TEMP.

Всё что вы делаете – вы делаете на свой страх и риск, я не несу никакой ответственности за ваши действия и претензии не принимаются.

Преамбула (или Кто виноват?)

При попытке обновиться через автообновление до новой версии Leader Task (LT) падал с ошибкой “Runtime Error! abnormal program termination”.

SNAGHTMLe5a306

Тогда попытался сначала установить новую версию LT с чистой базой, а затем восстановить в неё резервную копию БД. Но LT начинал делать “Конвертация базы данных…” и зависал в бесконечность (оставил его на выходные, процесс так и не закончился, хотя в мониторе ресурсов особой активности LT не наблюдалось) – пришлось снять процесс.

SNAGHTMLe92aac

Тогда я решил проверить, а вообще могу я восстановиться в старой версии LT из резервной копии? Оказалось что нет. При попытке восстановиться программа выдавала ошибку “Access to an unnamed file was denied”.

МЫСЛИ ВСЛУХ: Как потом оказалось эта ошибка нестабильна, т.к. при еще одной попытке восстановиться, БД всё-таки восстановилась. И кстати, на форуме LT в темах с проблемами обновления, были похожие ситуации, когда обновление падал, падало, а на десятый раз всё-таки проходило. Т.е. наверное можно тупо попробовать обновиться раз десять подряд – может проскочит. Хотя если причина была в битой БД, то хотя она и проскочит, но так и останется битой.

После всех этих попыток, возникла мысль: “А не в базе ли дело?”. Решил выполнить vacuum. Эта такая специальная команда sql sqlite, типа дефрагментации БД, которая как бы сжимает БД, убирая пустые промежутки оставшиеся после операций DML (insert, update, delete).

m:\TEMP>sqlite3.exe ltmain.dbase
SQLite version 3.7.9 2011-11-01 00:52:41
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> vacuum;
Error: database disk image is malformed
sqlite>

Для проверки БД можно еще выполнить PRAGMA integrity_check. (вывод урезан)

m:\TEMP>sqlite3.exe ltmain.dbase
SQLite version 3.7.9 2011-11-01 00:52:41
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> PRAGMA integrity_check;
*** in database main ***
On tree page 126 cell 1: 198 of 1096 pages missing from overflow list starting at 127
Page 1025 is never used
Page 1026 is never used
Page 1027 is never used
Page 1028 is never used
Page 1029 is never used

sqlite>

Получается что БД битая. Кстати, если проверить целостность файла, например chkdsk то всё будет ОК. Т.е. это какая-то логическая ошибка в самом файле БД.

C:\Windows\System32>chkdsk u: /f /r
Тип файловой системы: FAT32.
Невозможно выполнить команду Chkdsk на этом томе, т.к. том используется другим
процессом. Чтобы запустить Chkdsk, вначале следует отключить этот том.
ВCE ОТКРЫТЫЕ ДЕСКРИПТОРЫ ТОМА БУДУТ ДАЛЕЕ НЕВЕРНЫ.
Подтверждаете отключение тома? [Y(да)/N(нет)] y
Том отключен.  ВCE ОТКРЫТЫЕ ДЕСКРИПТОРЫ ТОМА СТАЛИ НЕВЕРНЫ.
Том ZIPPER создан 28.04.2011 7:12
Серийный номер тома: 77C3-EE93
Проверка файлов и папок...
Проверка файлов и папок завершена.
Проверка свободного места на диске...
Проверка свободного места на диске завершена.
Windows проверила файловую систему. Ошибок не обнаружено.
15 622 176 КБ всего на диске.
832 КБ в 17 скрытых файлах.
16 192 КБ в 506 папках.
9 261 888 КБ в 3 842 файлах.
6 343 232 КБ доступно.
32 768 байт в каждом кластере.
Всего кластеров на диске:          488 193.
198 226 кластеров на диске.
C:\Windows\System32>

МЫСЛИ ВСЛУХ: Вообще говоря, в FAQ sqllite написано (What is an SQLITE_CORRUPT error? What does it mean for the database to be «malformed»? Why am I getting this error?) что сам sqlite чрезвычайно редко может повредить БД в случае своих багов. Но вот внешние программы, баги ОС или железа могут это сделать намного чаще.

короче

Что делать?

Что делать? что делать? конечно же нужно просто восстановить БД из резервной копии и все дела.

Но, оказывается что все резервные копии имеют такую же проблему – они все битые. Т.к. LT скорее всего просто делает физическую копию файла БД, то логическая ошибка в файле БД также попадает в копию.

Для таких случаев может пригодиться команда .dump (sqlite3.exe). Эта команда выгружает БД или отдельные таблицы в виде sql-файла. Который потом можно выполнить на другой БД. Т.е. план такой:

— Сделать dump битой БД

— Создать новую, чистую БД

— Залить дамп в новую БД

Делаю дамп. Выполняю

m:\TEMP>sqlite3 ltmain.dbase .dump > M:\TEMP\aaa.sql

в результате получаю sql-файл M:\TEMP\aaa.sql примерно такого содержания

image

Но, ВНИМАНИЕ, оказывается .dump – это тупая команда, потому что, если она не может что-то прочитать из БД, она просто отмечает это комментарием в sql-файле, при этом на экран ничего не выводиться!

Если поискать слово malformed по тексту файла M:\TEMP\aaa.sql то можно увидеть комментарии типа

/**** ERROR: (11) database disk image is malformed *****/

Это говорит о том что dump пытался прочитать данные из файла БД и не смог, т.е. кусок данных пропал, причем безвозвратно. Проверил самую последнюю имеющуюся резервную копию БД там уже присутствует ошибка, т.е. в моем случае это действительно безвозвратная потеря с которой придется смириться.

Просмотрел файл M:\TEMP\aaa.sql – оказалось что повреждена только таблица contactnotes. Описания схемы БД нет, но логически понятно что это таблица содержит примечания к контактам. Т.е. какие-то контакты останутся без примечаний, какие и сколько их — не понятно. Но для меня это не столько критично.

Создаю новую БД, делается это очень просто, и сразу заливаю в неё дамп. Дамп заливается командой .read <file>, но предварительно нужно внести корректировки в файл M:\TEMP\aaa.sql. В самом его начале есть команда BEGIN TRANSACTION; её нужно убрать, т.к. с ней .read просто не отрабатывает ничего не выводя на экран, а если попробовать сделать импорт с помощью SQLite Manager то получим ошибку:

SQLiteManagen
BEGIN TRANSACTION; [ cannot start a transaction within a transaction ]
Exception Name: NS_ERROR_FAILURE
Exception Message: Component returned failure code: 0x80004005 (NS_ERROR_FAILURE)
[ mozIStorageStatement.execute]

image

Короче, команду убираем.

Кстати, в самом конце есть команда rollback; – она ни на что не влияет, но я её тоже убрал на всякий случай. Commit делается автоматом.

Я написал батник start.cmd для запуска процесса, просто для того чтобы иметь возможность замерить время выполнения. Для батника нужен вспомогательный файл command.txt в котором содержаться команды которые подаются на вход  sqlite3.exe. Но все действия можно выполнять и вручную. А вот и сами файлы.

PRAGMA page_size=32768; – Задает размер страницы БД. Я проверил, у меня именно с таким размером LT создает БД. Скорее всего зависит от ОС (т.е на другом компе может быть другое значение). Думаю если создавать БД с другим размером страницы, ничего страшного не будет. Это только может повлиять на производительность, но чтобы понять как — нужно провести дополнительное исследование. Если эту команду опустить, то sqlite3.exe создает БД с размером страницы 1024 байт. Чем больше размер страницы, тем больше получается файл БД, но при этом заливка дампа проходит нееемного быстрее. У меня исходный битый файл БД был 7,5 Мб. При page_size=1024 получился файл 3,6 Мб и время заливки 2 мин 19 сек. При page_size=32768 получился файл 4,6 Мб и время заливки 2 мин 07 сек.

PRAGMA journal_mode=OFF; – Отключает журналирование. При этом перестает работать rollback, но для заливки данных это не важно, т.к. если что вдруг пойдет не так, то можно просто повторить процесс заливки с самого начала, т.е. создав чистую БД. Зато время заливки с отключенным журналирование уменьшается в два, три раза. Для меня, с журналированием время заливки 6 минут, без журналирования 2 мин 19 сек. Плагин SQLite Manager для Firefox умеет делать импорт еще быстрее, поэтому если БД большая – имеет смысл использовать его.

start.cmd

echo %time%
sqlite3.exe ltmain777.dbase < command.txt
echo %time%
pause

command.txt

PRAGMA page_size=32768;
PRAGMA journal_mode=OFF;
.read aaa.sql
.exit

На всякий случай, нужно проверить восстановленую БД

m:\TEMP>sqlite3.exe ltmain777.dbase
SQLite version 3.7.9 2011-11-01 00:52:41
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> PRAGMA integrity_check;
ok
sqlite> .exit
m:\TEMP>

Ну вот и все. Осталось переименовать восстановленую БД M:\TEMP\ltmain777.dbase в M:\TEMP\ltmain.dbase и скопировать файл в рабочую папку программы LT (u:\ProgramFiles\LeaderTask\Data) вместо битой БД.

Теперь можно работать и обновляться.

Заключение (советы или выводы):

1) Если LT падает с abnormal program termination – проверь БД на целостность.

2) Сейчас LT (не знаю с какой версии) пишет лог-файл (U:\ProgramFiles\LeaderTask\Logs) с помощью которого можно попытаться диагностировать проблему.

===============================================================

P.S.

Т.к. я с начала времен обновлялся всё время “поверх” и ставил всяческие эксперименты над LT – папка программы немного замусорилась. Поэтому я решил совместить обновление на новую версию с глобальной чисткой.

Для этого я выполнил сохранение БД в старой версии LT (7.3.3.1) с помощью меню ФайлСохранить. Переименовал старую папку с LT. Установил LT новой версии (7.3.7.6) начисто. Запустил LT. И с помощью меню ФайлОткрыть, восстановил БД из резервной копии. При этом, LT призвала конвертацию БД в новую версию (в битой БД на этом шаге LT падала).

Файл настроек, я решил не переносить из старой версии. А просто прошелся еще раз и установил все настройки заново.

Всё.
Запись Обновление на новую версию Leader Task при abnormal program termination (восстановление базы LT) впервые появилась Dmitry Bobrovsky Blog

— Author: Dmitry Bobrovsky Google