- PVSM.RU - https://www.pvsm.ru -

Приведенный ниже материал может быть полезен начинающим администраторам баз данных, которые осознали важность создания системы резервного копирования, но пока не разжились собственными скриптами или утилитами. Ниже я приведу скрипт в виде командного bat-файла, используемого в нашей организации для автоматизации снятия бекапов с баз данных Firebird, разберу его ключевые фрагменты и приведу примеры использования. Он также подойдет для баз данных Interbase или Yaffil, но полагаю, что с минимальной переделкой вызова утилиты-бекапера, его можно адаптировать практически для любой СУБД.
Прежде всего, я привожу пару ссылок, по которым можно и нужно ознакомиться с теорией вопроса:
firebirdsql.org: Firebird's gbak Backup and Restore tool (англ.) [1]
ibase.ru: Утилита GBAK, Firebird и InterBase [2]
Немного о терминах:
Итак, какие мероприятия составляют процесс резервного копирования БД, если подойти к вопросу комплексно, а не ограничиваться лишь запуском gbak.exe с нужными ключами? Я бы выделил следующие основные:
Наш скрипт конечно же умеет делать все перечисленное, но также может и кое-что еще:
Вступление затянулось; под спойлером привожу полный исходник скрипта.
@CLS
@ECHO OFF
ECHO #=============================================================================#
ECHO # #
ECHO # Firebird/InterBase database backup, test restore, zip and rotate script #
ECHO # Ver 3.2.7 (11.11.2012) #
ECHO # #
ECHO # Author: arni (email:arnisoft at rambler dot ru) #
ECHO # #
ECHO # Format: #
ECHO # FB_BACKUP [host[/port]:][path]db_file_or_alias result_dir #
ECHO # [/count:backup_count] [/space:backup_space_limit] [/gc] #
ECHO # [/restore] [/compress:level] [/password:SYSDBA_password] #
ECHO # [other_files_to_compress [...]] #
ECHO # #
ECHO # Input params: #
ECHO # [host[/port]:][path] : local or network, full-specified path or alias #
ECHO # db_file_or_alias to the source database #
ECHO # result_dir : result backup collecting directory #
ECHO # /count:backup_count : backup file number to keep (30 by default) #
ECHO # /space:backup_space_limit : total backup size in bytes (not use by default) #
ECHO # you can use suffixes K, M or G. #
ECHO # /gc : need to collect garbage in DB (OFF by default) #
ECHO # /restore : need to do test restore (OFF by default) #
ECHO # /compress:level : compress ratio for RAR (2 by default): #
ECHO # 0: not compress, 1: fastest, 2: fast, #
ECHO # 3: normal, 4: good, 5: best #
ECHO # /password:SYSDBA_password : optional SYSDBA password for remote server #
ECHO # (by default uses one from the source code) #
ECHO # other_files_to_compress : list of files that must be add to archive #
ECHO # #
ECHO #=============================================================================#
REM ==== Server ====================================================================
SET gbak="C:ProgramsFB25bingbak.exe"
SET ISC_USER=SYSDBA
SET ISC_PASSWORD_LOCAL=masterkey
SET ISC_PASSWORD_REMOTE=
REM ==== Backup/restore preferences ================================================
SET temp_backup_dir=%TEMP%
SET temp_restore_dir=%TEMP%
SET backup_count=30
SET backup_space_limit=0
SET backup_ext=fbk
SET garbage_collection=-g
SET restore=0
REM ==== RAR =======================================================================
SET rar="C:Program FilesWinRARrar.exe"
SET rar_options=a -y -ep -idcd
SET rar_password=
SET rar_compress_ratio=2
REM ==== Mailer (see "Blat" at http://sourceforge.net/projects/blat) ===============
SET blat="C:ProgramsBlat307blat.exe"
SET smtp_server=smtp.mailserver.ru
SET mail_sender=foo@mailserver.ru
SET mail_login=foo
SET mail_password=1234
SET mail_receiver=
SET mail_subject=Fail while database b/r
REM ==== Other preferences =========================================================
SET include_logs_to_archive=1
SET net_send_receiver=
SET error_log=
REM ==== Define database location ==================================================
SET full_db_specification=%~1
ECHO full_db_specification = %full_db_specification%
REM Devide DB spec to network and local parts
FOR /f "DELIMS=: TOKENS=1*" %%i IN ("%full_db_specification%") DO (
SET network=%%i
SET local=%%j
)
REM Test if spec. is alias with no network part
IF "%local%" == "" (
SET network=
SET local=%full_db_specification%
)
REM Test if spec. is full specified file with no network part
FOR /f "DELIMS= TOKENS=*" %%i IN ("%local%") DO IF "%local%" == "%%i" (
SET network=
SET local=%full_db_specification%
)
ECHO network_specification = %network%
IF "%network%" GTR "" (
REM Extract port from network spec (if exists)
FOR /f "DELIMS=/ TOKENS=1*" %%i IN ("%network%") DO (
SET host=%%i
SET port=%%j
IF "%%j" GTR "" (
ECHO network_host = %%i
ECHO network_port = %%j
)
)
)
REM Test if DB is local or remote
SET service_mgr_host=localhost
SET is_local_db=1
IF "%network%" GTR "" IF "%host%" NEQ "127.0.0.1" IF /i "%host%" NEQ "localhost" SET is_local_db=0
IF %is_local_db% == 1 IF "%network%" GTR "" SET service_mgr_host=%network%
ECHO local_db_specification = %local%
IF "%local%" == "" (
SET fail=Param #1 {DB specification} missing!
GOTO finish
)
REM Extract file (or alias) from local part of spec.
FOR /f %%i IN ("%local%") DO (
SET local_path=%%~dpi
SET local_file_or_alias=%%~nxi
)
IF "%local%" NEQ "%local_file_or_alias%" (
ECHO local_path = %local_path%
REM Check DB file exists for local, not aliased specification
IF %is_local_db% == 1 IF NOT EXIST "%local%" (
SET fail=Local DB file %local% not found!
GOTO finish
)
)
ECHO local_db_file_or_alias = %local_file_or_alias%
REM ==== Define result directory ===================================================
SET result_dir=%~2
ECHO result_dir = %result_dir%
IF "%result_dir%" == "" (
SET fail=Param #2 {backup collecting directory} missing!
GOTO finish
)
REM Cut the result dir if it is in path-style (ends with separator)
IF "%result_dir:~-1%" == "" SET result_dir=%result_dir:~0,-1%
REM Try to create the result directory if it is not exists yet
IF NOT EXIST "%result_dir%" (
MD "%result_dir%"
IF NOT EXIST "%result_dir%" (
SET fail=Cannot create backup collecting directory!
GOTO finish
)
)
REM Test if it is local or remote directory (elementary, may get wrong answer)
SET is_local_result_dir=1
IF "%result_dir:~0,2%" == "\" SET is_local_result_dir=0
REM ==== Use other command line options ============================================
:loop_options
SHIFT
SET next_param=%~2
IF "%next_param%" == "" GOTO print_options
SET prefix=%next_param:~0,1%
IF "%prefix%" == "/" SET next_param=%next_param:~1%
IF "%prefix%" == "-" SET next_param=%next_param:~1%
IF "%next_param%" GTR "" (
FOR /f "DELIMS=: TOKENS=1*" %%i IN ("%next_param%") DO (
SET value=%%j
IF /i "%%i" == "count" IF "%%j" GTR "" GOTO count
IF /i "%%i" == "space" IF "%%j" GTR "" GOTO space
IF /i "%%i" == "gc" GOTO gc
IF /i "%%i" == "restore" GOTO restore
IF /i "%%i" == "compress" IF "%%j" GTR "" GOTO compress
IF /i "%%i" == "password" IF "%%j" GTR "" GOTO password
IF EXIST "%next_param%" GOTO add_file_to_compress
IF "%prefix%" GTR "/" GOTO add_file_to_compress
ECHO unknown param found: %next_param%
GOTO loop_options
)
) ELSE (
ECHO empty param found!
GOTO loop_options
)
REM ==== Define file count in the result dir =======================================
:count
SET /a backup_count=0+%value%
GOTO loop_options
REM ==== Define allowed backup space limit =========================================
:space
SET suffix=%value:~-1%
IF "%suffix%" GTR "9" (
SET value=%value:~0,-1%
IF /i "%suffix%" == "K" (
SET file_size_shift=0
SET /a value*=1000
)
IF /i "%suffix%" == "M" (
SET file_size_shift=3
SET /a value*=1000
)
IF /i "%suffix%" == "G" (
SET file_size_shift=6
SET /a value*=1000
)
)
SET /a backup_space_limit=0+%value%
GOTO loop_options
REM ==== Define need of garbage collection =========================================
:gc
SET garbage_collection=
IF "%value%" == "0" SET garbage_collection=-g
IF /i "%value%" == "N" SET garbage_collection=-g
IF /i "%value%" == "NO" SET garbage_collection=-g
IF /i "%value%" == "OFF" SET garbage_collection=-g
GOTO loop_options
REM ==== Define need of test restore ===============================================
:restore
SET restore=1
IF "%value%" == "0" SET restore=0
IF /i "%value%" == "N" SET restore=0
IF /i "%value%" == "NO" SET restore=0
IF /i "%value%" == "OFF" SET restore=0
GOTO loop_options
REM ==== Define need of backup compression and compress ratio ======================
:compress
IF "%value%" GEQ "0" IF "%value%" LEQ "5" SET rar_compress_ratio=%value%
GOTO loop_options
REM ==== Define SYSDBA password (in addition or for replace source code given) =====
:password
if "%ISC_PASSWORD_LOCAL%" GTR "" if "%ISC_PASSWORD_REMOTE%" GTR "" (
SET ISC_PASSWORD_LOCAL=%value%
SET ISC_PASSWORD_REMOTE=%value%
)
if "%ISC_PASSWORD_LOCAL%" == "" SET ISC_PASSWORD_LOCAL=%value%
if "%ISC_PASSWORD_REMOTE%" == "" SET ISC_PASSWORD_REMOTE=%value%
GOTO loop_options
REM ==== Define file list to compress (in addition to backup and maybe logs) =======
:add_file_to_compress
IF "%backup_files%" == "" (
SET backup_files="%next_param%"
) ELSE (
SET backup_files=%backup_files% "%next_param%"
)
GOTO loop_options
REM ==== Print predefined or recognized in command line options ====================
:print_options
IF %backup_count% GTR 0 (
ECHO backup_count = %backup_count%
) ELSE (
ECHO backup_count = OFF
)
IF "%file_size_shift%" == "" SET file_size_shift=0
IF %backup_space_limit% GTR 0 (
IF %file_size_shift% == 6 (
ECHO backup_space_limit = %backup_space_limit% Mb
) ELSE IF %file_size_shift% == 3 (
ECHO backup_space_limit = %backup_space_limit% Kb
) ELSE ECHO backup_space_limit = %backup_space_limit% bytes
) ELSE (
ECHO backup_space_limit = OFF
)
IF "%garbage_collection%" == "-g" (
ECHO garbage_collection_flag = OFF
) ELSE (
ECHO garbage_collection_flag = ON
)
IF %restore% == 0 (
ECHO test_restore_flag = OFF
) ELSE (
ECHO test_restore_flag = ON
)
IF %rar_compress_ratio% == 0 (
ECHO backup_compressing = OFF
) ELSE (
ECHO backup_compressing = ON, RAR-ratio=%rar_compress_ratio%
)
REM ==== Define backup file and backup log =========================================
SET datetime=%date:~-2%%date:~3,2%%date:~0,2%_%time:~0,2%%time:~3,2%
SET finish_file=%result_dir%%local_file_or_alias%.%datetime: =0%.%backup_ext%
SET direct_backup=0
IF %rar_compress_ratio% == 0 (
IF %is_local_result_dir% == 1 SET direct_backup=1
IF %restore% == 0 SET direct_backup=1
)
IF %direct_backup% == 1 (
SET backup_file=%finish_file%
) ELSE (
SET backup_file=%temp_backup_dir%%local_file_or_alias%.%backup_ext%
IF NOT EXIST "%temp_backup_dir%" (
MD "%temp_backup_dir%"
IF NOT EXIST "%temp_backup_dir%" (
SET fail=Cannot create backup directory!
GOTO finish
)
)
)
ECHO backup_file = %backup_file%
SET backup_log=%result_dir%%local_file_or_alias%.backup.log
ECHO backup_log = %backup_log%
REM ==== Define restore file and restore log =======================================
SET restore_file=%temp_restore_dir%%local_file_or_alias%.testrest
IF %restore% GTR 0 (
IF NOT EXIST "%temp_restore_dir%" (
MD "%temp_restore_dir%"
IF NOT EXIST "%temp_restore_dir%" (
ECHO temp_restore_dir = %temp_restore_dir%
SET fail=Cannot create restore directory!
GOTO finish
)
)
ECHO restore_file = %restore_file%
SET restore_log=%result_dir%%local_file_or_alias%.restore.log
)
IF "%restore_log%" GTR "" (
ECHO restore_log = %restore_log%
) else (
SET restore_log=just_a_stub
)
REM ==== Define compresed file =====================================================
SET compressed_file=%finish_file%.rar
IF %rar_compress_ratio% GTR 0 (
ECHO compressed_file = %compressed_file%
SET finish_file=%compressed_file%
)
REM ==== Delete not actual files (over defined count) ==============================
SET /a over=%backup_count%-1
IF %backup_count% == 1 (
ECHO deleting_old_files = %result_dir%%local_file_or_alias%.*.%backup_ext%*
DEL "%result_dir%%local_file_or_alias%.*.%backup_ext%*" /q
) ELSE IF %backup_count% GTR 1 (
FOR /f "SKIP=%over%" %%f IN ('DIR "%result_dir%%local_file_or_alias%.*.%backup_ext%*" /a:-D /b /o:-N 2^>NUL') DO (
IF EXIST "%result_dir%%%f" (
ECHO deleting_old_file = %result_dir%%%f
DEL "%result_dir%%%f" /q
)
)
)
REM ==== Perform backup ============================================================
IF EXIST "%backup_log%" DEL "%backup_log%" /q
ECHO backup_start = %date% %time:~0,8%
SET is_local_backup=0
IF %is_local_db% == 1 (
IF %is_local_result_dir% == 1 SET is_local_backup=1
IF %direct_backup% == 0 SET is_local_backup=1
SET ISC_PASSWORD=%ISC_PASSWORD_LOCAL%
) ELSE (
SET ISC_PASSWORD=%ISC_PASSWORD_REMOTE%
)
IF "%rar_password%" == "" SET rar_password=%ISC_PASSWORD%
IF %is_local_backup% == 1 (
ECHO %gbak% -b %garbage_collection% -se %service_mgr_host%:service_mgr %local% "%backup_file%" -v -y "%backup_log%"
%gbak% -b %garbage_collection% -se %service_mgr_host%:service_mgr %local% "%backup_file%" -v >"%backup_log%" 2>&1
) ELSE (
ECHO %gbak% -b %garbage_collection% "%full_db_specification%" "%backup_file%" -v -y "%backup_log%"
%gbak% -b %garbage_collection% "%full_db_specification%" "%backup_file%" -v >"%backup_log%" 2>&1
)
IF %ERRORLEVEL% GTR 0 (
IF EXIST "%backup_log%" (
SET fail=Backup fail! See %backup_log% for details.
) ELSE (
SET fail=Backup fail!
)
GOTO finish
)
IF NOT EXIST "%backup_log%" (
SET fail=Backup fail!
GOTO finish
)
REM ==== Perform test restore ======================================================
IF %restore% GTR 0 (
IF EXIST "%restore_log%" DEL "%restore_log%" /q
IF "%ISC_PASSWORD_LOCAL%" GTR "" (
SET ISC_PASSWORD=%ISC_PASSWORD_LOCAL%
) ELSE (
SET ISC_PASSWORD=%ISC_PASSWORD_REMOTE%
)
ECHO restore_start = %date% %time:~0,8%
ECHO %gbak% -rep -se %service_mgr_host%:service_mgr "%backup_file%" "%restore_file%" -v -y "%restore_log%"
%gbak% -rep -se %service_mgr_host%:service_mgr "%backup_file%" "%restore_file%" -v >"%restore_log%" 2>&1
IF %ERRORLEVEL% GTR 0 (
IF EXIST "%restore_log%" (
SET fail=Test restore fail! See %restore_log% for details.
) ELSE (
SET fail=Test restore fail!
)
GOTO finish
)
IF NOT EXIST "%restore_log%" (
SET fail=Test restore fail!
GOTO finish
)
)
REM ==== Perform RAR-compression or copy backup into destination dir ===============
IF "%rar_password%" GTR "" SET rar_password=-p%rar_password%
SET rar_options=%rar_options% -m%rar_compress_ratio%
SET backup_files="%backup_file%" %backup_files%
IF %include_logs_to_archive% == 1 (
IF %restore% GTR 0 (
SET backup_files=%backup_files% "%backup_log%" "%restore_log%"
) ELSE (
SET backup_files=%backup_files% "%backup_log%"
)
)
IF %rar_compress_ratio% GTR 0 (
ECHO compressing_start = %date% %time:~0,8%
ECHO %rar% %rar_options% "%compressed_file%" %backup_files%
%rar% %rar_options% %rar_password% "%compressed_file%" %backup_files%
IF %ERRORLEVEL% GTR 0 (
SET fail=Compression fail!
GOTO finish
)
) ELSE IF %direct_backup% == 0 (
ECHO copying_start = %date% %time:~0,8%
ECHO COPY "%backup_file%" "%finish_file%"
COPY "%backup_file%" "%finish_file%"
)
REM ==== Delete not actual files (over defined space) ==============================
IF %backup_space_limit% GTR 0 (
SETLOCAL EnableDelayedExpansion
IF %ERRORLEVEL% GTR 0 (
ECHO You must enable var delayed expansion by CMD.EXE /V:ON or at registry key
ECHO SoftwareMicrosoftCommand ProcessorDelayedExpansion: HKLM or HKCU
GOTO finish
)
FOR /f %%f IN ('DIR "%result_dir%%local_file_or_alias%.*.%backup_ext%*" /a:-D /b /o:-N') DO (
FOR %%i in ("%result_dir%%%f") DO (
SET size=%%~zi
IF %file_size_shift% == 3 SET size=!size:~0,-3!
IF %file_size_shift% == 6 SET size=!size:~0,-6!
IF "!size!" == "" SET size=0
IF "!total_space!" == "" (
SET /a total_space=!size!
) ELSE (
IF !total_space! LEQ %backup_space_limit% SET /a total_space+=!size!
IF !total_space! GTR %backup_space_limit% (
ECHO deleting_overquota_file = %result_dir%%%f
DEL "%result_dir%%%f" /q
)
)
)
)
)
REM ==== Report when fail or exit ==================================================
:finish
IF "%fail%" GTR "" (
ECHO #=============================================================================#
ECHO # %fail%
ECHO #=============================================================================#
SET fail=%fail% DB: %full_db_specification% Dest: %result_dir%
IF "%net_send_receiver%" GTR "" (
ECHO NET SEND %net_send_receiver% "%fail%"
NET SEND %net_send_receiver% "%fail%"
)
IF "%blat%" GTR "" IF "%smtp_server%" GTR "" IF "%mail_sender%" GTR "" IF "%mail_login%" GTR "" IF "%mail_receiver%" GTR "" (
ECHO %blat% -to "%mail_receiver%" -subject "%mail_subject%" -body "%fail%" -server %smtp_server% -f "%mail_sender%" -u "%mail_login%"
%blat% -to "%mail_receiver%" -subject "%mail_subject%" -body "%fail%" -server %smtp_server% -f "%mail_sender%" -u "%mail_login%" -pw "%mail_password%"
)
SET time_ex=%time: =0%
IF "%error_log%" GTR "" (
ECHO %date% %time_ex:~0,8% %fail% >> "%error_log%"
)
EXIT /b 1
) ELSE (
ECHO Finish = %date% %time:~0,8%
)
Приведу также лог, генерируемый запуском скрипта в наиболее простом виде: никаких дополнительных ключей, все параметры по умолчанию, передается только адрес БД и каталог назначения
#=============================================================================#
# #
# Firebird/InterBase database backup, test restore, zip and rotate script #
# Ver 3.2.7 (11.11.2012) #
# #
# Author: arni (email:arnisoft at rambler dot ru) #
# #
# Format: #
# FB_BACKUP [host[/port]:][path]db_file_or_alias result_dir #
# [/count:backup_count] [/space:backup_space_limit] [/gc] #
# [/restore] [/compress:level] [/password:SYSDBA_password] #
# [other_files_to_compress [...]] #
# #
# Input params: #
# [host[/port]:][path] : local or network, full-specified path or alias #
# db_file_or_alias to the source database #
# result_dir : result backup collecting directory #
# /count:backup_count : backup file number to keep (30 by default) #
# /space:backup_space_limit : total backup size in bytes (not use by default) #
# you can use suffixes K, M or G. #
# /gc : need to collect garbage in DB (OFF by default) #
# /restore : need to do test restore (OFF by default) #
# /compress:level : compress ratio for RAR (2 by default): #
# 0: not compress, 1: fastest, 2: fast, #
# 3: normal, 4: good, 5: best #
# /password:SYSDBA_password : optional SYSDBA password for remote server #
# (by default uses one from the source code) #
# other_files_to_compress : list of files that must be add to archive #
# #
#=============================================================================#
full_db_specification = localhost:p:MSODBMS_ORDERS.FDB
network_specification = localhost
local_db_specification = p:MSODBMS_ORDERS.FDB
local_path = p:MSODB
local_db_file_or_alias = MS_ORDERS.FDB
result_dir = \192.168.1.1disk_a1обмен
backup_count = 30
backup_space_limit = OFF
garbage_collection_flag = OFF
test_restore_flag = OFF
backup_compressing = ON, RAR-ratio=2
backup_file = C:WINDOWSTEMPMS_ORDERS.FDB.fbk
backup_log = \192.168.1.1disk_a1обменMS_ORDERS.FDB.backup.log
compressed_file = \192.168.1.1disk_a1обменMS_ORDERS.FDB.121111_1621.fbk.rar
backup_start = 11.11.2012 16:21:48
"C:ProgramsFB25bingbak.exe" -b -g -se localhost:service_mgr p:MSODBMS_ORDERS.FDB "C:WINDOWSTEMPMS_ORDERS.FDB.fbk" -v -y "\192.168.1.1disk_a1обменMS_ORDERS.FDB.backup.log"
compressing_start = 11.11.2012 16:21:51
"C:Program FilesWinRARrar.exe" a -y -ep -idcd -m2 "\192.168.1.1disk_a1обменMS_ORDERS.FDB.121111_1621.fbk.rar" "C:WINDOWSTEMPMS_ORDERS.FDB.fbk" "\192.168.1.1disk_a1обменMS_ORDERS.FDB.backup.log"
Создание архива \192.168.1.1disk_a1обменMS_ORDERS.FDB.121111_1621.fbk.rar
Добавление C:WINDOWSTEMPMS_ORDERS.FDB.fbk 6% 12% 18% 24% 30% 36% 42% 48% 54% 60% 66% 72% 78% 84% 86% OK
Добавление \192.168.1.1disk_a1обменMS_ORDERS.FDB.backup.log 92% 98%100% OK
Finish = 11.11.2012 16:21:51
Разберем фрагменты скрипта:
@CLS
@ECHO OFF
ECHO #=============================================================================#
ECHO # #
ECHO # Firebird/InterBase database backup, test restore, zip and rotate script #
ECHO # Ver 3.2.7 (11.11.2012) #
ECHO # #
ECHO # Author: arni (email:arnisoft at rambler dot ru) #
ECHO # #
ECHO # Format: #
ECHO # FB_BACKUP [host[/port]:][path]db_file_or_alias result_dir #
ECHO # [/count:backup_count] [/space:backup_space_limit] [/gc] #
ECHO # [/restore] [/compress:level] [/password:SYSDBA_password] #
ECHO # [other_files_to_compress [...]] #
ECHO # #
ECHO # Input params: #
ECHO # [host[/port]:][path] : local or network, full-specified path or alias #
ECHO # db_file_or_alias to the source database #
ECHO # result_dir : result backup collecting directory #
ECHO # /count:backup_count : backup file number to keep (30 by default) #
ECHO # /space:backup_space_limit : total backup size in bytes (not use by default) #
ECHO # you can use suffixes K, M or G. #
ECHO # /gc : need to collect garbage in DB (OFF by default) #
ECHO # /restore : need to do test restore (OFF by default) #
ECHO # /compress:level : compress ratio for RAR (2 by default): #
ECHO # 0: not compress, 1: fastest, 2: fast, #
ECHO # 3: normal, 4: good, 5: best #
ECHO # /password:SYSDBA_password : optional SYSDBA password for remote server #
ECHO # (by default uses one from the source code) #
ECHO # other_files_to_compress : list of files that must be add to archive #
ECHO # #
ECHO #=============================================================================#
REM ==== Server ====================================================================
SET gbak="C:ProgramsFB25bingbak.exe"
SET ISC_USER=SYSDBA
SET ISC_PASSWORD_LOCAL=masterkey
SET ISC_PASSWORD_REMOTE=
REM ==== Backup/restore preferences ================================================
SET temp_backup_dir=%TEMP%
SET temp_restore_dir=%TEMP%
SET backup_count=30
SET backup_space_limit=0
SET backup_ext=fbk
SET garbage_collection=-g
SET restore=0
REM ==== RAR =======================================================================
SET rar="C:Program FilesWinRARrar.exe"
SET rar_options=a -y -ep -idcd
SET rar_password=
SET rar_compress_ratio=2
REM ==== Mailer (see "Blat" at http://sourceforge.net/projects/blat) ===============
SET blat="C:ProgramsBlat307blat.exe"
SET smtp_server=smtp.mailserver.ru
SET mail_sender=foo@mailserver.ru
SET mail_login=foo
SET mail_password=1234
SET mail_receiver=
SET mail_subject=Fail while database b/r
REM ==== Other preferences =========================================================
SET include_logs_to_archive=1
SET net_send_receiver=
SET error_log=
где:
REM ==== Define database location ==================================================
SET full_db_specification=%~1
ECHO full_db_specification = %full_db_specification%
REM Devide DB spec to network and local parts
FOR /f "DELIMS=: TOKENS=1*" %%i IN ("%full_db_specification%") DO (
SET network=%%i
SET local=%%j
)
REM Test if spec. is alias with no network part
IF "%local%" == "" (
SET network=
SET local=%full_db_specification%
)
REM Test if spec. is full specified file with no network part
FOR /f "DELIMS= TOKENS=*" %%i IN ("%local%") DO IF "%local%" == "%%i" (
SET network=
SET local=%full_db_specification%
)
ECHO network_specification = %network%
IF "%network%" GTR "" (
REM Extract port from network spec (if exists)
FOR /f "DELIMS=/ TOKENS=1*" %%i IN ("%network%") DO (
SET host=%%i
SET port=%%j
IF "%%j" GTR "" (
ECHO network_host = %%i
ECHO network_port = %%j
)
)
)
REM Test if DB is local or remote
SET service_mgr_host=localhost
SET is_local_db=1
IF "%network%" GTR "" IF "%host%" NEQ "127.0.0.1" IF /i "%host%" NEQ "localhost" SET is_local_db=0
IF %is_local_db% == 1 IF "%network%" GTR "" SET service_mgr_host=%network%
ECHO local_db_specification = %local%
IF "%local%" == "" (
SET fail=Param #1 {DB specification} missing!
GOTO finish
)
REM Extract file (or alias) from local part of spec.
FOR /f %%i IN ("%local%") DO (
SET local_path=%%~dpi
SET local_file_or_alias=%%~nxi
)
IF "%local%" NEQ "%local_file_or_alias%" (
ECHO local_path = %local_path%
REM Check DB file exists for local, not aliased specification
IF %is_local_db% == 1 IF NOT EXIST "%local%" (
SET fail=Local DB file %local% not found!
GOTO finish
)
)
ECHO local_db_file_or_alias = %local_file_or_alias%
REM ==== Define result directory ===================================================
SET result_dir=%~2
ECHO result_dir = %result_dir%
IF "%result_dir%" == "" (
SET fail=Param #2 {backup collecting directory} missing!
GOTO finish
)
REM Cut the result dir if it is in path-style (ends with separator)
IF "%result_dir:~-1%" == "" SET result_dir=%result_dir:~0,-1%
REM Try to create the result directory if it is not exists yet
IF NOT EXIST "%result_dir%" (
MD "%result_dir%"
IF NOT EXIST "%result_dir%" (
SET fail=Cannot create backup collecting directory!
GOTO finish
)
)
REM Test if it is local or remote directory (elementary, may get wrong answer)
SET is_local_result_dir=1
IF "%result_dir:~0,2%" == "\" SET is_local_result_dir=0
Данный блок имеет код обработки ошибок, при возникновении которых в переменную пишется суть сбоя, после чего управление передается в конец скрипта — в блок обратной связи с админом. Подобные обработчики встречаются во всех последующих блоках, и далее я не буду их специально упоминать.
REM ==== Use other command line options ============================================
:loop_options
SHIFT
SET next_param=%~2
IF "%next_param%" == "" GOTO print_options
SET prefix=%next_param:~0,1%
IF "%prefix%" == "/" SET next_param=%next_param:~1%
IF "%prefix%" == "-" SET next_param=%next_param:~1%
IF "%next_param%" GTR "" (
FOR /f "DELIMS=: TOKENS=1*" %%i IN ("%next_param%") DO (
SET value=%%j
IF /i "%%i" == "count" IF "%%j" GTR "" GOTO count
IF /i "%%i" == "space" IF "%%j" GTR "" GOTO space
IF /i "%%i" == "gc" GOTO gc
IF /i "%%i" == "restore" GOTO restore
IF /i "%%i" == "compress" IF "%%j" GTR "" GOTO compress
IF /i "%%i" == "password" IF "%%j" GTR "" GOTO password
IF EXIST "%next_param%" GOTO add_file_to_compress
IF "%prefix%" GTR "/" GOTO add_file_to_compress
ECHO unknown param found: %next_param%
GOTO loop_options
)
) ELSE (
ECHO empty param found!
GOTO loop_options
)
REM ==== Define file count in the result dir =======================================
:count
SET /a backup_count=0+%value%
GOTO loop_options
REM ==== Define allowed backup space limit =========================================
:space
SET suffix=%value:~-1%
IF "%suffix%" GTR "9" (
SET value=%value:~0,-1%
IF /i "%suffix%" == "K" (
SET file_size_shift=0
SET /a value*=1000
)
IF /i "%suffix%" == "M" (
SET file_size_shift=3
SET /a value*=1000
)
IF /i "%suffix%" == "G" (
SET file_size_shift=6
SET /a value*=1000
)
)
SET /a backup_space_limit=0+%value%
GOTO loop_options
REM ==== Define need of garbage collection =========================================
:gc
SET garbage_collection=
IF "%value%" == "0" SET garbage_collection=-g
IF /i "%value%" == "N" SET garbage_collection=-g
IF /i "%value%" == "NO" SET garbage_collection=-g
IF /i "%value%" == "OFF" SET garbage_collection=-g
GOTO loop_options
REM ==== Define need of test restore ===============================================
:restore
SET restore=1
IF "%value%" == "0" SET restore=0
IF /i "%value%" == "N" SET restore=0
IF /i "%value%" == "NO" SET restore=0
IF /i "%value%" == "OFF" SET restore=0
GOTO loop_options
REM ==== Define need of backup compression and compress ratio ======================
:compress
IF "%value%" GEQ "0" IF "%value%" LEQ "5" SET rar_compress_ratio=%value%
GOTO loop_options
REM ==== Define SYSDBA password (in addition or for replace source code given) =====
:password
if "%ISC_PASSWORD_LOCAL%" GTR "" if "%ISC_PASSWORD_REMOTE%" GTR "" (
SET ISC_PASSWORD_LOCAL=%value%
SET ISC_PASSWORD_REMOTE=%value%
)
if "%ISC_PASSWORD_LOCAL%" == "" SET ISC_PASSWORD_LOCAL=%value%
if "%ISC_PASSWORD_REMOTE%" == "" SET ISC_PASSWORD_REMOTE=%value%
GOTO loop_options
REM ==== Define file list to compress (in addition to backup and maybe logs) =======
:add_file_to_compress
IF "%backup_files%" == "" (
SET backup_files="%next_param%"
) ELSE (
SET backup_files=%backup_files% "%next_param%"
)
GOTO loop_options
Примечание:
REM ==== Print predefined or recognized in command line options ====================
:print_options
IF %backup_count% GTR 0 (
ECHO backup_count = %backup_count%
) ELSE (
ECHO backup_count = OFF
)
IF "%file_size_shift%" == "" SET file_size_shift=0
IF %backup_space_limit% GTR 0 (
IF %file_size_shift% == 6 (
ECHO backup_space_limit = %backup_space_limit% Mb
) ELSE IF %file_size_shift% == 3 (
ECHO backup_space_limit = %backup_space_limit% Kb
) ELSE ECHO backup_space_limit = %backup_space_limit% bytes
) ELSE (
ECHO backup_space_limit = OFF
)
IF "%garbage_collection%" == "-g" (
ECHO garbage_collection_flag = OFF
) ELSE (
ECHO garbage_collection_flag = ON
)
IF %restore% == 0 (
ECHO test_restore_flag = OFF
) ELSE (
ECHO test_restore_flag = ON
)
IF %rar_compress_ratio% == 0 (
ECHO backup_compressing = OFF
) ELSE (
ECHO backup_compressing = ON, RAR-ratio=%rar_compress_ratio%
)
REM ==== Define backup file and backup log =========================================
SET datetime=%date:~-2%%date:~3,2%%date:~0,2%_%time:~0,2%%time:~3,2%
SET finish_file=%result_dir%%local_file_or_alias%.%datetime: =0%.%backup_ext%
SET direct_backup=0
IF %rar_compress_ratio% == 0 (
IF %is_local_result_dir% == 1 SET direct_backup=1
IF %restore% == 0 SET direct_backup=1
)
IF %direct_backup% == 1 (
SET backup_file=%finish_file%
) ELSE (
SET backup_file=%temp_backup_dir%%local_file_or_alias%.%backup_ext%
IF NOT EXIST "%temp_backup_dir%" (
MD "%temp_backup_dir%"
IF NOT EXIST "%temp_backup_dir%" (
SET fail=Cannot create backup directory!
GOTO finish
)
)
)
ECHO backup_file = %backup_file%
SET backup_log=%result_dir%%local_file_or_alias%.backup.log
ECHO backup_log = %backup_log%
REM ==== Define restore file and restore log =======================================
SET restore_file=%temp_restore_dir%%local_file_or_alias%.testrest
IF %restore% GTR 0 (
IF NOT EXIST "%temp_restore_dir%" (
MD "%temp_restore_dir%"
IF NOT EXIST "%temp_restore_dir%" (
ECHO temp_restore_dir = %temp_restore_dir%
SET fail=Cannot create restore directory!
GOTO finish
)
)
ECHO restore_file = %restore_file%
SET restore_log=%result_dir%%local_file_or_alias%.restore.log
)
IF "%restore_log%" GTR "" (
ECHO restore_log = %restore_log%
) else (
SET restore_log=just_a_stub
)
REM ==== Define compresed file =====================================================
SET compressed_file=%finish_file%.rar
IF %rar_compress_ratio% GTR 0 (
ECHO compressed_file = %compressed_file%
SET finish_file=%compressed_file%
)
REM ==== Delete not actual files (over defined count) ==============================
SET /a over=%backup_count%-1
IF %backup_count% == 1 (
ECHO deleting_old_files = %result_dir%%local_file_or_alias%.*.%backup_ext%*
DEL "%result_dir%%local_file_or_alias%.*.%backup_ext%*" /q
) ELSE IF %backup_count% GTR 1 (
FOR /f "SKIP=%over%" %%f IN ('DIR "%result_dir%%local_file_or_alias%.*.%backup_ext%*" /a:-D /b /o:-N 2^>NUL') DO (
IF EXIST "%result_dir%%%f" (
ECHO deleting_old_file = %result_dir%%%f
DEL "%result_dir%%%f" /q
)
)
)
REM ==== Perform backup ============================================================
IF EXIST "%backup_log%" DEL "%backup_log%" /q
ECHO backup_start = %date% %time:~0,8%
SET is_local_backup=0
IF %is_local_db% == 1 (
IF %is_local_result_dir% == 1 SET is_local_backup=1
IF %direct_backup% == 0 SET is_local_backup=1
SET ISC_PASSWORD=%ISC_PASSWORD_LOCAL%
) ELSE (
SET ISC_PASSWORD=%ISC_PASSWORD_REMOTE%
)
IF "%rar_password%" == "" SET rar_password=%ISC_PASSWORD%
IF %is_local_backup% == 1 (
ECHO %gbak% -b %garbage_collection% -se %service_mgr_host%:service_mgr %local% "%backup_file%" -v -y "%backup_log%"
%gbak% -b %garbage_collection% -se %service_mgr_host%:service_mgr %local% "%backup_file%" -v >"%backup_log%" 2>&1
) ELSE (
ECHO %gbak% -b %garbage_collection% "%full_db_specification%" "%backup_file%" -v -y "%backup_log%"
%gbak% -b %garbage_collection% "%full_db_specification%" "%backup_file%" -v >"%backup_log%" 2>&1
)
IF %ERRORLEVEL% GTR 0 (
IF EXIST "%backup_log%" (
SET fail=Backup fail! See %backup_log% for details.
) ELSE (
SET fail=Backup fail!
)
GOTO finish
)
IF NOT EXIST "%backup_log%" (
SET fail=Backup fail!
GOTO finish
)
REM ==== Perform test restore ======================================================
IF %restore% GTR 0 (
IF EXIST "%restore_log%" DEL "%restore_log%" /q
IF "%ISC_PASSWORD_LOCAL%" GTR "" (
SET ISC_PASSWORD=%ISC_PASSWORD_LOCAL%
) ELSE (
SET ISC_PASSWORD=%ISC_PASSWORD_REMOTE%
)
ECHO restore_start = %date% %time:~0,8%
ECHO %gbak% -rep -se %service_mgr_host%:service_mgr "%backup_file%" "%restore_file%" -v -y "%restore_log%"
%gbak% -rep -se %service_mgr_host%:service_mgr "%backup_file%" "%restore_file%" -v >"%restore_log%" 2>&1
IF %ERRORLEVEL% GTR 0 (
IF EXIST "%restore_log%" (
SET fail=Test restore fail! See %restore_log% for details.
) ELSE (
SET fail=Test restore fail!
)
GOTO finish
)
IF NOT EXIST "%restore_log%" (
SET fail=Test restore fail!
GOTO finish
)
)
Примечание:
Если у вас InterBase, Yaffil или Firebird младше версии 2.0, флаг восстановления -rep нужно заменить на -r
REM ==== Perform RAR-compression or copy backup into destination dir ===============
IF "%rar_password%" GTR "" SET rar_password=-p%rar_password%
SET rar_options=%rar_options% -m%rar_compress_ratio%
SET backup_files="%backup_file%" %backup_files%
IF %include_logs_to_archive% == 1 (
IF %restore% GTR 0 (
SET backup_files=%backup_files% "%backup_log%" "%restore_log%"
) ELSE (
SET backup_files=%backup_files% "%backup_log%"
)
)
IF %rar_compress_ratio% GTR 0 (
ECHO compressing_start = %date% %time:~0,8%
ECHO %rar% %rar_options% "%compressed_file%" %backup_files%
%rar% %rar_options% %rar_password% "%compressed_file%" %backup_files%
IF %ERRORLEVEL% GTR 0 (
SET fail=Compression fail!
GOTO finish
)
) ELSE IF %direct_backup% == 0 (
ECHO copying_start = %date% %time:~0,8%
ECHO COPY "%backup_file%" "%finish_file%"
COPY "%backup_file%" "%finish_file%"
)
Примечание:
В ряде обсуждений встречаются примеры, когда для ускорения сжатия резервной копии gbak.exe и rar.exe запускаются в связке, когда вывод первого подается непосредственно на вход второго. К сожалению, у этого метода есть существенный недостаток, не позволяющий рекомендовать его к использованию: если gbak.exe завершается ошибкой, то в итоге все равно возвращается нулевой (успешный) код возврата, т.к. rar.exe честно и безошибочно забекапил те крохи, что gbak.exe успел ему передать, прежде чем завалился. Т.е. вы никогда не узнаете, что у вас сбоит процесс изготовления резервных копий, пока не попытаетесь восстановить битый бекап, либо случайно не обратите внимание на копеешный размер итогового архива.
REM ==== Delete not actual files (over defined space) ==============================
IF %backup_space_limit% GTR 0 (
SETLOCAL EnableDelayedExpansion
IF %ERRORLEVEL% GTR 0 (
ECHO You must enable var delayed expansion by CMD.EXE /V:ON or at registry key
ECHO SoftwareMicrosoftCommand ProcessorDelayedExpansion: HKLM or HKCU
GOTO finish
)
FOR /f %%f IN ('DIR "%result_dir%%local_file_or_alias%.*.%backup_ext%*" /a:-D /b /o:-N') DO (
FOR %%i in ("%result_dir%%%f") DO (
SET size=%%~zi
IF %file_size_shift% == 3 SET size=!size:~0,-3!
IF %file_size_shift% == 6 SET size=!size:~0,-6!
IF "!size!" == "" SET size=0
IF "!total_space!" == "" (
SET /a total_space=!size!
) ELSE (
IF !total_space! LEQ %backup_space_limit% SET /a total_space+=!size!
IF !total_space! GTR %backup_space_limit% (
ECHO deleting_overquota_file = %result_dir%%%f
DEL "%result_dir%%%f" /q
)
)
)
)
)
REM ==== Report when fail or exit ==================================================
:finish
IF "%fail%" GTR "" (
ECHO #=============================================================================#
ECHO # %fail%
ECHO #=============================================================================#
SET fail=%fail% DB: %full_db_specification% Dest: %result_dir%
IF "%net_send_receiver%" GTR "" (
ECHO NET SEND %net_send_receiver% "%fail%"
NET SEND %net_send_receiver% "%fail%"
)
IF "%blat%" GTR "" IF "%smtp_server%" GTR "" IF "%mail_sender%" GTR "" IF "%mail_login%" GTR "" IF "%mail_receiver%" GTR "" (
ECHO %blat% -to "%mail_receiver%" -subject "%mail_subject%" -body "%fail%" -server %smtp_server% -f "%mail_sender%" -u "%mail_login%"
%blat% -to "%mail_receiver%" -subject "%mail_subject%" -body "%fail%" -server %smtp_server% -f "%mail_sender%" -u "%mail_login%" -pw "%mail_password%"
)
SET time_ex=%time: =0%
IF "%error_log%" GTR "" (
ECHO %date% %time_ex:~0,8% %fail% >> "%error_log%"
)
EXIT /b 1
) ELSE (
ECHO Finish = %date% %time:~0,8%
)
Приведу пару сценариев, описывающих применение скрипта в нашей повседневной практике. Условно назову их «ночной бекап» и «дневной бекап».
В ночное время с базой никто не работает, или почти никто. Ресурсы сервера простаивают, а поэтому уместно произвести полноценный цикл b/r, а именно:
— бекап со сборкой мусора;
— тестовое восстановление;
— сжатие резервной копии и текущей версии прикладной программы, причем сжатие наилучшим образом;
Вот пример запуска «ночного бекапа»:
fb_backup.bat localhost:Orma4 d:Bak /count:99 /space:500G /compress:5 /restore /gc d:Orma.exe >C:Orma4.log 2>&1
Напротив, запуск «дневного бекапа» должен отработать как можно быстрее, как можно менее напрягая сервер, а значит и подключенных к БД пользователей. Поэтому исключаем сборку мусора и тестовое восстановление, сжимаем наибыстрейшим методом, и только файл резервной копии:
fb_backup.bat localhost:Orma4 d:Bak /count:99 /space:500G /compress:1 >C:Orma4.log 2>&1
Есть еще вариант записи бекапа на удаленный сервер (в целях безопасности согласно принципа «не хранить все яйца в одной корзине»). Он сочетает промежуточный набор ключей: жать нужно наиболее плотно, т.к. архиватор обычно успевает перемолачивать быстрее, чем сеть справляется с перекачкой файла, а остальные операции (сбор мусора, тестовое восстановление, сохранение прикладной программы и т.д.) по возможности исключить, т.к. они уже были выполнены «ночным бекапом» на локальный сервер:
fb_backup.bat localhost:Orma4 \ifsE$backupFirebirdDB /count:99 /space:300G /compress:5 >C:Orma4.log 2>&1
Для тех кто не в курсе, концовка команды означает перенаправить вывод скрипта (stdout) в файл, и вывод ошибок (stderr) направить в тот же файл.
>C:Orma4.log 2>&1
Немного об ограничениях скрипта.
Автор: arni
Источник [9]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/administrirovanie-baz-danny-h/20026
Ссылки в тексте:
[1] firebirdsql.org: Firebird's gbak Backup and Restore tool (англ.): http://www.firebirdsql.org/file/documentation/reference_manuals/user_manuals/html/gbak.html
[2] ibase.ru: Утилита GBAK, Firebird и InterBase: http://ibase.ru/devinfo/gbak.htm
[3] Бекап: http://ibase.ru/devinfo/gbak.htm#backup
[4] Восстановление, или рестор: http://ibase.ru/devinfo/gbak.htm#restore
[5] не смог её восстановить в новую БД: http://ibase.ru/devinfo/db_repair.htm#norestore
[6] бекап через сервисы: http://ibase.ru/devinfo/gbak.htm#bsapi
[7] Blat: http://sourceforge.net/projects/blat/
[8] Windows Trusted Authentication: http://firebird.svn.sourceforge.net/viewvc/firebird/firebird/trunk/doc/README.trusted_authentication?view=markup
[9] Источник: http://habrahabr.ru/post/158575/
Нажмите здесь для печати.