/// <summary> /// The process for backing up a directory index is simple: /// a) create hard links to all the files in the lucene directory in a temp director /// that gives us the current snapshot, and protect us from Lucene's /// deleting files. /// b) copy the hard links to the destination directory /// c) delete the temp directory /// </summary> public void Execute(ProgressNotifier progressNotifier) { if (allowOverwrite) // clean destination folder; we want to do this as close as possible to the actual backup operation { IOExtensions.DeleteDirectory(destination); Directory.CreateDirectory(destination); } foreach (var file in Directory.EnumerateFiles(tempPath)) { Notify("Copying " + Path.GetFileName(file), BackupStatus.BackupMessageSeverity.Informational); var fullName = new FileInfo(file).FullName; FileCopy(file, Path.Combine(destination, Path.GetFileName(file)), fileToSize[fullName], progressNotifier); Notify("Copied " + Path.GetFileName(file), BackupStatus.BackupMessageSeverity.Informational); } try { IOExtensions.DeleteDirectory(tempPath); } catch (Exception e) //cannot delete, probably because there is a file being written there { logger.WarnException(string.Format("Could not delete {0}, will delete those on startup", tempPath), e); foreach (var file in Directory.EnumerateFiles(tempPath)) { MoveFileEx(file, null, MoveFileDelayUntilReboot); } MoveFileEx(tempPath, null, MoveFileDelayUntilReboot); } }
private void FileCopy(string src, string dest, long size, ProgressNotifier notifier, CancellationToken token) { var buffer = new byte[16 * 1024]; using (var srcStream = File.Open(src, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { if (File.Exists(dest)) { File.SetAttributes(dest, FileAttributes.Normal); } using (var destStream = File.Create(dest, buffer.Length)) { while (true) { token.ThrowIfCancellationRequested(); var read = srcStream.Read(buffer, 0, (int)Math.Min(buffer.Length, size)); notifier.UpdateProgress(read, Notify); if (read == 0) { break; } size -= read; destStream.Write(buffer, 0, read); } destStream.Flush(); } } }
/// <summary> /// The process for backing up a directory index is simple: /// a) create hard links to all the files in the lucene directory in a temp director /// that gives us the current snapshot, and protect us from Lucene's /// deleting files. /// b) copy the hard links to the destination directory /// c) delete the temp directory /// </summary> public void Execute(ProgressNotifier progressNotifier, CancellationToken token) { if (allowOverwrite) // clean destination folder; we want to do this as close as possible to the actual backup operation { IOExtensions.DeleteDirectory(destination); } EnsureDirectoryExists(destination); foreach (var file in Directory.EnumerateFiles(tempPath)) { token.ThrowIfCancellationRequested(); Notify("Copying " + Path.GetFileName(file), null, BackupStatus.BackupMessageSeverity.Informational); var fullName = new FileInfo(file).FullName; FileCopy(file, Path.Combine(destination, Path.GetFileName(file)), fileToSize[fullName], progressNotifier, token); Notify("Copied " + Path.GetFileName(file), null, BackupStatus.BackupMessageSeverity.Informational); } try { IOExtensions.DeleteDirectory(tempPath); } catch (Exception e) //cannot delete, probably because there is a file being written there { logger.WarnException(string.Format("Could not delete {0}, will delete those on startup", tempPath), e); foreach (var file in Directory.EnumerateFiles(tempPath)) { MoveFileEx(file, null, MoveFileDelayUntilReboot); } MoveFileEx(tempPath, null, MoveFileDelayUntilReboot); } }
public void Execute() { try { string incrementalTag = null; log.Info("Starting backup of '{0}' to '{1}'", backupSourceDirectory, backupDestinationDirectory); UpdateBackupStatus( string.Format("Started backup process. Backing up data to directory = '{0}'", backupDestinationDirectory), BackupStatus.BackupMessageSeverity.Informational); if (BackupAlreadyExists) // trying to backup to an existing backup folder { if (!incrementalBackup) throw new InvalidOperationException("Denying request to perform a full backup to an existing backup folder. Try doing an incremental backup instead."); while (true) { incrementalTag = SystemTime.UtcNow.ToString("Inc yyyy-MM-dd HH-mm-ss"); backupDestinationDirectory = Path.Combine(backupDestinationDirectory, incrementalTag); if (Directory.Exists(backupDestinationDirectory) == false) break; Thread.Sleep(100); // wait until the second changes, should only even happen in tests } } else { incrementalBackup = false; // destination wasn't detected as a backup folder, automatically revert to a full backup if incremental was specified } UpdateBackupStatus(string.Format("Backing up indexes.."), BackupStatus.BackupMessageSeverity.Informational); // Make sure we have an Indexes folder in the backup location if (!Directory.Exists(Path.Combine(backupDestinationDirectory, "Indexes"))) Directory.CreateDirectory(Path.Combine(backupDestinationDirectory, "Indexes")); var directoryBackups = new List<DirectoryBackup> { new DirectoryBackup(Path.Combine(backupSourceDirectory, "IndexDefinitions"), Path.Combine(backupDestinationDirectory, "IndexDefinitions"), Path.Combine(backupSourceDirectory, "Temp" + Guid.NewGuid().ToString("N")), incrementalBackup) }; database.IndexStorage.Backup(backupDestinationDirectory); var progressNotifier = new ProgressNotifier(); foreach (var directoryBackup in directoryBackups) { directoryBackup.Notify += UpdateBackupStatus; var backupSize = directoryBackup.Prepare(); progressNotifier.TotalBytes += backupSize; } foreach (var directoryBackup in directoryBackups) { directoryBackup.Execute(progressNotifier); } UpdateBackupStatus(string.Format("Finished indexes backup. Executing data backup.."), BackupStatus.BackupMessageSeverity.Informational); ExecuteBackup(backupDestinationDirectory, incrementalBackup); if (databaseDocument != null) File.WriteAllText(Path.Combine(backupDestinationDirectory, "Database.Document"), RavenJObject.FromObject(databaseDocument).ToString()); OperationFinished(); } catch (AggregateException e) { var ne = e.ExtractSingleInnerException(); log.ErrorException("Failed to complete backup", ne); UpdateBackupStatus("Failed to complete backup because: " + ne.Message, BackupStatus.BackupMessageSeverity.Error); } catch (Exception e) { log.ErrorException("Failed to complete backup", e); UpdateBackupStatus("Failed to complete backup because: " + e.Message, BackupStatus.BackupMessageSeverity.Error); } finally { CompleteBackup(); } }
private void FileCopy(string src, string dest, long size, ProgressNotifier notifier) { var buffer = new byte[16 * 1024]; var initialSize = size; using (var srcStream = File.Open(src,FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { if (File.Exists(dest)) File.SetAttributes(dest,FileAttributes.Normal); using (var destStream = File.Create(dest, buffer.Length)) { while (true) { var read = srcStream.Read(buffer, 0, (int)Math.Min(buffer.Length, size)); notifier.UpdateProgress(read, Notify); if (read == 0) break; size -= read; destStream.Write(buffer, 0, read); } destStream.Flush(); } } }
public void Execute() { try { log.Info("Starting backup of '{0}' to '{1}'", backupSourceDirectory, backupDestinationDirectory); UpdateBackupStatus( string.Format("Started backup process. Backing up data to directory = '{0}'", backupDestinationDirectory), null, BackupStatus.BackupMessageSeverity.Informational); EnsureBackupDestinationExists(); if (incrementalBackup) { var incrementalBackupState = Path.Combine(backupDestinationDirectory, Constants.IncrementalBackupState); if (File.Exists(incrementalBackupState)) { var state = RavenJObject.Parse(File.ReadAllText(incrementalBackupState)).JsonDeserialization<IncrementalBackupState>(); if(state.ResourceId != database.TransactionalStorage.Id) throw new InvalidOperationException(string.Format("Can't perform an incremental backup to a given folder because it already contains incremental backup data of different database. Existing incremental data origins from '{0}' database.", state.ResourceName)); } else { var state = new IncrementalBackupState() { ResourceId = database.TransactionalStorage.Id, ResourceName = database.Name ?? Constants.SystemDatabase }; File.WriteAllText(incrementalBackupState, RavenJObject.FromObject(state).ToString()); } if (CanPerformIncrementalBackup()) { backupDestinationDirectory = DirectoryForIncrementalBackup(); } else { incrementalBackup = false; // destination wasn't detected as a backup folder, automatically revert to a full backup if incremental was specified } } else if (BackupAlreadyExists) { throw new InvalidOperationException("Denying request to perform a full backup to an existing backup folder. Try doing an incremental backup instead."); } UpdateBackupStatus(string.Format("Backing up indexes.."), null, BackupStatus.BackupMessageSeverity.Informational); // Make sure we have an Indexes folder in the backup location if (!Directory.Exists(Path.Combine(backupDestinationDirectory, "Indexes"))) Directory.CreateDirectory(Path.Combine(backupDestinationDirectory, "Indexes")); var directoryBackups = new List<DirectoryBackup> { new DirectoryBackup(Path.Combine(backupSourceDirectory, "IndexDefinitions"), Path.Combine(backupDestinationDirectory, "IndexDefinitions"), Path.Combine(backupSourceDirectory, "Temp" + Guid.NewGuid().ToString("N")), incrementalBackup) }; database.IndexStorage.Backup(backupDestinationDirectory,null, UpdateBackupStatus); var progressNotifier = new ProgressNotifier(); foreach (var directoryBackup in directoryBackups) { directoryBackup.Notify += UpdateBackupStatus; var backupSize = directoryBackup.Prepare(); progressNotifier.TotalBytes += backupSize; } foreach (var directoryBackup in directoryBackups) { directoryBackup.Execute(progressNotifier); } UpdateBackupStatus(string.Format("Finished indexes backup. Executing data backup.."), null, BackupStatus.BackupMessageSeverity.Informational); ExecuteBackup(backupDestinationDirectory, incrementalBackup); if (databaseDocument != null) File.WriteAllText(Path.Combine(backupDestinationDirectory, Constants.DatabaseDocumentFilename), RavenJObject.FromObject(databaseDocument).ToString()); OperationFinished(); } catch (AggregateException e) { var ne = e.ExtractSingleInnerException(); log.ErrorException("Failed to complete backup", ne); UpdateBackupStatus("Failed to complete backup because: " + ne.Message, ne.ExceptionToString(null), BackupStatus.BackupMessageSeverity.Error); } catch (Exception e) { log.ErrorException("Failed to complete backup", e); UpdateBackupStatus("Failed to complete backup because: " + e.Message, e.ExceptionToString(null), BackupStatus.BackupMessageSeverity.Error); } finally { CompleteBackup(); } }