您的位置:首页 > 其它

SVN 备份恢复策略

2011-05-19 13:08 253 查看
SVN支持hotcopy和dump两种备份模式,hotcopy可以把整个代码库的目录结构拷贝出来包括配置文件和数据文件等,而dump以可读的方式将repository中的内容导出,支持增量备份。恢复hotcopy比较简单,直接将文件夹拷贝回原来的位置即可,恢复dump文件必须通过命令行的方式导入,如果某个增量备份丢失会导致恢复dump失败。

 

常见的备份策略是每天对dump进行增量备份,每周执行一次hotcopy备份。恢复的时候可以从dump恢复(时间较长),也可以先恢复hotcopy在从dump的增量恢复。

 

如果使用SVN edge server,用户信息和访问控制信息存放在csvn-production-hsqldb.properties和csvn-production-hsqldb.script中(data目录下),还有svn_access_file和svn_auth_file(data/conf目录下)。需要对这些文件分别备份。

 

SVN备份脚本:

#!perl -w
use File::Path qw(make_path);
use File::Copy;
use File::Compare;

#######################################################
#																											#
#										main procedure										#
#																											#
#######################################################

#log control flag
my $DEBUG = 1;
my $ERROR = 10;
my $WARN = 8;
my $INFO = 5;
# current log level
my $LEVEL = $DEBUG;

if(@ARGV != 3){
&usage;
exit 0
}

#get arguments from command line
my ($bk_type, $respo_dir, $backup_dir) = @ARGV;
my @reopsitories;

#bk_type = both or hotcopy or dump
$bk_type = lc($bk_type);
if($bk_type ne "both" && $bk_type ne "hotcopy" && $bk_type ne "dump"){
&error("Unknown backup type");
&usage;
exit 1;
}

unless (-e $respo_dir){
&error("Unknown directocry $respo_dir");
exit 1;
}
unless (-e $backup_dir){
&error("Unknown directocry $backup_dir");
exit 1;
}

my %time = &format_date(localtime);

&info("########## SVN server backup start ...");

opendir DH, $respo_dir or die "cannot open dir $respo_dir $!";
while(readdir DH){
next if $_ =~ /^/./; #skip dot files
my $repo = "$respo_dir//$_";
next unless -e "$repo//format"; #skip any invalidate folder
push @repositories, $_;
}
closedir DH;
&debug("Discover repositories: ".join(", ", @repositories));

foreach (@repositories){
if($bk_type ne "both"){
if($bk_type eq "hotcopy"){
&hotcopy_repository($_);
}
if($bk_type eq "dump"){
&dump_repository($_);
}
} else {
&hotcopy_repository($_);
&dump_repository($_);
}
}

&backup_cfg();

&info("########## SVN server backup complete ... ");

#######################################################
#																											#
#										subroutines												#
#																											#
#######################################################

sub hotcopy_repository{
unless(defined $_[0]){
&error("Repository is required!");
return;
}
my $repository = $_[0];
my $dumpfile_path = "$backup_dir//dump//$repository";
my $timelable = sprintf("%04d-%02d-%02d", $time{"year"}, $time{"month"}, $time{"day"});
my $repo_path = "$respo_dir//$repository";
my $hotcopy_path = "$backup_dir//hotcopy//${repository}//$timelable";

my $youngest = `svnlook youngest $repo_path`;
my $last_update;
chomp $youngest;

if (! open HISTORY, "$dumpfile_path//backup_history"){
&info("backup_history for repository $repository does not exist, perform hotcopy anyway");
} else {
chomp ($last_update = <HISTORY>);
close HISTORY;
}
&debug("youngest : last_backup $youngest : $last_update");
if($last_update eq $youngest){
&info("No update to repository $repository");
return;
}

unless(-e $hotcopy_path){
if (! make_path($hotcopy_path)){
&error("Can not make dir $hotcopy_path, $!");
return;
}
&debug("Make dir $hotcopy_path sucessfully");
}

my $command = "svnadmin hotcopy $repo_path $hotcopy_path 2>>$backup_dir//hotcopy//${repository}//${repository}_hotcopy.log";
&debug("Call svnadmin hotcopy to copy repository $repository starts.");
&debug($command);
my $rc = system($command);
&debug("Hotcopy repository $repository ends, return value = $rc");
if($rc){
&error("Hotcopy repository $repository failed, please check ${repository}_hotcopy.log to find the root cause");
return;
}

#check zip is installed or in the environment variable
#redirect the output to nul device
$rc = system("7z > nul");
&debug("call 7z and get return code: $rc");
if($rc){
&warn("Zip utility may not be installed or configured correctly")
}

my $zipcmd = "7z a ${hotcopy_path}_$repository.7z $hotcopy_path";
&debug("Call zip command: $zipcmd");
&info("Compress the hotcopy to $hotcopy_path.7z");
system("7z a ${hotcopy_path}_$repository.7z $hotcopy_path > $hotcopy_path//..//zip.log");
&info("Hotcopy repository $repository successfully");
} #end of sub hotcopy_repository

sub dump_repository{
my $repository = $_[0];

unless(defined $_[0]){
&error("Repository is required!");
return;
}

my $repo_path = "$respo_dir//$repository";
my $dumpfile_path = "$backup_dir//dump//$repository";

unless(-e $dumpfile_path){
if (! make_path($dumpfile_path)){
&error("Can not make dir $dumpfile_path, $!");
return;
}
}

#Get the lastest revision
my $youngest = `svnlook youngest $repo_path`;
chomp $youngest;
my $command;
&debug("Latest revision of repository $repository $youngest");

if (!open FILE, "$dumpfile_path//backup_history"){
&info("backup_history for repository $repository does not exist, perform a full dump");
$command = "svnadmin dump $repo_path > $dumpfile_path//${repository}_full.dump 2>>$dumpfile_path//${repository}_dump.log";
} else {
my $last_backup =  <FILE>;
chomp $last_backup;
close FILE;
&debug("Last backup revision of repository $repository $last_backup");
if($last_backup eq $youngest){
&info("No update to repository $repository");
return;
}
$last_backup += 1;
&info("Incremental backup of repository $repository from revision $last_backup to $youngest");
$command = "svnadmin dump -r $last_backup:$youngest --incremental $repo_path > $dumpfile_path//${repository}_r$youngest.dump 2>>$dumpfile_path//${repository}_dump.log";
}

&debug("Call svnadmin dump to dump repository $repository starts.");
&debug($command);
#the return code should be zero if command is successfully excuted
my $rc = system($command);
&debug("Dump repository $repository ends, return value = $rc");
if($rc){
&error("Dump repository $repository failed, check ${repository}_dump.log to find the root cause");
return;
}
&info("Dump repository $repository successfully");

#persist backup revision to file
if(-e "$dumpfile_path//backup_history"){
copy("$dumpfile_path//backup_history", "$dumpfile_path//backup_history.bk");
}
open FOUT, ">$dumpfile_path//backup_history" or die "Can not open file $dumpfile_path//backup_history $!";
print FOUT $youngest;
close FOUT;
}#end of sub dump_repository

#subroutine backup svn_auth_file and svn_access_file under %csvnroot%/data/conf
sub backup_cfg{
my $conf_source_dir = $respo_dir."//..//conf";
my $conf_backup_dir = $backup_dir."//conf";

unless(-e $conf_backup_dir){
if(! make_path($conf_backup_dir)){
&error("Can not make dir $conf_backup_dir $!, abort...");
return;
}
}
#compare original and backup, backup if changes
if(compare("$conf_source_dir//svn_auth_file", "$conf_backup_dir//avn_auth_file") != 0){
&info("Backup configuration file: svn_auth_file");
copy("$conf_source_dir//svn_auth_file", "$conf_backup_dir");
}
if(compare("$conf_source_dir//svn_access_file", "$conf_backup_dir//svn_access_file") != 0){
&info("Backup configuration file: svn_access_file");
copy("$conf_source_dir//svn_access_file", "$conf_backup_dir");
}
}#end of sub backup_cfg

sub warn{
&_log($WARN, $_[0]);
}

sub debug{
&_log($DEBUG, $_[0]);
}

sub info{
&_log($INFO, $_[0]);
}

sub error{
&_log($ERROR, $_[0]);
}

# subroutine _log
# usage: _log($level, $message);
#
sub _log{
my %d = &format_date(localtime());
my $level = $_[0];
my $lvldesc;

if($level == $DEBUG){
$lvldesc = "DEBUG";
} elsif ($level == $INFO){
$lvldesc = "INFO";
} elsif ($level == $ERROR){
$lvldesc = "ERROR";
}	elsif ($level == $WARN){
$lvldesc = "WARN";
}else {
$lvldesc = "UNKOWN";
}

my $message = sprintf("%04d-%02d-%02d %02d:%02d:%02d [%s] %s/n",
$d{"year"}, $d{"month"}, $d{"day"}, $d{"hour"}, $d{"minute"}, $d{"second"}, $lvldesc, $_[1]);

if($level >= $LEVEL){
print($message);
&_wirte_file($message);
}
}

sub _wirte_file(){
open LOG, ">>$backup_dir//backup.log" or die "failed to opne log file";
print LOG $_[0];
close LOG;
}

# subroutine format_date
#
# analyze output of localtime() and save the results to a hash
#
# usage: &format_date(localtime());
#
sub format_date{
my ($second,		$minute,    $hour,
$dayOfMonth,	$month,     $yearOffset,
$dayOfWeek,  	$dayOfYear,	$daylightSavings) = @_;

my %d = (
"second" 	=> $second < 10 ? "0".$second : $second,
"minute" 	=> $minute < 10 ? "0".$minute : $minute,
"hour" 		=> $hour < 10 ? "0".$hour : $hour,
"day"		=> $dayOfMonth < 10 ? "".$dayOfMonth : $dayOfMonth,
"month"		=> $month < 9 ? "0".$month + 1 : $month + 1,
"year"		=> $yearOffset + 1900
);
return %d;
}

sub usage{
print "usage: perl $0 <backup_type> <repository_dir> <backup_dir>/n";
print "<backup_type> can be both, hotcopy or dump/n";
print "example: perl $0 hotcopy c://csvn//data//repositories d://svnbackup/n";
}


 

SVN dump恢复脚本

#!perl -w
#restore dump files
my $repo_dir = $ARGV[0];
my $dump_dir = $ARGV[1];

if(! @ARGV){
print "usage: perl $0 <repository dir> <dump dir>/n";
exit 0;
}

unless (-e $repo_dir){
print "Error unknown directocry $repo_dir $!";
exit 1;
}

unless (-e $dump_dir){
print "Error unknown directocry $dump_dir $!";
exit 1;
}
unless (-e "$repo_dir//format") {
print "Error repository dir structure/n";
exit 1;
}

opendir DH, $dump_dir or die "cannot open dir $dump_dir $!";
my @dumps = grep { //.dump$/i && -f "$dump_dir/$_" } readdir(DH);
closedir DH;

my $cmd = "svnadmin load $repo_dir ";
my $rc;

foreach(@dumps){
$cmd .= "< $dump_dir//$_ >> svnresotre.log";
$rc = system($cmd);
if($rc != 0){
print "Error during restore abort!";
return 1;
}
print "Successfully Load $dump_dir//$_/n";
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息