Wednesday, March 12, 2008

SVN備份策略

這幾天試了SVN (Subversion),跟之前的WinCVS用起來不太順手,可能以前用WinCVS用的太習慣了!!然而現今世界都在使用SVN來管理文件或程式碼,連sourceforge都已經在使用SVN,所以身為一個資訊人員,也要試試看SVN到底有多迷人~~~

SVN Server也架好了,剛好公司也有一台NFS Server,NFS Server目的是要備份所有程式碼倉庫(Repository)的文件,以免防止意外產生(如硬碟毀損...). 而我在網路上找到幾個備份的策略,雖然不符合我的需求,索性只好修改程式然後再加上我自己想要的功能..

網路上找到的,都是針對一個Repository來作備份的,而我的需求是備份所有倉庫. 做法很簡單,只要設定固定要存放倉庫的路徑,這支perl script就會自動幫你備份,再搭配crontable的設定就可以每天自動幫你備份.

底下可以分為兩種策略,一種是漸進式的備份Repository,另外一種是完整的備份.

漸進式的備份的優點是備份速度快,而完整的備份速度比較慢.原因是漸進式的備份是屬於少量的Reversion的備份,資料量比較少,而完整的備份是從Reversion 1 到 Reversion 100,每一個version都完全地備份,所佔的硬碟空間也比較大!!


策略一: 每天備份,我設定的時間是晚上11點,只要今天有異動到的我就會以最新的版本備份
------------------------------------------
#!/usr/bin/perl -w

use DirHandle;
use strict;

sub svn_repos_backup;

#--------------------------Config variable---------------------------
my $repos_dir = "/usr/local/svn"; #This is current repository directory.
my $repos_backup_dir = "/mnt/svn"; #This is the backup directory.

#------------------------------Don't change--------------------------
my $repos_backup_lastver = "REV";
my $next_backup_file = "daily_backup.".`date +%Y%m%d`;
my $svnlook_cmd ="svnlook youngest";
my @ReposList;
#--------------------------------------------------------------------

print "=======================================\n";
print "\tREPOS_DIR=".$repos_dir."\n";
print "\tREPOS_BACKUP_DIR=".$repos_backup_dir."\n";
print "=======================================\n";

#
# Parse all repositories under repository direcotry. We are not suggest empty directory in repository directory.
# Please remove the empty directory when you execute this perl script before.
#
if (opendir(DIRHANDLE, $repos_dir))
{
my @Filelist;


@Filelist = readdir(DIRHANDLE);

foreach(@Filelist)
{
my $fname = "$repos_dir/$_";

#print $fname."\n";

if (-d $fname) # test directory
{
if( ($_ ne '.') && ($_ ne '..'))
{
push @ReposList,$_;
}
}
}
}

closedir(DIRHANDLE);


#
# Backup each repository to BACKUP_DIR
#
my $tmp_repos_dir;
my $exec_cmd;

foreach(@ReposList)
{
$tmp_repos_dir= $repos_dir."/".$_;
$exec_cmd =$svnlook_cmd." ".$tmp_repos_dir."\n";
#print $exec_cmd;

svn_repos_backup($_);

}

#
# Backup the respository
#
sub svn_repos_backup()
{

my $lastrev;
my $currev;
my $repos_backup_file;

my $file_path_lastrev;
my $cmd_cur_rev;
my $cmd_svn_backup;
my $cmd_compress_file;



#print "ARG[0] ".$_[0]."\n";


$cmd_cur_rev = $svnlook_cmd." "."$repos_dir/".$_[0]."|";
open(REVS,$cmd_cur_rev) || die "can't fork: $!";
$currev = int();
print "Read Current Rev ".$currev."\n";
close(REVS);


$file_path_lastrev = $repos_backup_dir."/".$_[0]."/$repos_backup_lastver";

if(-e $file_path_lastrev)
{
print "Read $file_path_lastrev\n";
open(LREVS,"cat ".$file_path_lastrev."|");
$lastrev = int();
print "Read Last Rev ".$lastrev."\n";
close(LREVS);

if($lastrev != $currev)
{
$repos_backup_file = sprintf("$repos_backup_dir/$_[0]/%s-%s",$_[0],$next_backup_file);
#
#Execute the backup command.
#
print "Backup is processing...\n";
$cmd_svn_backup = sprintf("svnadmin dump /usr/local/svn/%s --incremental -r %d > $repos_backup_file",$_[0],$currev);
#print $cmd_svn_backup."\n";
system($cmd_svn_backup);

#
#Compress the file of the dumped file.
#
print "Compressing backup file...\n";
$cmd_compress_file = "gzip -9f $repos_backup_file";
print($cmd_compress_file."\n");
system($cmd_compress_file);

#
#Recodr current version and save to REV file.
#
open(LREVS,"+>","$file_path_lastrev");
print LREVS $currev;
close(LREVS);

#
#Remove the temporary dump file.
#
system("rm $repos_backup_file");
print("$_[0] backup done...\n");
}
}
else
{
mkdir($repos_backup_dir."/".$_[0])|| print $!;

open(REV_HANDLE,'>',$file_path_lastrev);
close(REV_HANDLE);
print "not found!!\n";
}
}

策略二: 每個禮拜備份一次,每個星期五晚上23點整個完整的備份,完整備份的資料會很龐大,所以要小心硬碟空間夠不夠用
#!/usr/bin/perl -w

use DirHandle;
use strict;

sub svn_repos_backup;

#--------------------------Config variable---------------------------
my $repos_dir = "/usr/local/svn"; #This is current repository directory.
my $repos_backup_dir = "/mnt/svn"; #This is the backup directory.

#------------------------------Don't change--------------------------

my $repos_backup_lastver = "REV";
my $next_backup_file;
my $svnlook_cmd ="svnlook youngest";
my @ReposList;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
#--------------------------------------------------------------------

print "=======================================\n";
print "\tREPOS_DIR=".$repos_dir."\n";
print "\tREPOS_BACKUP_DIR=".$repos_backup_dir."\n";
print "=======================================\n";
$year += 1900;
$mon += 1;
$next_backup_file= sprintf("weekly_backup.%04d%02d%02d",$year,$mon,$mday);
#
# Parse all repositories under repository direcotry. We are not suggest empty directory in repository directory.
# Please remove the empty directory when you execute this perl script before.
#
if (opendir(DIRHANDLE, $repos_dir))
{
my @Filelist;


@Filelist = readdir(DIRHANDLE);
   
foreach(@Filelist)
{
my $fname = "$repos_dir/$_";

#print $fname."\n";

if (-d $fname) # test directory
{
if( ($_ ne '.') && ($_ ne '..'))
{
push @ReposList,$_;
}
}
}
}

closedir(DIRHANDLE);


#
# Backup each repository to BACKUP_DIR
#
my $tmp_repos_dir;
my $exec_cmd;

foreach(@ReposList)
{
$tmp_repos_dir= $repos_dir."/".$_;
$exec_cmd =$svnlook_cmd." ".$tmp_repos_dir."\n";
#print $exec_cmd;

svn_repos_backup($_);

}

#
# Backup the respository
#
sub svn_repos_backup()
{

my $lastrev;
my $currev;
my $repos_backup_file;

my $file_path_lastrev;
my $cmd_cur_rev;
my $cmd_svn_backup;
my $cmd_compress_file;



$repos_backup_file = "$repos_backup_dir/$_[0]/$_[0]-$next_backup_file";

#
#Execute the backup command.
#
print "SVN Backup is processing...\n";
$cmd_svn_backup = "svnadmin dump $repos_dir/$_[0] > $repos_backup_file >& /dev/null";

print $cmd_svn_backup."\n";
#system($cmd_svn_backup);

#
#Compress the file of the dumped file.
#
print "Compressing backup file...\n";
$cmd_compress_file = "gzip -9f $repos_backup_file";
print($cmd_compress_file."\n");
system($cmd_compress_file);

#
#Remove the temporary dump file.
#
system("rm $repos_backup_file");
print("$_[0] backup done...\n");
}


No comments: