E-mail:
Пароль:
Забыли пароль?

Использование ЛИНТЕР в качестве встроенной СУБД

«Технология клиент-сервер», № 4, 2000 г.

Максимов В. Е., Пасечник П. В., Маркин С.П., Ермаков М. В.

С развитием информационных технологий возрастают требования, предъявляемые к прикладным системам, а, следовательно, и к инструментам разработки. Основой любой современной прикладной программы является система управления базами данных (СУБД). Именно от СУБД во многом зависят наиболее важные параметры системы, такие как скорость, надежность, отказоустойчивость и многие другие.

В принципе, основные функции СУБД (хранение данных и доступ к ним) могло бы взять на себя приложение. Однако это, как правило, не выгодно, так как усложняет процесс разработки, отладки, сопровождения и пр. В общем, как ни крути, а без системы управления базами данных современному приложению просто не обойтись.

С другой стороны возникает еще одна проблема, связанная с тем, что конечному пользователю приложения абсолютно неинтересно как и с помощью чего построена система. Следовательно, перед программистом, разрабатывающим приложение, стоит задача «сокрытия» от конечного пользователя присутствия в прикладной системе достаточно больших и сложных подсистем (порой даже более сложных, чем использующие их приложения). Эту проблему можно условно разделить на несколько подзадач.

Во-первых, нежелательно загружать конечного пользователя дополнительными и совершенно ненужными ему знаниями (например, зачем бухгалтеру знать, что существует некая база данных и тем более как она устроена).

Во-вторых, не стоит заставлять его делать действия, не связанные непосредственно с функциями приложения (например, оператору по продаже железнодорожных билетов совершенно не требуется запускать процедуры проверки физических структур базы данных).

В-третьих, хочется снизить до минимума требования к обслуживающему персоналу разрабатываемой прикладной системы. То есть программа должна быть достаточно простой в администрировании, чтобы можно было обойтись как можно меньшим количеством высокооплачиваемых сотрудников, занимающихся поддержкой приложения.

Итак, можно сказать, что одним из основных критериев оценки встраиваемости открытой подсистемы, в частности СУБД, является «видимость» этой подсистемы для пользователя в конечном приложении.

Компания РЕЛЭКС (www.relex.ru), представляющая на рынке реляционную СУБД ЛИНТЕР®, позиционирует ее именно как встраиваемую систему. При создании ЛИНТЕР® одним из основополагающих требований была простота работы с системой. Это относилось как к установке, так и к администрированию. В результате получилась очень компактная и простая в управлении и настройке система, которая очень легко может быть встроена в любую пользовательскую дистрибуцию.

Зачем нужна встроенная СУБД

Вопрос о необходимости встраивания СУБД в прикладную программу достаточно спорен. Безусловно, чтобы встроить СУБД в дистрибутив приложения необходимо потратить определенное количество сил и средств. Естественно, возникает вопрос: а надо ли это? Зачем усложнять приложение? Почему бы просто не поставлять СУБД отдельно от прикладной программы? Чтобы ответить на эти вопросы, рассмотрим необходимость встраивания СУБД в конечное приложение на примере СУБД ЛИНТЕР®.

ЛИНТЕР® распространяется в виде дерева каталогов, содержащих исполняемые файлы системы, управляющие программы на shell-языках, данные системного словаря для создания новой БД, примеры, описания, конфигурационные программы, makefiles и т.д.

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

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

Набор утилит, необходимых приложению

Как уже было сказано, первое, с чем необходимо определиться при встраивании СУБД в свой продукт – это состав необходимых файлов ЛИНТЕР® и их расположение в дереве устанавливаемого продукта. Следует отметить, что так как исполняемые и служебные файлы БД представляют собой нечто целое и отличное от комплекта программ пользователя, то логично сгруппировать их в отдельном каталоге (или каталогах). Там же рекомендуется расположить и управляющие программы на запуск, останов и управление системой.

Все программы ЛИНТЕР® завершаются с кодами завершения, указывающими на причину или состояние завершения работы. Это сильно облегчает написание управляющих программ.

В составе дистрибутива ЛИНТЕР® содержатся следующие необходимые для функционирования СУБД файлы: linter, sql, intsrt, tsp – файлы ядра СУБД. Они должны быть исполняемыми. Собственно это и есть минимальный комплект программ для встраивания в прикладную систему (если отсутствует необходимость в сетевом доступе). Все остальные функции управления базой данных можно реализовать на уровне прикладной программы. Естественно, в случае поставки такого минимального комплекта, необходимо поставлять уже готовую стартовую базу данных.

Запуск ядра осуществляется запуском на исполнение программы linter. Эта программа почти сразу переводит себя в состояние background и продолжает функционировать параллельно. Однако, корректный код завершения этой программы не гарантирует, что СУБД уже запущена.

Для определения состояния программы «запущено» существует вспомогательная утилита chklinter. От результата проверки зависит код завершения программы. У программы есть параметр – timeout – время ожидания запуска. Она будет ждать соответствующее время перед определением состояния «ядро не запущено».

Существует еще несколько полезных программ, которые могут реализовать различные функции управления системой. Первая из них – программа shut. Эта программа инициирует завершение работы СУБД или выдает диагностическое сообщение о причинах невозможности исполнения данной операции. Эта программа посылает команду CALL-интерфейса SHUT ядру.

Таким образом, пользовательская программа в принципе сама может содержать это управляющее воздействие. Следует помнить, что команда shut не завершает работу ядра. Она только проверяет доступ пользователя и планирует завершение работы системы. Собственно завершение произойдет несколько позже.

