Incremental DB Backup Scripts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Incremental DB Backup Script. | |
* | |
* Requires: innobackupex percona script. | |
* | |
* Meant to run via cron, every 8 hours. It assumes during the fourth | |
* invocation a day has gone by. | |
* | |
* @author Kingcat <kingcat@nzb.cat> | |
* @last_modified 3/19/2016 | |
* | |
* @notes This script has no deps on nZEDb so it can be placed anywhere. | |
*/ | |
/** | |
* Inside this directory it will create the base backup in the ./base directory, | |
* the first incremental in the ./hourly.1 directory and so forth until ./hourly.3. | |
* At that point it will rotate the backups, applying all incrementals to the base, | |
* tarring and gzipping the base directory, deleting the base and all the incrementals, | |
* and rerunning the base backup for the next iteration. | |
*/ | |
$backup_home = '/path/to/backups'; | |
//Below here not much needs to be modified, you may want to modify the "--parallel=4" flag | |
// if your hardware can't afford to run 4 threads during backup. | |
class DBBackup { | |
public $backup_home; | |
public $base_dir; | |
public $cmd = 'innobackupex'; | |
public $flags = [ | |
'basic' => '--parallel=4 --rsync', | |
'no_ts' => '--no-timestamp', | |
'incremental' => '--incremental', | |
'inc_basedir' => '--incremental-basedir=', | |
'inc_dir' => '--incremental-dir=', | |
'apply' => '--apply-log', | |
'redo' => '--redo-only' | |
]; | |
const CLEANUP_DAYS = 7; | |
public function __construct($backup_dir, $base_dir) { | |
if (is_writable($backup_dir)) { | |
$this->backup_home = $backup_dir; | |
} else { | |
throw new InvalidArgumentException(); | |
} | |
$this->base_dir = $base_dir; | |
} | |
public function prepareBackup($dir, $incremental=true, $redo_only=true) { | |
$cmd = sprintf('%s %s', $this->cmd, $this->flags['apply']); | |
if ($redo_only) | |
$cmd .= sprintf(' %s', $this->flags['redo']); | |
if ($incremental) { | |
$cmd .= sprintf(' %s %s%s', $this->base_dir,$this->flags['inc_dir'],$dir); | |
} else { | |
$cmd .= sprintf(' %s', $dir); | |
} | |
system($cmd, $return); | |
return $return; | |
} | |
public function rotateBackup($inc_dirs) { | |
$date = date('omd-His'); | |
$rotate_file = sprintf('%s/%s.tar.gz', $this->backup_home, $date); | |
$rotate_cmd = sprintf('cd %s && tar -czf %s ./', $this->base_dir, $rotate_file); | |
system($rotate_cmd, $return); | |
if ($return == 0) { | |
foreach ($inc_dirs as $dir) { | |
$rm_cmd = sprintf('rm -fr %s', $dir); | |
system($rm_cmd); | |
} | |
system("rm -fr $this->base_dir"); | |
} else { | |
throw new ErrorException('unable to rotate'); | |
} | |
} | |
public function incrementalBackup($basedir, $destdir) { | |
$cmd = sprintf('%s %s %s %s %s %s%s', | |
$this->cmd, | |
$this->flags['basic'], | |
$this->flags['no_ts'], | |
$this->flags['incremental'], | |
$destdir, | |
$this->flags['inc_basedir'], | |
$basedir | |
); | |
system($cmd, $return); | |
if ($return != 0) | |
throw new ErrorException('unable to complete incremental backup'); | |
} | |
public function doBaseBackup() { | |
$cmd = sprintf('%s %s %s %s', | |
$this->cmd, | |
$this->flags['basic'], | |
$this->flags['no_ts'], | |
$this->base_dir); | |
system($cmd, $return); | |
if ($return != 0) | |
throw new ErrorException('unable to complete base backup'); | |
} | |
public function cleanUp() { | |
$cmd = sprintf("find %s -name '*.tar.gz' -mtime +%s -delete", | |
$this->backup_home, | |
self::CLEANUP_DAYS); | |
system($cmd, $return); | |
if ($return != 0) | |
throw new ErrorException('unable to cleanup backup dir'); | |
} | |
} | |
$fourth_backup_dir = sprintf('%s/hourly.3', $backup_home); | |
$third_backup_dir = sprintf('%s/hourly.2', $backup_home); | |
$second_backup_dir = sprintf('%s/hourly.1', $backup_home); | |
$first_backup_dir = sprintf('%s/base', $backup_home); | |
$backup = new DBBackup($backup_home, $first_backup_dir); | |
if (file_exists($fourth_backup_dir)) { | |
if ($backup->prepareBackup($first_backup_dir, false) == 0) | |
if ($backup->prepareBackup($second_backup_dir) == 0) | |
if ($backup->prepareBackup($third_backup_dir) == 0) | |
if ($backup->prepareBackup($fourth_backup_dir, true, false) == 0) | |
if ($backup->prepareBackup($first_backup_dir, false, false) ==0) | |
$backup->rotateBackup([$second_backup_dir, $third_backup_dir, $fourth_backup_dir]); | |
echo "Rotate complete"; | |
} | |
if (file_exists($third_backup_dir)) { | |
$backup->incrementalBackup($third_backup_dir, $fourth_backup_dir); | |
echo "Third incremental backup complete"; | |
exit; | |
} | |
if (file_exists($second_backup_dir)) { | |
$backup->incrementalBackup($second_backup_dir, $third_backup_dir); | |
echo "Second incremental backup complete"; | |
exit; | |
} | |
if (file_exists($first_backup_dir)) { | |
$backup->incrementalBackup($first_backup_dir, $second_backup_dir); | |
$backup->cleanUp(); | |
echo "First incremental backup complete"; | |
exit; | |
} | |
$backup->doBaseBackup(); | |
echo "Base backup complete"; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment