function getChild()
 {
     global $config;
     if (!is_numeric($this->id)) {
         throw new Exception('backupSnapshot->getChild: ' . "Error: The ID for this object is not an integer.");
     }
     $conn = dbConnection::getInstance($this->log);
     $sql = "SELECT backup_snapshot_id FROM backup_snapshots WHERE status='COMPLETED' AND parent_snapshot_id=" . $this->id;
     if (!($res = $conn->query($sql))) {
         throw new Exception('backupSnapshot->getChild: ' . "Error: Query: {$sql} \nFailed with MySQL Error: {$conn->error}");
     }
     if ($res->num_rows != 1) {
         throw new Exception('backupSnapshot->getChild: ' . "Error: Could not identify a single child of this backupSnapshot.");
     }
     $row = $res->fetch_array();
     $backupGetter = new backupSnapshotGetter();
     return $backupGetter->getById($row['backup_snapshot_id']);
 }
 function getBackupSnapshot()
 {
     $this->__validate();
     $info = $this->getInfo();
     $backupSnapshotGetter = new backupSnapshotGetter();
     $this->backupSnapshot = $backupSnapshotGetter->getById($info['backup_snapshot_id']);
     return $this->backupSnapshot;
 }
 function handleSnapshotActions($args)
 {
     global $config;
     if (!isset($args[2])) {
         // Just output some helpful info and exit
         echo "Error: Action missing.\n\n";
         $this->printSnapshotHelpText($args);
         return;
     }
     switch ($args[2]) {
         // Handle list
         case 'list':
             // If we just get a hostname, check to see if it only has one Scheduled Backup task
             if (isset($args[3]) && !isset($args[4])) {
                 $hostname = $args[3];
                 $hostGetter = new hostGetter();
                 $hostGetter->setLogStream($this->log);
                 if (!($host = $hostGetter->getByName($hostname))) {
                     throw new ProcessingException("Error: Could not find a host with hostname: {$hostname}");
                 }
                 $scheduledBackups = $host->getScheduledBackups();
                 // If we dont find scheduled backups - throw exception
                 if (sizeOf($scheduledBackups) == 0) {
                     throw new ProcessingException("Error: Could not find any backups for host: {$hostname}");
                 }
             }
             // If we are dealing with only one specific backup
             if (isset($args[3]) && isset($args[4])) {
                 $scheduledBackupGetter = new scheduledBackupGetter();
                 $scheduledBackupGetter->setLogStream($this->log);
                 $hostname = $args[3];
                 $backupName = $args[4];
                 $scheduledBackups = array();
                 if (!($scheduledBackups[0] = $scheduledBackupGetter->getByHostnameAndName($hostname, $backupName))) {
                     throw new ProcessingException("Error: Could not find a backup for host: {$hostname} with name: {$backupName}");
                 }
             }
             if (!isset($args[3]) && !isset($args[4])) {
                 throw new InputException("Error: Not all required parameters for the snapshots to list were given.\n\n" . "  Syntax:\n\n\txbm " . $args[1] . " list <hostname> [<backup_name>]\n\n" . "  Example:\n\n\txbm " . $args[1] . " list db01.mydomain.com 'Nightly Backup'\n\n");
             }
             echo "-- Listing Backup Snapshots for {$hostname} --\n\n";
             // By this point we should have an array scheduledBackups to display info for
             foreach ($scheduledBackups as $scheduledBackup) {
                 $sbInfo = $scheduledBackup->getInfo();
                 $groups = $scheduledBackup->getSnapshotGroupsNewestToOldest();
                 $strategy = $scheduledBackup->getBackupStrategy();
                 $strategyInfo = $strategy->getInfo();
                 echo " -- Snapshots for Backup Name: " . $sbInfo['name'] . "\n";
                 // Display materialized snapshot if enabled
                 $params = $scheduledBackup->getParameters();
                 if (isset($params['maintain_materialized_copy']) && $params['maintain_materialized_copy'] == 1) {
                     $materialized = $scheduledBackup->getMostRecentCompletedMaterializedSnapshot();
                     echo "\t-- Latest Materialized Snapshot:\n";
                     if ($materialized == false) {
                         echo "\t  None.\n";
                     } else {
                         $materializedInfo = $materialized->getInfo();
                         $mSnap = $materialized->getBackupSnapshot();
                         $mSnapInfo = $mSnap->getInfo();
                         echo "\t  ID: m" . $materializedInfo['materialized_snapshot_id'] . "  Snapshot Time: " . $mSnapInfo['snapshot_time'];
                         // Was going to display path here, but decided users should never know the path
                         // they should always use xbm commands for restores to ensure correct locking
                         //."  Path: ".$materialized->getPath()."\n");
                     }
                 }
                 // Display Snapshots (by group if ROTATING method is used)
                 $groupNum = 0;
                 foreach ($groups as $group) {
                     $groupNum++;
                     if ($strategyInfo['strategy_code'] == 'ROTATING') {
                         echo "\t-- Group: {$groupNum}\n";
                     }
                     $snapshots = $group->getAllSnapshotsNewestToOldest();
                     foreach ($snapshots as $snapshot) {
                         $snapInfo = $snapshot->getInfo();
                         echo "\t  ID: " . $snapInfo['backup_snapshot_id'] . "  Type: " . $snapInfo['type'] . "  Snapshot Time: " . $snapInfo['snapshot_time'] . "  Creation Method: " . $snapInfo['creation_method'] . "\n";
                     }
                     if (sizeOf($snapshots) == 0) {
                         echo "\t  None.\n";
                     }
                 }
             }
             echo "\n\n";
             break;
             // Handle restore
         // Handle restore
         case 'restore-latest':
             // If we just got a path and hostname,
             if (isset($args[3]) && isset($args[4]) && !isset($args[5])) {
                 $hostname = $args[4];
                 $targetPath = $args[3];
                 $hostGetter = new hostGetter();
                 $hostGetter->setLogStream($this->log);
                 if (!($host = $hostGetter->getByName($hostname))) {
                     throw new ProcessingException("Error: Could not find a host with hostname: {$hostname}");
                 }
                 $scheduledBackups = $host->getScheduledBackups();
                 // If we dont find scheduled backups - throw exception
                 if (sizeOf($scheduledBackups) == 0) {
                     throw new ProcessingException("Error: Could not find any backups for host: {$hostname}");
                 }
                 // If we find more than 1 scheduled backup - throw exception
                 if (sizeOf($scheduledBackups) > 1) {
                     throw new ProcessingException("Error: Found multiple Backup Tasks for host: {$hostname} - Please specify which backup name to restore the latest snapshot for.");
                 }
                 $scheduledBackup = $scheduledBackups[0];
             }
             // If we got a host AND backup name
             if (isset($args[3]) && isset($args[4]) && isset($args[5])) {
                 $targetPath = $args[3];
                 $hostname = $args[4];
                 $backupName = $args[5];
                 $scheduledBackupGetter = new scheduledBackupGetter();
                 $scheduledBackupGetter->setLogStream($this->log);
                 if (!($scheduledBackup = $scheduledBackupGetter->getByHostnameAndName($hostname, $backupName))) {
                     throw new ProcessingException("Error: Could not find a Scheduled Backup Task for host: {$hostname} with name: {$backupName}");
                 }
             }
             if (!isset($args[3]) || !isset($args[4])) {
                 throw new InputException("Error: Not all required parameters for the Scheduled Backup you wish to restore the latest snapshot for were given.\n\n" . "  Syntax:\n\n\txbm " . $args[1] . " restore-latest <target_path> <hostname> [<backup_name>]\n\n" . "  Example:\n\n\txbm " . $args[1] . " restore-latest /restores/myrestore db01.mydomain.com 'Nightly Backup'\n\n");
             }
             $sbInfo = $scheduledBackup->getInfo();
             // Check if we have any COMPLETED snapshots anyway
             $snapCount = $scheduledBackup->getCompletedSnapshotCount();
             if ($snapCount < 1) {
                 throw new ProcessingException("Error: No snapshots exist for the Scheduled Backup Task with name: " . $sbInfo['name'] . " for host: {$hostname}");
             }
             // We have a scheduledBackup - figure out if we might have a materialized snapshot and work accordingly
             $params = $scheduledBackup->getParameters();
             $snapshot = false;
             if ($params['maintain_materialized_copy'] == 1) {
                 // Is there a materialized snapshot?
                 $snapshot = $scheduledBackup->getMostRecentCompletedMaterializedSnapshot();
             }
             // If not, lets try finding the most recent snapshot for this scheduledBackup
             if ($snapshot == false) {
                 $snapshot = $scheduledBackup->getMostRecentCompletedBackupSnapshot();
             }
             // At this point we either have a materialized snapshot or regular snapshot in $snapshot
             // Lets proceed with restoring...
             $this->handleRestore($snapshot, $targetPath);
             break;
         case 'restore':
             if (isset($args[3]) && isset($args[4])) {
                 // Handle the valid snapshot id inputs that we know
                 // Numeric - regular snapshot
                 if (is_numeric($args[4])) {
                     $backupSnapshotGetter = new backupSnapshotGetter();
                     $backupSnapshotGetter->setLogStream($this->log);
                     if (!($snapshot = $backupSnapshotGetter->getById($args[4]))) {
                         throw new ProcessingException("Error: Could not find a Backup Snapshot with ID: " . $args[4]);
                     }
                     // Materialized snapshot
                 } elseif (substr($args[4], 0, 1) == 'm' && is_numeric(substr($args[4], 1))) {
                     $materialId = substr($args[4], 1);
                     $materializedSnapshotGetter = new materializedSnapshotGetter();
                     $materializedSnapshotGetter->setLogStream($this->log);
                     if (!($snapshot = $materializedSnapshotGetter->getById($materialId))) {
                         throw new ProcessingException("Error: Could not find a materialized Backup Snapshot with ID: " . $args[4]);
                     }
                     // Catch all for when the input snapshot id is not recognized...
                     // it should have been one of the following:
                     // letter m, followed by numeric ID - eg. m12 - m signifies a materialized snapshot
                     // just a numeric id - eg. 12 - no letter m prepended signifies a regular snapshot
                 } else {
                     throw new InputException("Error: The Snapshot ID specified must be of any of these forms: 12, m12 (m denotes a Materialized Snapshot ID)\n\n" . "  Syntax:\n\n\txbm " . $args[1] . " restore <snapshot_id> <target_path>\n\n" . "  Example:\n\n\txbm " . $args[1] . " restore m21 /restores/myrestore\n\n");
                 }
                 $snapInfo = $snapshot->getInfo();
                 if ($snapInfo['status'] != 'COMPLETED') {
                     throw new ProcessingException("Error: The snapshot specified is in " . $snapInfo['status'] . " status. Only COMPLETED snapshots can be restored.");
                 }
                 $this->handleRestore($snapshot, $args[3]);
             } else {
                 throw new InputException("Error: Not all required parameters for the restore action were given.\n\n" . "  Syntax:\n\n\txbm " . $args[1] . " restore <snapshot_idt> <target_path>\n\n" . "  Example:\n\n\txbm " . $args[1] . " restore m21 /restores/myrestore\n\n");
             }
             break;
             // Catch unknown action
         // Catch unknown action
         default:
             echo "Error: Unrecognized action for " . $args[1] . " context: " . $args[2] . "\n\n";
             $this->printSnapshotHelpText($args);
             break;
     }
 }
 function getMostRecentCompletedBackupSnapshot()
 {
     global $config;
     if (!is_numeric($this->id)) {
         throw new Exception('scheduledBackup->getMostRecentCompletedBackupSnapshot: ' . "Error: The ID for this object is not an integer.");
     }
     $conn = dbConnection::getInstance($this->log);
     $sql = "SELECT backup_snapshot_id FROM backup_snapshots WHERE status='COMPLETED' AND scheduled_backup_id=" . $this->id . " ORDER BY snapshot_time DESC LIMIT 1";
     if (!($res = $conn->query($sql))) {
         throw new Exception('scheduledBackup->getMostRecentCompletedBackupSnapshot: ' . "Error: Query: {$sql} \nFailed with MySQL Error: {$conn->error}");
     }
     if ($res->num_rows != 1) {
         throw new Exception('scheduledBackup->getMostRecentCompletedBackupSnapshot: ' . "Error: Could not find the most recent backup snapshot for Scheduled Backup ID " . $this->id);
     }
     $row = $res->fetch_array();
     $snapshotGetter = new backupSnapshotGetter();
     $snapshot = $snapshotGetter->getById($row['backup_snapshot_id']);
     return $snapshot;
 }
 function getAllSnapshotsNewestToOldest()
 {
     $this->__validate();
     global $config;
     $conn = dbConnection::getInstance($this->log);
     $sql = "SELECT backup_snapshot_id FROM backup_snapshots WHERE status='COMPLETED' AND scheduled_backup_id=" . $this->scheduledBackupId . " \n\t\t\t\t\tAND snapshot_group_num=" . $this->snapshotGroupNum . " ORDER BY snapshot_time DESC";
     if (!($res = $conn->query($sql))) {
         throw new Exception('backupSnapshotGroup->getAllSnapshotsNewestToOldest: ' . "Error: Query: {$sql} \nFailed with MySQL Error: {$conn->error}");
     }
     $snapshots = array();
     while ($row = $res->fetch_array()) {
         $snapshotGetter = new backupSnapshotGetter();
         $snapshots[] = $snapshotGetter->getById($row['backup_snapshot_id']);
     }
     return $snapshots;
 }
 function applyRetentionPolicy(backupJob $job)
 {
     global $config;
     $scheduledBackup = $job->getScheduledBackup();
     $this->infolog->write("Checking to see if any snapshots need to be merged into the seed backup.", XBM_LOG_INFO);
     if (!is_object($scheduledBackup)) {
         throw new Exception('continuousIncrementalBackupTaker->applyRetentionPolicy: ' . "Error: This function requires a scheduledBackup object as a parameter.");
     }
     $conn = dbConnection::getInstance($this->log);
     $sql = "SELECT backup_snapshot_id FROM backup_snapshots WHERE status='COMPLETED' AND scheduled_backup_id=" . $scheduledBackup->id . " AND snapshot_time IS NOT NULL ORDER BY snapshot_time ASC";
     if (!($res = $conn->query($sql))) {
         throw new Exception('continuousIncrementalBackupTaker->applyRetentionPolicy: ' . "Error: Query: {$sql} \nFailed with MySQL Error: {$conn->error}");
     }
     // Get info for this scheduledBackup
     $info = $scheduledBackup->getInfo();
     // Get the params/options for this scheduledBackup
     $params = $scheduledBackup->getParameters();
     // Validate them
     $this->validateParams($params);
     // Build service objects for later use
     $snapshotGetter = new backupSnapshotGetter();
     $snapshotMerger = new backupSnapshotMerger();
     // Check to see if the number of rows we have is more than the number of snapshots we should have at a max
     while ($res->num_rows > $params['max_snapshots']) {
         // Grab the first row - it is the SEED
         if (!($row = $res->fetch_array())) {
             throw new Exception('continuousIncrementalBackupTaker->applyRetentionPolicy: ' . "Error: Could not retrieve the object ID for the seed of Scheduled Backup ID " . $scheduledBackup->id);
         }
         $seedSnapshot = $snapshotGetter->getById($row['backup_snapshot_id']);
         // Grab the second row - it is the DELTA to be collapsed.
         if (!($row = $res->fetch_array())) {
             throw new Exception('continuousIncrementalBackupTaker->applyRetentionPolicy: ' . "Error: Could not retrieve the object ID for the seed of Scheduled Backup ID " . $scheduledBackup->id);
         }
         $deltaSnapshot = $snapshotGetter->getById($row['backup_snapshot_id']);
         $this->infolog->write("Merging deltas in Backup Snapshot ID #" . $deltaSnapshot->id . " with Backup Snapshot ID #" . $seedSnapshot->id . ".", XBM_LOG_INFO);
         // Merge them together
         $snapshotMerger->mergeSnapshots($seedSnapshot, $deltaSnapshot);
         // Check to see what merge work is needed now.
         $sql = "SELECT backup_snapshot_id FROM backup_snapshots WHERE status='COMPLETED' AND scheduled_backup_id=" . $scheduledBackup->id . " AND snapshot_time IS NOT NULL ORDER BY snapshot_time ASC";
         if (!($res = $conn->query($sql))) {
             throw new Exception('continuousIncrementalBackupTaker->applyRetentionPolicy: ' . "Error: Query: {$sql} \nFailed with MySQL Error: {$conn->error}");
         }
     }
     return true;
 }