Программа shut требует имя пользователя и пароль для успешной работы. Соответственно в случае, если эта программа используется в shell-программах, необходимо использовать специальные средства для хранящегося открытым текстом пароля. Ниже будут приведены некоторые рекомендации по обеспечению защищенности этой информации.

В некоторых случаях необходимо точно знать момент действительного завершения работы ядра СУБД. Для этих целей предназначена программа lsyncd. Эта программа не завершается до тех пор, пока не завершится работа ядра СУБД ЛИНТЕР®.

Существует еще несколько полезных утилит, которые могут пригодиться для работы пользовательского приложения. Прежде всего это программа архивации данных lhb, программа тестирования физической целостности базы данных – testdb, программа пакетной загрузки данных (из формата CSV) – loarel, программа исполнения операторов SQL – inl, программа сохранения базы данных в виде текстовых файлов – dbstore, программа конвертации из .dbf формата – dbf2lin. Далее мы рассмотрим эти утилиты подробнее.

Программа архивирования базы данных lhb обладает широчайшими возможностями, она может делать архивные копии как отдельных объектов базы данных, так и всей базы целиком. Причем процесс архивации абсолютно прозрачен для пользователя прикладной системы, то есть не требует остановки работы приложения. Программа lhb может записывать создаваемый архив напрямую на ленту, в файл, на дискеты (с разбивкой по томам), на stdout (это позволяет сделать конвейер).

Программа тестирования базы данных testdb позволяет проверять и в случае физического повреждения структуры базы данных восстанавливать ее. При этом развитый набор опций позволяет управлять сложностью (а, следовательно, и временем) проверки и дополнительными операциями по восстановлению базы данных.

Программа пакетной загрузки данных loarel позволяет загрузить данные в указанную таблицу из текстового файла. Утилита, как правило, применяется при создании первоначальной базы данных, также может использоваться при периодических массовых загрузках пользовательских данных.

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

Программа сохранения БД в виде текстовых файлов dbstore очень удобна для получения в виде обычных текстовых файлов всего содержимого базы данных – от структуры таблиц до текстов триггеров.

Программа конвертации из .dbf формата dbf2lin используется в случаях, если необходимо импортировать данные из .dbf таблиц. С помощью интерфейса командной строки можно одной командой загрузить .dbf файл в базу данных ЛИНТЕР®.

Здесь стоит сказать о еще одной весьма полезной утилите, входящей в состав СУБД ЛИНТЕР® – программе генерации базы данных – gendb. Она позволяет при необходимости создать новую базу данных или изменить параметры уже существующей.

Работа СУБД ЛИНТЕР® в сети

Сетевые компоненты СУБД ЛИНТЕР® представляют собой 2 исполняемых файла – dbs_tcp (драйвер сервера) и dbc_tcp (драйвер клиента). Программа dbc_tcp, кроме того, использует файл настроек серверов nodetab (текстовый файл, содержащий простое описание удаленных серверов).

Одной из отличительных особенностей СУБД ЛИНТЕР® является практически полная прозрачность сетевых интерфейсов. Сетевой драйвер имитирует обычный интерфейс ядра СУБД на локальной машине, при этом, позволяя работать с удаленными ядрами.

Для того чтобы разрешить сетевой доступ к некоторому активному ядру СУБД, необходимо просто запустить драйвер сервера с указанием обслуживаемого сетевого порта. Для работы с удаленной машины необходимо прописать в файле nodetab символическое наименование сервера, с которым собираются работать, его IP адрес (или DNS-имя) и сетевой порт. Затем запустить драйвер сетевого клиента. После этих процедур Вы сможете работать через сеть с удаленным ядром СУБД.

Параметры конфигурации ядра системы.

Теперь обратимся к параметрам конфигурации ядра СУБД, определяющим работу системы – расположение системных файлов БД, размер допустимой памяти для системы, параметры, позволяющие запускать несколько ядер на одной машине.

СУБД ЛИНТЕР® отличается относительно малым количеством настраиваемых параметров. Собственно, практически все они были перечислены выше. Все эти величины берутся или из параметров командной строки или из переменных среды окружения процесса.

Первый параметр – путь к системным файлам базы данных. Этот параметр представляет собой значение переменной среды окружения SY00. Это абсолютный или относительный путь. Если путь относительный, то он задается относительно текущего каталога. Данный параметр может быть задан в shell-файле на запуск ядра СУБД. Например, для bash (и далее в тексте, если не указано обратное, используется именно этот shell-интерпретатор) –

export SY00=/usr/linter/db
linter

В приведенном примере одновременно переменная устанавливается и становится доступной всем запускаемым процессам. При запуске ядра СУБД, оно будет искать базу данных в каталоге /usr/linter/db. По умолчанию (если не задана переменная среды SY00) системные файлы ищутся в текущем каталоге.

Кроме передачи пути к системным файлам через переменную среды, допускается задавать это значение через параметр /base ядра.

Размер выделяемой системе оперативной памяти контролируется двумя параметрами запуска ядра СУБД.

СУБД ЛИНТЕР® спроектирована так, что при работе не требует память, дополнительно к использованной в момент загрузки. Если ядру потребуется дополнительное пространство для хранения промежуточных результатов, то оно автоматически организует свою собственную «виртуальную» память, проецируемую на один из системных файлов базы данных. Подобный механизм работы с памятью обеспечивает прикладной системе гарантию отказоустойчивости ядра СУБД из-за нехватки оперативной памяти.

При запуске ядро выделяет себе часть памяти под внутренние структуры, а часть под высокоэффективный пул страниц базы данных, работающий в режиме write-back. Размер этого пула задается параметром запуска ядра /pool.

linter /pool=1000

Память выделяется страницами по 4096 байт. В приведенном примере выделено 4 мегабайта памяти под пул страниц базы данных. Если этот параметр при запуске не указывается, то пул по умолчанию считается равным 200 страницам.

Еще одним важным параметром, влияющим на объем используемой ядром памяти является пул сортировки. В случае появления запроса на сортировку данных, СУБД сортирует данные не все сразу, а по частям, сообразуясь именно с этим параметром.

linter /spool=500

В этом примере каждый процесс сортировки будет использовать максимум 500*4096 байт памяти. Если этот параметр опускается, то по умолчанию пул сортировки считается равным половине пула страниц базы данных.

Из приведенного описания можно сделать вывод, что чем больше выделено памяти этими параметрами, тем быстрее будет работать система. На самом деле это не совсем так. Дело в том, что с ростом выделенного ядру объема памяти, уменьшается память, доступная для других приложений. Кроме того, растут накладные расходы на обслуживание «виртуальной» памяти большего объема. В любом случае, следует немного поэкспериментировать и найти оптимальный размер памяти необходимый для конкретной задачи.

Ниже приводится пример автоматического определения размера выделяемой памяти в зависимости от количества доступной

# calculate pool size
freemem=`vmstat | awk '{ if(NR == 3) print $5 }'`
# give 1/3 of free memory to linter
poolsize=`exp $freemem / 3 / 4096`
[ $poolsize -lt 2000 ] && poolsize=2000

Последним из описываемых параметров является параметр, позволяющий запустить несколько копий ядра СУБД на одной машине. Ядро СУБД общается с клиентскими задачами при помощи различных средств межзадачного обмена: IPC или Unix Domain Sockets или Posix механизмы обмена. Если Вы не планируете запускать на одной машине одновременно несколько различных баз данных, то можете пропустить дальнейшие рекомендации, касающиеся работы нескольких копий ядра СУБД на одной машине.

Работа нескольких копий ядра СУБД на одной машине.

В любом случае, необходимо однозначно идентифицировать различные одновременно активные базы. Для этой цели служит переменная LINTER_MBX. Значение этой переменной – число в диапазоне от 1024 до 65000.

export LINTER_MBX=12000
linter

По умолчанию значение этого уникального идентификатора – 20561. Доступ к различным ядрам может осуществляться или через сеть, или если у клиентской задачи переменная среды имеет то же значение, что и у соответствующего ядра.

Останов ядра СУБД выполняется, как уже говорилось выше, программой shut. Эта программа имеет несколько параметров очень удобных для использования в пакетном режиме исполнения. Параметр –u задает имя пользователя и пароль, под которыми будет выполнено соединение с базой данных и которые будут проверяться ядром СУБД на доступ. Например, для демонстрационной базы данных будет работать следующий пример:

shut –u SYSTEM/MANAGER

В принципе можно использовать альтернативный метод останова СУБД – посылка ядру (программе linter) сигнала SIGTERM. Только надо помнить, что двойная посылка этого сигнала приведет к немедленной деактивации программы, что при запуске системы приведет к восстановлению базы данных по журналу.

Автоматический запуск и завершение работы СУБД

Рассмотрим два shell-скрипта на запуск и останов СУБД. Эти программы будут потом использованы в примере на автоматический запуск СУБД.

Отдельно сделаем файл настроек, в который внесем все изменяемые параметры запуска СУБД, описанные выше. Этот файл будет располагаться в каталоге /linter/bin и называться constants.

Листинг 1

###############################

#constants
SY00=/linter/db #путь к базе

#путь к исполняемым файлам ЛИНТЕР®

LINTER_BIN=/linter/bin

#Память, используемая системой в 4к страницах

POOL=1000

#Память, используемая каждым из процессов сортировки

SPOOL=500

#Номер«ящика обмена» между задачами
#это«ящик обмена» по умолчанию

LINTER_MBX=20561
export LINTER_MBX SY00

#Порт TCP IP, который слушает сетевой сервер dbs_tcp
#это сетевой порт по умолчанию

PORT=1060

############################

Сделаем сразу еще один файл. Он должен будет содержать имя пользователя и пароль на завершение работы с базой данных. Этот файл должен быть обязательно очень хорошо защищен с точки зрения операционной системы, то есть читать его содержимое должен только владелец.

USER="SYSTEM"
PASSWORD="MANAGER"

Этот файл будет называться private_passwd.

Теперь, используя этот файл, можно сделать простые программы на запуск и останов СУБД.

Далее приводиться текст небольшой программы на запуск ЛИНТЕР®

Листинг 2

################################

#!/bin/sh

#Включаем файл с описанием переменных

LINTER_BIN=/linter/bin
. $LINTER_BIN/constants

#И файл с паролем

. $LINTER_BIN/private_passwd

#NET_MBX=1458 #Любой не используемый в дальнейшем
#export NET_MBX

#Проверяем не запущен ли сервер

$LINTER_BIN/chklinter -u $USER'/'$PASSWORD
if [ $? -ne 0 ]; then
echo "Linter already runnig"
exit 1
fi

#Проверяем наличие каталога блокировочного файла

if [ ! -d $SY00/lock ]; then
mkdir $SY00/lock #создаем каталог
if [ $? -ne 0 ];then
echo "Error create locking directory"
exit 1;
fi
fi

#Проверяем наличие блокировочного файла

if [ -f $SY00/lock/lock ];then
echo "Linter not correct shutdown"
exit 1
fi

#стартуем SQL сервер

$LINTER_BIN/linter /BASE=$SY00 /POOL= $POOL /SPOOL=$SPOOL

#ждем 60 сек запуска ЛИНТЕР®

$LINTER_BIN/chklinter -u $USER'/'$PASSWORD -t 60
if [ $? -eq 0 ]; then
echo "Error Running linter"
exit 1
fi

#Создаем блокировочный файл

touch $SY00/lock/lock
if [ $? -ne 0 ]; then
echo "Error create locking file"
exit 1
fi

#Синхронизируем файловый кеш ОС с диском

sync

#стартуем сетевой сервер

$LINTER_BIN/dbs_tcp /P=$PORT

############################

В этой программе использовано несколько дополнительных программ из дистрибутива СУБД ЛИНТЕР® и несколько технических приемов. Рассмотрим работу этого файла подробнее.

После включения описанных выше файлов – constants и privare_passwd, производится проверка наличия запущенной копии ядра с тем же LINTER_MBX, что и указанный в нашей программе. Это делается с помощью программы chklinter. Аргументы этой программы берутся из private_passwd. Если программа вернула код завершения 0, то ЛИНТЕР® уже запущен. В противном случае – нет.

В данной shell-программе применяется механизм блокировки для предотвращения запуска базы данных в случае некорректного завершения (ниже будет приведена программа, завершающая работу СУБД, она удаляет блокировочный файл).

В конце стартового файла производится запуск сетевого драйвера для обеспечения доступа к данной базе данных по сети.

Теперь рассмотрим примерный файл на останов СУБД.

#############################

#!/bin/sh
# stoplin

#Включение файла с описанием настроек

LINTER_BIN=/linter/bin
. $LINTER_BIN/constants

#Включение файла с описанием имени пользователя и пароля

. $LINTER_BIN/private_passwd

#Проверка работы ЛИНТЕР®а

$LINTER_BIN/chklinter -u $USER'/'$PASSWORD
if [ $? -eq 0 ]; then
echo "Linter not running"
exit 1
fi

#Остановка сервера

echo -e $USER'n'$PASSWORD | $LINTER_BIN/shut

#ожидаем завершения работы

for i in 1 3 5 10 20 30;do
$LINTER_BIN/chklinter -u $USER'/'$PASSWORD
if [ $? -ne 0 ];then
sleep $i
else

#удаление файла блокировки

rm -f $SY00/lock/lock
if [ $? -ne 0 ]; then
echo "Error delete locking file"
exit 1
fi
exit 0
fi
done

echo "Error shutdown linter"
exit 1

###########################

Используя программы для старта ЛИНТЕР®, можно запускать СУБД при старте прикладной системы. Здесь приводится пример для Linux дистрибутивов, совместимых с RedHat. Для этого в каталоге /etc/rc.d/init.d необходимо создать новый файл с названием, к примеру, linter примерно следующего содержания:

Листинг 3

############################

#!/bin/sh
#
# Auto start-stop Linter SQL server

LINTER_BIN=/linter/bin

. /etc/rc.d/init.d/functions

case "$1" in
start)
echo -n "Starting Linter SQL server: "

#Работаем из-под специального пользователя – владельца
#файлов базы данных и всех файлов ЛИНТЕР®.

su oleg -c $LINTER_BIN/startlin

#Обязательно должно совпадать с названием программы

touch /var/lock/subsys/linter.s
;;
stop)
echo -n "Stopping Linter SQL server: "
su oleg -c $LINTER_BIN/stoplin
rm -f /var/lock/subsys/linter.s
;;
restart)
$0 stop
$0 start
;;
*)
echo "Usage: linter {start|stop|restart}"
exit 1
esac

########################

После этого необходимо создать ссылки на этот файл в каталогах /etc/rc.d/rcX.d, где X – уровень загрузки, причем ссылка должна начинаться с буквы K – для останова и с буквы S – для старта, потом должны следовать две цифры, определяющие порядок вызова среди остальных. Для старта целесообразно использовать большие числа (запускать ЛИНТЕР® одним из последних среди прочих доменов), а для останова – маленькие (останавливать одним из первых). За двумя числами должно следовать название программы из каталога /etc/rc.d/init.d. Останов вносится обычно в уровни загрузки 0 и 6 (останов ОС и перезагрузка), а запуск в каталог уровня загрузки 3.

Принципиально важно, чтобы название, которое идет сразу за двумя цифрами, определяющими последовательность, совпадало с именем блокировочного файла в /var/lock/subsys. Если Вы изменили название стартовой программы, то обязательно измените и название блокировочного файла, иначе при попытке завершения работы системы программа останова СУБД не будет вызвана, что может привести к разрушению базы данных.

Неудачное завершение программы startlin или автоматического старта свидетельствует или о уже запущенном ядре СУБД или о некорректном завершении (без использования программы stoplin). В любом случае необходимо выяснить причину неудачного запуска и, возможно, провести мероприятия по тестированию целостности базы с использованием утилиты testdb.

В приведенном примере, в случае неуспешного запуска ЛИНТЕР® (по любым причинам – даже по наличию блокировочного файла), запуск СУБД отменяется. Однако в реальной системе естественно будет необходимо попытаться восстановить базу данных в любых случаях, в которых это возможно.

Восстановление информации при сбоях

В СУБД ЛИНТЕР® имеются встроенные средства для автоматического восстановления данных после некорректного завершения работы системы. В случае, если ядро СУБД запускается на базе данных, которая не была корректно закрыта, то автоматически запускается процедура восстановления по журналу транзакций. Если этой процедуре удастся полностью корректно восстановить базу данных, то ядро СУБД автоматически загрузится, как и в случае обычного запуска.

Если в процессе восстановления по журналу транзакций возникнет ошибка, то необходимо применить процедуру восстановления базы данных с помощью автономной утилиты тестирования физической целостности базы данных. Эта программа частично восстанавливает базу данных, а частично создает .gdb и .sql файлы для программ gendb и inl соответственно.

Для завершения процесса восстановления в случае, если создан файл .gdb необходимо выполнить этот файл программой gendb, затем запустить ядро и выполнить файл .sql и только после этого процедура восстановления будет завершена. В примере, приводимом ниже (файл linrecover), отражен процесс восстановления базы данных для случая, если это необходимо.

Листинг 4

########################

#!/bin/sh
#
# 1. shutdown linter kernel
# 2. run testdb -r
# 3. run gendb
# 4. start linter kernel
# 5. run inl
# 6. shutdown linter kernel
# 7. run testdb

#Включение файла с описанием настроек

LINTER_BIN=/linter/bin
. $LINTER_BIN/constants

#Включение файла с описанием имени пользователя и пароля

. $LINTER_BIN/private_passwd

#NET_MBX=1458
#export NET_MBX

# stop Linter
$LINTER_BIN/stoplin

$LINTER_BIN/testdb -r -f /tmp/testdb.log -i 1 -p $POOL -s /tmp/idx.sql -g /tmp/gen.gdb
retc=$?

[ $retc -eq 0 ] && {
echo -n "Database is OK"
rm -f /tmp/idx.sql /tmp/gen.gdb
exit 0
}

# Run gendb script if it exists

[ -s /tmp/gen.gdb ] && {
msg=`$LINTER_BIN/gendb /tmp/gen.gdb`
#???
[ $? -ne 0 ] && {
echo -n "Error running gendb : $msg"
echo -n "Database recovery failed!"
exit 1
}
}

# Run sql script if exists

[ -s /tmp/idx.sql ] && {
# start linter kernel
$LINTER_BIN/linter >> /tmp/linter.log
# wait for linter startup (max 180 sec)
$LINTER_BIN/chklinter -u $USER'/'$PASSWORD -t 180
[ $? -eq 0 ] && {
echo -n "Can not start Linter kernel!"
exit 1
}
$LINTER_BIN/inl -u $USER'/'$PASSWORD -f /tmp/idx.sql
[ $? -ne 0 ] && {
echo -n "Error running inl"
echo -n "Database recovery failed!"
exit 1
}

$LINTER_BIN/shut -u $USER'/'$PASSWORD
$LINTER_BIN/lsyncd
}
$LINTER_BIN/testdb -r -f /tmp/testdb.log -i 1 -p $POOL -s /tmp/idx.sql -g /tmp/gen.gdb
[ $? -eq 0 ] && {
echo -n "Database successfully recovered."
rm -f /tmp/idx.sql /tmp/gen.gdb
exit 0
}
echo -n "Database NO successfully recovered."
exit 1

##############################

Эту программу можно вызвать в случае, если у нас обнаружен lock файл. Однако на проверку программой testdb может уйти достаточно много времени. Поэтому лучше вызывать этот файл только в случае, если ядро СУБД не запустилось.

Таким образом, с учетом всего вышесказанного файл startlin должен выглядеть следующим образом:

Листинг 5

################################

#!/bin/sh

#Включаем файл с описанием переменных
LINTER_BIN=/linter/bin
. $LINTER_BIN/constants

#И файл с паролем
. $LINTER_BIN/private_passwd

#NET_MBX=1458 #Любой не используемый в дальнейшем
#export NET_MBX

#Проверяем, не запущен ли сервер
$LINTER_BIN/chklinter -u $USER'/'$PASSWORD
if [ $? -ne 0 ]; then
echo "Linter already runnig"
exit 1
fi

#Проверяем наличие каталога блокировочного файла
if [ ! -d $SY00/lock ]; then
mkdir $SY00/lock #создаем каталог
if [ $? -ne 0 ];then
echo "Error create locking directory"
exit 1;
fi
fi

#Проверяем наличие блокировочного файла
if [ -f $SY00/lock/lock ];then
echo "Linter not correct shutdown"
fi

#стартуем SQL сервер
$LINTER_BIN/linter /BASE=$SY00 /POOL=$POOL /SPOOL=$SPOOL
retval=$?

#ждем 3 мин запуска ЛИНТЕР®
[ $retval -eq 0 ] && $LINTER_BIN/chklinter -u $USER'/'$PASSWORD -t 180
if [ $retval -ne 0 -o $? -eq 0 ]; then
$LINTER_BIN/linrecover
if [ $? -ne 0 ]; then
echo "Recover fail"
exit 1
else
$LINTER_BIN/linter /BASE=$SY00 /POOL=$POOL /SPOOL=$SPOOL
fi
fi

#Создаем блокировочный файл
touch $SY00/lock/lock
if [ $? -ne 0 ]; then
echo "Error create locking file"
exit 1
fi

#Синхронизируем файловый кеш ОС с диском
sync

#стартуем сетевой сервер
$LINTER_BIN/dbs_tcp /P=$PORT

#############################

Создание архивной копии базы данных

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

Самая тривиальная процедура – получение простого архива базы данных средствами операционной системы. Эта процедура проста, но требует остановки ядра СУБД на время архивирования данных. В приведенном ниже примере не учитывается возможность расположения базы данных в нескольких каталогах, но модифицировать эту программу будет для этого случая совсем не сложно.

Листинг 6

#################################

#!/bin/sh

DIR_ARC=/mnt/db
DEVICE_ARC=/dev/hdd1
LINTER_BIN=/linter/bin
. $LINTER_BIN/constants

#если запускать из crontab, то эта переменная не установлена

PATH=/bin:/usr/bin:/usr/local/bin:$LINTER_BIN
export PATH

#монтируем устройство архивации
#(можно опустить если подмонтировано постоянно)

mount $DEVICE_ARC
if [ $? -ne 0 ]; then
echo "Error mount $DEVICE_ARC"
exit 1
fi

#проверяем наличие каталога

if [ ! -d $DIR_ARC ]; then
echo "Arcive directory not exist"
exit 1
fi

#останавливаем СУБД

stoplin

#создаем архив

tar cfz $DIR_ARC/db.new $SY00/*
RETVAL=$?

#запускаем СУБД

startlin

#Проверяем окончание архивации

if [ $RETVAL -ne 0 ]; then
echo "Error create arcive"
exit 1
fi

#Переименовываем более старые архивы, храним 5 последних

PREV=""
for i in 4 3 2 1 tgz ; do
if [ "$PREV"AA = AA ]; then
rm -f $DIR_ARC/db.$i
else
if [ -f $DIR_ARC/db.$i ]; then
mv -f $DIR_ARC/db.$i $DIR_ARC/db.$PREV
fi
fi
PREV=$i
done
#переименовываем новый архив

mv -f $DIR_ARC/db.new $DIR_ARC/db.tgz

#отмонтируем устройство архивирования

umount $DEVICE_ARC
if [ $? -ne 0 ]; then
echo "Error umount $DEVICE_ARC"
exit 1
fi

#######################

Далее необходимо настроить системный демон cron на запуск архивации, допустим по средам и воскресеньям в 2 часа ночи. Для этого запускаем crontab –e и добавляем следующую строку:

00 02 * * 00,03 /linter/bin/arclin

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

«Горячее» архивирование

Однако, при наличии развитых встроенных средств резервного копирования СУБД, останов базы для целей архивирования необходимым не является. Если воспользоваться программой lhb, то можно обеспечить «горячее» архивирование – без остановки базы данных. Рассмотрим несколько вариантов архивирования.

Первый вариант – периодическое полное архивирование базы данных. С помощью программы cron будет запускаться программа lhb и делать архивную копию базы данных в файл или не ленту.

Второй вариант – расширение первого – изредка архивируется полная база данных, и, периодически, выполняется инкрементный backup, который создает архив-продолжение полного архива.

Третий вариант – полное (или инкрементное) архивирование в режиме –wait. В этом случае данные, необходимые для архивирования попадают в архив практически одновременно с занесением в базу данных.

В принципе можно отказаться от использования программы cron и работать исключительно с помощью языка скриптов lhb. В этом режиме программа lhb должна будет запускаться в стартовой программе для СУБД.

Для автоматического запуска lhb необходимо будет добавить в конец файла startlin строки на запуск программы, в которых указать bsl-скрипт для исполнения lhb. Например:

#стартуем lhb
$LINTER_BIN/lhb script -ft script.bsl -fl script.log

Периодическое получение полного архива БД

Рассмотрим несколько примеров архивирования. Первый вариант представляет собой периодическое получение полного архива. Создаем shell-программу (arclhb) для запуска программы архивирования и помещаем ее в каталог /linter/bin. В crontab прописываем строку (с помощью crontab –e):

15 05 * * * /linter/bin/arclhb

Ниже приведен текст программы arclhb

Листинг 7

############################

#!/bin/sh

DIR_ARC=/mnt/db
DEVICE_ARC=/dev/hdd1
LINTER_BIN=/linter/bin
. $LINTER_BIN/constants
. $LINTER_BIN/private_passwd

#если запускать из crontab эта переменная не установлена
PATH=/bin:/usr/bin:/usr/local/bin:$LINTER_BIN
export PATH

#монтируем устройство архивации
#(можно опустить если подмонтировано постоянно)

mount $DEVICE_ARC
if [ $? -ne 0 ]; then
echo "Error mount $DEVICE_ARC"
exit 1
fi

#проверяем наличие каталога
if [ ! -d $DIR_ARC ]; then
echo "Arcive directory not exist"
exit 1
fi

#создаем архив
lhb s -u $USER'/'$PASSWORD -f $DIR_ARC/db.new

#Проверяем окончание архивации
if [ $? -ne 0 ]; then
echo "Error create arcive"
exit 1
fi


#Переименовываем более старые архивы, храним 5 последних
PREV=""
for i in 4 3 2 1 lhb ; do
if [ "$PREV"AA = AA ]; then
rm -f $DIR_ARC/db.$i
else
if [ -f $DIR_ARC/db.$i ]; then
mv -f $DIR_ARC/db.$i $DIR_ARC/db.$PREV
fi
fi
PREV=$i
done

#переименовываем новый архив
mv -f $DIR_ARC/db.new $DIR_ARC/db.lhb

#отмонтируем устройство архивирования
umount $DEVICE_ARC
if [ $? -ne 0 ]; then
echo "Error umount $DEVICE_ARC"
exit 1
fi

###########################

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

Инкрементное архивирование

Теперь рассмотрим вариант реализации процедуры инкрементного архивирования. В приведенном ниже примере полный архив базы данных создается 2 раза в неделю, а инкрементирование архива происходит 2 раза в день.

Для реализации этого метода написаны две shell-программы – srclhb.startinc и arclhb.inc. Первая из них отвечает за полное архивирование, а вторая за инкрементные части. В crontab необходимо добавить 2 строки

30 02,13 * * * /linter/bin/arclhb.inc
50 00 * * 0,4 /linetr/bin/arclhb.startinc

Далее приводятся тексты примеров архивирования.

Листинг 8
Файл arclhb.startinc

#############################

#!/bin/sh

DIR_ARC=/mnt/db
DEVICE_ARC=/dev/hdd1
LINTER_BIN=/linter/bin
. $LINTER_BIN/constants
. $LINTER_BIN/private_passwd

#если запускать из crontab, эта переменная не установлена
PATH=/bin:/usr/bin:/usr/local/bin:$LINTER_BIN
export PATH

#монтируем устройство архивации
#(можно опустить, если подмонтировано постоянно)
mount $DEVICE_ARC
if [ $? -ne 0 ]; then
echo "Error mount $DEVICE_ARC"
exit 1
fi

#проверяем наличие каталога
if [ ! -d $DIR_ARC ]; then
echo "Arcive directory not exist"
exit 1
fi

#создаем архив
lhb s -u $USER'/'$PASSWORD -f $DIR_ARC/db.new -startinc

#Проверяем окончание архивации
if [ $? -ne 0 ]; then
echo "Error create arcive"
exit 1
fi


#Переименовываем более старые архивы, храним 5 последних
PREV=""
for i in 4 3 2 1 lhb ; do
if [ "$PREV"AA = AA ]; then
rm -f $DIR_ARC/db.$i
else
if [ -f $DIR_ARC/db.$i ]; then
mv -f $DIR_ARC/db.$i $DIR_ARC/db.$PREV
fi
fi
PREV=$i
done

#переименовываем новый архив
mv -f $DIR_ARC/db.new $DIR_ARC/db.lhb

#отмонтируем устройство архивирования
umount $DEVICE_ARC
if [ $? -ne 0 ]; then
echo "Error umount $DEVICE_ARC"
exit 1
fi

##############################

Листинг 9
Файл arclhb.inc

##############################

#!/bin/sh

DIR_ARC=~/mnt/db
DEVICE_ARC=/dev/hdd1
LINTER_BIN=~/linter/bin
. $LINTER_BIN/constants
. $LINTER_BIN/private_passwd

#если запускать из crontab эта переменная не установлена

PATH=/bin:/usr/bin:/usr/local/bin:$LINTER_BIN
export PATH

#монтируем устройство архивации
#(можно опустить если подмонтировано постоянно)

mount $DEVICE_ARC
if [ $? -ne 0 ]; then
echo "Error mount $DEVICE_ARC"
exit 1
fi

#проверяем наличие каталога

if [ ! -d $DIR_ARC ]; then
echo "Arcive directory not exist"
exit 1
fi

#создаем архив

lhb s -u $USER'/'$PASSWORD -f $DIR_ARC/db.lhb -inc

#Проверяем окончание архивации
if [ $? -ne 0 ]; then
echo "Error create arcive"
exit 1
fi

#отмонтируем устройство архивирования
umount $DEVICE_ARC
if [ $? -ne 0 ]; then
echo "Error umount $DEVICE_ARC"
exit 1
fi

###########################

Использование встроенного языка сценариев BSL

Все предыдущие варианты использовали программу crontab в качестве программы, которая запускает задачи по расписанию. Вместо этого можно использовать встроенный язык сценариев bsl программы lhb для обеспечения тех же самых возможностей работы по расписанию.

Для запуска на исполнение bsl-скрипта необходимо из стартового файла (например linstart) запустить программу lhb с параметром script.

Ниже приводится программа на языке bsl которая сохраняет базу данных при запуске и затем каждый день в 02:00. При этом предыдущие файлы переименовываются соответственно в arc1.lhb...arc4.lhb. Свежий файл имеет имя db.lhb. Если при запуске lhb задать ключ -fl FILE.LOG, то история сохранения будет накапливаться в файле FILE.LOG

Листинг 10

###############################
/*--------------------------------------------------------*/
Variables:
USERNAME ="SYSTEM"; /* user name */
USERPASSWORD ="MANAGER"; /* user password */
ARCDEVICE ="./"; /* for new files */
ARCFNAME =""; /* new name for old file */
CHKSUF = ".lhb"; /* suffix for checkpoint file */
NUMFILE = 1;
/*--------------------------------------------------------*/

Rights:
Everyday ( time = '02:00' )
{
NUMFILE = 1;
while ( NUMFILE < 5 )
{
if ( exist ( ARCDEVICE+"arc" + TOSTR(NUMFILE) + ".lhb" ) )
{
if ( NUMFILE == 1 )
delete ( ARCDEVICE+"arc" + TOSTR(NUMFILE) + ".lhb" );
else
rename ( ARCDEVICE+"arc" + TOSTR(NUMFILE) + ".lhb" ,
ARCDEVICE+"arc" + TOSTR(NUMFILE-1) + ".lhb" );
} /* if */
NUMFILE = NUMFILE + 1;
} /* while */
rename ( ARCDEVICE+"db.lhb" , ARCDEVICE+"arc" + TOSTR(NUMFILE-1) + ".lhb" );
backup ( "s -u "+USERNAME+"/"+USERPASSWORD+" -f "+ARCDEVICE+"db.lhb"+" -qc DF" );
logprint ( CTIMESTAMP() + " --- File " + "db" + CHKSUF +
" created.n" );
Exception: /* for everyday */
print ( "Error=" + TOSTR(CERROR) +
" , LinError=" + TOSTR(LINERROR) +
" , SysError=" + TOSTR(SYSERROR) );
logprint ( CTIMESTAMP() + " --- Error=" + TOSTR(CERROR) +
" , LinError=" + TOSTR(LINERROR) +
" , SysError=" + TOSTR(SYSERROR) );
stop;
} /* Everyday */

/*--------------------------------------------------------*/

Special:
before /* just after the start */
{
NUMFILE = 1;
while ( NUMFILE < 5 )
{
if ( exist ( ARCDEVICE+"arc" + TOSTR(NUMFILE) + ".lhb" ) )
{
if ( NUMFILE == 1 )
delete ( ARCDEVICE+"arc" + TOSTR(NUMFILE) + ".lhb" );
else
rename ( ARCDEVICE+"arc" + TOSTR(NUMFILE) + ".lhb" ,
ARCDEVICE+"arc" + TOSTR(NUMFILE-1) + ".lhb" );
} /* if */
NUMFILE = NUMFILE + 1;
} /* while */
rename ( ARCDEVICE+"db.lhb" , ARCDEVICE+"arc" + TOSTR(NUMFILE-1) + ".lhb" );
backup ( "s -u "+USERNAME+"/"+USERPASSWORD+" -f " +ARCDEVICE+"db.lhb"+" -qc DF" );
logprint ( CTIMESTAMP() + " --- File " + "db" + CHKSUF +
" created.n" );
}
after /* after stop or Ctrl-C */
{
print ( " --- Stop backup system" );
if ( CERROR != 0 )
logprint ( CTIMESTAMP() + " --- Error present: " + TOSTR(CERROR) );
logprint ( CTIMESTAMP() + " --- Stop backup systemn" );
}
iferr /* global */
{
print ( "Error=" + TOSTR(CERROR) +
" , LinError=" + TOSTR(LINERROR) +
" , SysError=" + TOSTR(SYSERROR) );
logprint ( CTIMESTAMP() + " --- Error=" + TOSTR(CERROR) +
" , LinError=" + TOSTR(LINERROR) +
" , SysError=" + TOSTR(SYSERROR) );
stop;
}

/*--------------------------------------------------------*/

############################

Следующий пример включает в себя более сложную схему – с инкрементированием. Программа сохраняет базу данных при запуске, и затем каждый день в 02:00 добавляет накопленные изменения. Если при запуске lhb задать ключ -fl FILE.LOG, то история сохранения будет накапливаться в файле FILE.LOG

Листинг 11

###############################
/*--------------------------------------------------------*/
Variables:
USERNAME ="SYSTEM"; /* user name */
USERPASSWORD ="MANAGER"; /* user password */
ARCDEVICE ="./"; /* for new files */
ARCFNAME =""; /* new name for old file */
CHKSUF = ".lhb"; /* suffix for checkpoint file */

/*--------------------------------------------------------*/

Rights:
Everyday ( time = '15:35' )
{
backup ( "s -u "+USERNAME+"/"+USERPASSWORD+" -f "+ARCDEVICE+
"db.lhb"+" -qc DF -inc" );
logprint ( CTIMESTAMP() + " --- File " + "db" + CHKSUF +
" updated.n" );
Exception: /* for everyday */
print ( "Error=" + TOSTR(CERROR) +
" , LinError=" + TOSTR(LINERROR) +
" , SysError=" + TOSTR(SYSERROR) );
logprint ( CTIMESTAMP() + " --- Error=" + TOSTR(CERROR) +
" , LinError=" + TOSTR(LINERROR) +
" , SysError=" + TOSTR(SYSERROR) );
stop;
} /* Everyday */

/*--------------------------------------------------------*/

Special:
before /* just after the start */
{
backup ( "s -u "+USERNAME+"/"+USERPASSWORD
+" -f "+ARCDEVICE+"db.lhb"+
" -qc DF -startinc" );
logprint ( CTIMESTAMP() + " --- File " + "db" + CHKSUF +
" created.n" );
}
after /* after stop or Ctrl-C */
{
print ( " --- Stop backup system" );
if ( CERROR != 0 )
logprint ( CTIMESTAMP() + " --- Error present: "
+ TOSTR(CERROR) );
logprint ( CTIMESTAMP() + " --- Stop backup systemn" );
}
iferr /* global */
{
print ( "Error=" + TOSTR(CERROR) +
" , LinError=" + TOSTR(LINERROR) +
" , SysError=" + TOSTR(SYSERROR) );
logprint ( CTIMESTAMP() + " --- Error=" + TOSTR(CERROR) +
" , LinError=" + TOSTR(LINERROR) +
" , SysError=" + TOSTR(SYSERROR) );
stop;
}

/*--------------------------------------------------------*/

###############################

Более полное описание языка bsl можно найти в документации на СУБД ЛИНТЕР®, а описание программы cron и файла crontab в документации на операционную систему.

Заключение

Итак, мы рассмотрели некоторые возможности и методы встраивания СУБД в прикладную пользовательскую систему, привели примеры автоматических процедур запуска, останова, тестирования и архивирования базы данных.

Из всего вышесказанного можно определить основные требования, предъявляемые к встраиваемым СУБД: простота инсталляции, конфигурирования, администрирования и, конечно, прозрачность для пользователя.

Конечно, затронутый нами вопрос слишком широк и многогранен для того, чтобы уместиться в рамки одной журнальной статьи, поэтому мы постарались здесь рассмотреть только основные аспекты проблемы. Если у Вас, уважаемые читатели, возникнут вопросы, замечания или предложения, касающиеся тематики настоящей статьи, мы с удовольствием обсудим интересующие Вас вопросы. Вы можете связаться с нами через редакцию журнала, или напрямую по электронной почте.



Возврат к списку

ѕрокрутить вверх