Hi folks, I have a question regarding backups taken from a running slave. I have a slave replicating to a master server, and do a hot backup using the following script:
#!/usr/bin/perl use strict; use DBI; use File::Copy; use POSIX ":sys_wait_h"; my $dbh = DBI->connect("DBI:mysql:dbname=mysql;mysql_socket=/tmp/mysql.sock","user ","password") || die DBI->errstr(); ## Create the backup folder my ($d,$m,$y) = (localtime)[3..5]; my $date = sprintf("%d-%02d-%02d",$y+1900,$m+1,$d); my $ibbackup_pid; print "Creating backup folder : /storage/backups/backup-$date\n"; mkdir("/storage/backups/backup-$date") || die "couldn't create backup dir: $!"; mkdir("/storage/backups/backup-$date/sql") || die "couldn't create backup dir: $!"; ## Parse the /etc/my.cnf print "Parsing my.cnf\n"; open(F,"/etc/my.cnf") || die; my $found = 0; my %cfg; while(<F>) { chomp; ## Junk until we have start of [mysqld] section if (!$found) { next if (!/\[mysqld\]/i); $found = 1; next; } ## We aren't interested in anything not relating to the [mysqld] section ## stop reading when it's finished. last if ($found && /^\s*\[/); ## Skip comments and empty lines next if (/^(?:(?:#\|;).*|\s*)$/); ## Get rid of trailing space or ; s/(?:|\s*)$//; ## Handle the set-variable=var=something if (/^set-variable=(.*)$/) { my ($var,$val) = split(/\s*=\s*/,$1); $cfg{'set-variable'}{$var} = $val; next; } ## Split name/value pairs my ($var,$val) = split(/\s*=\s*/); $cfg{$var} = $val; } ## At this point %cfg contains the relevant [mysqld] configuration information. ## Create the backup config file print "Creating /storage/backups/backup-$date/my-backup.cnf\n"; open(FILE, ">/storage/backups/backup-$date/my-backup.cnf") || die "Failed to open file /storage/backups/backup-$date/my-backup.cnf: $!"; print FILE <<"(EOF)"; # This MySQL options file was generated by Mark's backup script. [mysqld] datadir=/storage/backups/backup-$date/sql innodb_data_home_dir=/storage/backups/backup-$date/sql innodb_data_file_path=$cfg{'innodb_data_file_path'} innodb_log_group_home_dir=/storage/backups/backup-$date/sql innodb_log_files_in_group=$cfg{'set-variable'}{'innodb_log_files_in_grou p'} innodb_log_file_size=$cfg{'innodb_log_file_size'} (EOF) close(FILE); ## Start the backup... my $pid = undef; if (defined($pid = fork)) { if ($pid) { # parent process $ibbackup_pid = $pid; } else { # child process print "Child process started\n"; print "Command: ibbackup --suspend-at-end --compress /etc/my.cnf /storage/backups/backup-$date/my-backup.cnf\n"; exec("ibbackup --suspend-at-end --compress /etc/my.cnf /storage/backups/backup-$date/my-backup.cnf") || die "Failed to exec ibbackup: $!"; } } else { die "failed to fork ibbackup child process: $!"; } print "Waiting for child to create /storage/backups/backup-$date/sql/ibbackup_suspended\n"; while(1) { sleep 5; $dbh->do("SELECT UNIX_TIMESTAMP()"); last if -e "/storage/backups/backup-$date/sql/ibbackup_suspended"; } print "Starting backup of MyISAM tables\n"; ## ibbackup is waiting for us to get rid of the suspended file. ## start backing up the files. print "Locking tables\n"; $dbh->do("DROP TABLE IF EXISTS ibbackup_binlog_marker"); $dbh->do("CREATE TABLE ibbackup_binlog_marker(a INT) TYPE=INNODB"); $dbh->{AutoCommit} = 0; $dbh->do("INSERT INTO ibbackup_binlog_marker VALUES (1)"); $dbh->do("FLUSH TABLES WITH READ LOCK"); $dbh->commit(); opendir(DIR,$cfg{'datadir'}) || die "can't open directory: $!"; while (my $f = readdir(DIR)) { next if (!-d "$cfg{'datadir'}/$f" || $f =~ /^\.{1,2}$/); mkdir("/storage/backups/backup-$date/sql/$f") || die "couldn't create folder: /storage/backups/backup-$date/$f : $!"; my @list = glob("$cfg{'datadir'}/$f/*.{frm,MYD}"); my @listidx = glob("$cfg{'datadir'}/$f/*.MYI"); for (@list) { $dbh->do("SELECT UNIX_TIMESTAMP()"); print "Copying $_\n"; copy("$_","/storage/backups/backup-$date$_") || die "couldn't copy file $_: $!"; } for (@listidx) { print "Copying INDEX $_\n"; $dbh->do("SELECT UNIX_TIMESTAMP()"); open(FIDX,"<$_") || die "couldn't open index... ack!"; my $buff; my $length = read(FIDX,$buff,2048); #die "Can't read index header from $_\n" if ($length < 1024); close(FIDX); open(FIDX,">/storage/backups/backup-$date$_") || die "couldn't open file for copy: $_: $!"; if (syswrite(FIDX,$buff) != length($buff)) { die "Error when writing data to /storage/backups/backup-$date$_: $!\n"; } close FIDX || die "Error on close of /storage/backups/backup-$date$_: $!\n"; } } closedir(DIR); print "Removing /storage/backups/backup-$date/sql/ibbackup_suspended\n"; unlink("/storage/backups/backup-$date/sql/ibbackup_suspended"); print "Waiting for ibbackup to finish\n"; waitpid($ibbackup_pid,0); print "Unlocking tables\n"; $dbh->do("UNLOCK TABLES"); $dbh->do("DROP TABLE IF EXISTS ibbackup_binlog_marker"); $dbh->disconnect; print "Compressing the backup\n"; ## Tar the backup `tar cfz /storage/backups/sql-backup-$date.tar.gz /storage/backups/backup-$date`; print "Removing the backup folder\n"; ## Remove the folder `rm -rf /storage/backups/backup-$date`; print "Removing backup from 2 days ago\n"; ## Remove the 2 day old backup ($d,$m,$y) = (localtime(time()-60*60*24*2))[3..5]; $date = sprintf("%d-%02d-%02d",$y+1900,$m+1,$d); unlink("/storage/backups/sql-backup-$date.tar.gz"); ## END This script uses the ibbackup tool from innodb (non-free) to take a hot backup of the innodb tables, then near the end of the innodb backup,ibbackup waits for a backup to be taken of the MyISAM tables and table definitions (lock tables with read lock, copy the *.FRM, *.MYI, *.MYD files, unlock). Once the MyISAM tables and table definitions are backed up, ibbackup resumes and theoretically I _should_ have a consistent backup of the whole database server once ibbackup is finished. (although I truncate the MyISAM index files, but they can be reconstructed with myisamchk -r) My question is, suppose I would like to use one of these backups to create a new slave server, what additional information would I need to include in the backup to be able to start up a new slave properly? (relay logs/info files, etc...) Ideally, I would like these snapshots to be taken off the running server while it is in use, is there any way to do this? Regards, Mark Steele Implementation Director CDT Inc. [EMAIL PROTECTED] PS: the perl code is sloppy and needs more error checking,etc... use at your own risk. -- MySQL General Mailing List For list archives: http://lists.mysql.com/mysql To unsubscribe: http://lists.mysql.com/[EMAIL PROTECTED]