Skip to content

Instantly share code, notes, and snippets.

@simonwelsh
Created October 15, 2014 00:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save simonwelsh/ce75f7a627a15c3aec44 to your computer and use it in GitHub Desktop.
Save simonwelsh/ce75f7a627a15c3aec44 to your computer and use it in GitHub Desktop.
#!/usr/bin/php
<?php
function latest_base_lsn() {
exec('grep -H to_lsn /root/backup/base/*/xtrabackup_checkpoints', $options);
if (!$options) {
return null;
}
$options = array_map(function($opt) {
preg_match('#/(\d+)/.+= (\d+)#', $opt, $matches);
return array('date' => $matches[1], 'lsn' => $matches[2]);
}, $options);
usort($options, function($a, $b) {
if ($b['lsn'] === $a['lsn']) {
return $b['date'] - $a['date'];
}
return $b['lsn'] - $a['lsn'];
});
return $options[0];
}
function get_next_lsn($current, $date) {
$dir = '/root/backup/increment/' . $current . '-' . $date;
assert(file_exists($dir) && is_dir($dir));
$file = $dir . '/xtrabackup_checkpoints';
assert(file_exists($file));
$settings = parse_ini_file($file);
assert($settings['from_lsn'] == $current);
return $settings['to_lsn'];
}
function available_increments() {
$increments = array();
$dir = dir('/root/backup/increment');
while (false !== ($file = $dir->read())) {
if (preg_match('#^(\d+)-(\d{14})$#', $file, $match)) {
$date = $match[2];
$lsn = $match[1];
if (!isset($increments[$lsn]) || $increments[$lsn] < $date) {
$next = get_next_lsn($lsn, $date);
if ($next == $lsn) {
// Skip empty incremental backups
continue;
}
$increments[$lsn] = array('date' => $date, 'next' => $next);
}
}
}
$dir->close();
ksort($increments, SORT_NUMERIC);
return $increments;
}
function run_script($script) {
$script = escapeshellarg($script);
$command = "ssh root@localhost $script";
$ret = system($command, $code);
return array($ret, $code);
}
function prep_stream() {
$script = <<<SCRIPT
mkdir /tmp/restore
if [ $? -ne 0 ]
then
exit 1
fi
#service mysql stop
#rm -rf /var/lib/mysql/*
SCRIPT;
list(, $code) = run_script($script);
return !$code;
$script = escapeshellarg($script);
$command = "ssh root@localhost $script";
$ret = system($command, $var);
return !$var;
}
function cleanup() {
$script = <<<SCRIPT
rm -rf /tmp/restore
SCRIPT;
run_script($script);
}
function stream($path, $last, $base = false) {
echo "Will stream $path";
if ($base) echo " as base";
if ($last) echo " and finish preparing\n";
else echo " and do a partial prepare\n";
}
function restore() {
echo "Restoring.\n";
}
$base = latest_base_lsn();
if (!$base) {
echo 'No backups found.';
exit(1);
}
$increments = available_increments();
$toStream = array();
$lsn = $base['lsn'];
while (isset($increments[$lsn])) {
$inc = $increments[$lsn];
$toStream[] = '/root/backup/increment/' . $lsn . '-' . $inc['date'];
$lsn = $inc['next'];
}
if (!prep_stream()) {
echo 'Unable to prepare for restore. ';
echo "Is another restore happening?\n";
exit(1);
}
// stream the base
stream('/root/backup/base/' . $base['date'], !$toStream, true);
// Stream everything else
while ($toStream) {
$path = array_shift($toStream);
stream($path, !$toStream);
}
// Do the restore
restore();
// Cleanup
cleanup();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment