Как вылечить базу tdb

MySQL/PostgreSQL/SQLite/Oracle/M$SQL/....

Модератор: terminus

Правила форума
Убедительная просьба юзать теги [code] при оформлении листингов.
Сообщения не оформленные должным образом имеют все шансы быть незамеченными.
als
рядовой
Сообщения: 26
Зарегистрирован: 2015-08-26 8:17:23

Как вылечить базу tdb

Непрочитанное сообщение als » 2016-12-10 7:18:52

Напишу тут, может кому пригодиться.
Работает samba4. Она использует базы формата TDB
И вот, в один прекрасный момент начались ошибки

Код: Выделить всё

>tdbdump fileofbase.ldb
tdb(fileofbase.ldb): FATAL: tdb_rec_read bad magic 0xd9fee666 at offset=518252


В файле fileofbase.ldb по смещению 518252 (замечу, что смещение десятичное) последовательность байтов никак не устраивает tdb движок.
Открыл hex neo.
Там действительно эта последовательность(0xd9fee666). И что она не устраивает, не понимаю.
Пошел в сеть. Материала по теме восстановления tdb баз очень мало.
Нашел ключ у команды tcpdump

Код: Выделить всё

>tdbdump -e fileofbase.ldb > /tmp/keyfrombase.dmp


Ключ -e не описан в мане. Но есть в --help, что на мой взгляд удивительно. Как-то привык манам доверять.
В этом случае программа сохраняет в текстовом виде ключи из базы. Их можно редактировать.
Мне это ничего не дало. Да, есть последовательность, но что не устраивает tdb не ясно.

Решил предпринять следующую стратегию.
Сохраняем ключи из текстового файла обратно в tdb и смотрим на целостность. После какого ключа база помрет, тот и виноват.
Сказано, сделано.
Создал скрипт /tmp/get_key.awk

Код: Выделить всё

        nkey=0;
        stopstr=4000;
}
{
   tag=$1;
   if (tag=="{")
        {
                nkey=nkey+1;
        }
   if (nkey<=stopstr)
        {
                print;
        }
}
END {
    }

В переменной stopstr указано номер ключа, на котором надо остановиться.
Создал скрипт для некоторой автоматизации этого процесса
/tmp/restore.sh

Код: Выделить всё

awk -f /tmp/get_key.awk /tmp/keyfrombase.dmp > /tmp/from_key.dmp
rm /tmp/test.ldb

Второй строкой удаляем файл куда будет грузить.
Грузим через tdbrestore
tdbrestore /tmp/test.ldb < /tmp/from_key.dmp


Если загрузка прошла нормально, то никаких сообщений не будет. Для проверки открываем tdbtool

Код: Выделить всё

tdbtool
> open /tmp/test.ldb
> info
можно вывести ключи
>keys


Если tdbrestore столкнется с ошибкой, он об этом напишет. Если указать tdbrestore в вспомогательном скрипте, то ошибку не увидите. Поэтому пришлось его вынести.
Тогда через значение переменной stopstr подбираем номер ключа и вычисляем какой битый.
После этого удаляем этот ключ в исходном тексте и продолжаем проверять.

Что мне не нравится. Некогда было разбираться, как в awk передавать параметры. Поэтому пришлось делать исправление диапазона ключа вручную.
Ну и подбирать приходится методом деления отрезка пополам, а последние итерации в этом методе идут дольше. Хотя, это все мелочи по сравнению с гибелью базы :-D

Аватара пользователя
Alex Keda
стреляли...
Сообщения: 34924
Зарегистрирован: 2004-10-18 14:25:19
Откуда: Made in USSR
Контактная информация:

Как вылечить базу tdb

Непрочитанное сообщение Alex Keda » 2016-12-10 13:42:54

А не проще их бэкапить, раз в день? ;))
Убей их всех! Бог потом рассортирует...

als
рядовой
Сообщения: 26
Зарегистрирован: 2015-08-26 8:17:23

Как вылечить базу tdb

Непрочитанное сообщение als » 2016-12-11 10:42:43

Alex Keda писал(а):Источник цитаты А не проще их бэкапить, раз в день?

Конечно проще :)
Я даже больше скажу. Давным давно, реклама ИБП APC заканчивалась словами (по памяти) "... вы о нас вспоминаете, когда уже поздно" :)

Но факт остается фактом. Однажды открываешь базу, а там все неправильно. И надо что-то делать...

als
рядовой
Сообщения: 26
Зарегистрирован: 2015-08-26 8:17:23

Как вылечить базу tdb

Непрочитанное сообщение als » 2016-12-11 14:58:28

Начал работать с этой базой, нашлась другая ошибка.
При ldbsearch выдается
search error - Indexed and full searches both failed!

Опять надо пропускать записи через движок и смотреть, на какой помрет.
Так как записей получилось много, решил модернизировать движок. Каждый раз менять номер строки в скрипте не удобно. Гораздо удобнее передавать его параметром.

Скрипт для awk
/tmp/get_key.awk

Код: Выделить всё

 BEGIN{
        nkey=0;
#       stopstr=1200;
}
{
   tag=$1;
   if (tag=="{")
        {
                nkey=nkey+1;
        }
   if (nkey<=stopstr)
        {
                print;
        }
}
END {
    }


Предполагаем, что stopstr будет передаваться параметром.
Скрипт для запуска
/tmp/restore

Код: Выделить всё

echo "no. str: $1"
awk -v stopstr=$1 -f /tmp/get_key.awk /tmp/sam.ldb > /tmp/from_sam.ldb
rm /tmp/test.ldb
tdbrestore /tmp/test.ldb < /tmp/from_sam.ldb
ldbsearch -H /tmp/test.ldb als
#tdbdump /tmp/test.ldb


Вызываем /tmp/restore 600
То есть будет обработано 600 ключей. Они будут переданы в другой файл. Из него восстановлена база, по ней будет проведен поиск.
Если все гуд, то увеличиваем число ключей. Если нет, то можно добиться, что бы битый ключ был последним.
Он будет последним в файле /tmp/from_sam.ldb
Ищем его в файле /tmp/sam.ldb и удаляем его. Запускаем снова /tmp/restore для продолжение процесса.


Вернуться в «Базы данных»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость