/// <summary>
        ///
        /// </summary>
        /// <param name="backupItem"></param>
        /// <param name="restore"></param>
        /// <remarks>
        ///     <paramref name="restore"/> must have backup device already added
        /// </remarks>
        private void AddMoveFileInstructionsIfNeeded(BackupItem backupItem, Restore restore)
        {
            Check.DoRequireArgumentNotNull(restore, "restore");
            Check.DoCheckArgument(restore.Devices.Count > 0, "Restore instance must have backup device already added");

            if (backupItem.BackupType == BackupType.Full)
            {
                var databaseFilesInBackup = ReadDatabaseFileList(restore);
                foreach (var dbFile in databaseFilesInBackup)
                {
                    var targetDir        = dbFile.IsLog ? DefaultLogPath : DefaultDataPath;
                    var physicalFilePath = FindExistingDatabaseFile(dbFile.LogicalName, dbFile.IsLog);

                    if (string.IsNullOrEmpty(physicalFilePath))
                    {
                        // no such file in the existing database; maybe it was dropped
                        physicalFilePath = Path.Combine(targetDir, Path.GetFileName(dbFile.PhysicalName));
                        physicalFilePath = PickNewFileName(physicalFilePath);
                    }

                    Log.InfoFormat("Moving {0} to {1}", dbFile.LogicalName, physicalFilePath);

                    restore.RelocateFiles.Add(new RelocateFile(dbFile.LogicalName, physicalFilePath));
                }
            }
        }
Example #2
0
        public BackupFileHeader(FileInfo fileInfo, List <BackupItem> validItems)
        {
            Check.DoRequireArgumentNotNull(fileInfo, "fileInfo");
            Check.DoRequireArgumentNotNull(validItems, "validItems");
            Check.DoCheckArgument(validItems.Count > 0, "No valid backup items");

            FileInfo        = fileInfo;
            FirstBackupTime = validItems.First().BackupStartTime;
            LastBackupTime  = validItems[validItems.Count - 1].BackupStartTime;
            ValidItems      = new List <BackupItem>(validItems);
        }
Example #3
0
        public BackupFileCatalog(
            IBackupDirectoryNamingConvention namingConvention
            , string databaseBackupFolder)
        {
            Check.DoRequireArgumentNotNull(namingConvention, "namingConvention");
            Check.DoRequireArgumentNotNull(databaseBackupFolder, "databaseBackupFolder");

            NamingConvention        = namingConvention;
            DatabaseBackupDirectory = new DirectoryInfo(databaseBackupFolder);
            Check.DoCheckArgument(DatabaseBackupDirectory.Exists, () => string.Format("Backup folder {0} does not exist", databaseBackupFolder));

            _backupFileFolders = GetBackupFolders();
        }
Example #4
0
        public BackupFileFolderInfo(IBackupFileNamingConvention fileNamingConvention, DirectoryInfo directoryInfo, DateTime startTime, DateTime?endTime)
        {
            Check.DoRequireArgumentNotNull(fileNamingConvention, "fileNamingConvention");
            Check.DoRequireArgumentNotNull(directoryInfo, "directoryInfo");
            Check.DoCheckArgument(endTime > startTime, "Time period");

            DirectoryInfo = directoryInfo;
            StartTime     = startTime;

            PeriodEndDeclaredExplicitly = endTime.HasValue;
            EndTime = endTime.HasValue ? endTime.Value : directoryInfo.LastWriteTime;

            BackupFileNamingConvention = fileNamingConvention;
        }
Example #5
0
        /// <summary>
        ///     Constructor of immutable instance.
        /// </summary>
        /// <param name="backupType">
        ///     Type of backups contained in this file.
        /// </param>
        /// <param name="startTime">
        ///     Explicitly defined start of the period in which backups were written into the file. If null, the start time will be taken from creation time.
        /// </param>
        /// <param name="endTime">
        ///     Explicitly defined end of the period in which backups were written into the file.
        /// </param>
        /// <param name="fileInfo">
        /// </param>
        /// <remarks>
        ///     Note that <see cref="StartTime"/> will always have a value while <see cref="EndTime"/> may be null. This is because start time is more important and
        ///     must be figured out in any case while EndTime is not essential and only beneficial for optimization.
        ///     If simultaneous log and database backups are allowed, without end time we only need to start from first log prior to last database backup.
        ///     However, if there is no simultaneous backup, things are much easier and we can work without end time.
        ///     What happens if diff backup is marked with the hour when it is made and single daily log backup is marked with start of day timestamp?
        ///     Then we need end time or have to start from first log backup file prior to the database backup.
        /// </remarks>
        public BackupFileInfo(SupportedBackupType backupType, DateTime?startTime, DateTime?endTime, FileInfo fileInfo)
        {
            Check.DoRequireArgumentNotNull(fileInfo, "fileInfo");
            Check.DoCheckArgument(backupType != SupportedBackupType.None, "Invalid file type");

            BackupType = backupType;

            FileInfo = fileInfo;

            PeriodStartDeclaredExplicitly = startTime.HasValue;
            StartTime = startTime ?? fileInfo.CreationTime;

            PeriodEndDeclaredExplicitly = endTime.HasValue;
            EndTime = endTime ?? fileInfo.LastWriteTime;
        }
Example #6
0
        /// <summary>
        ///     Get reverse sequence of backup files which started before <paramref name="pointInTime"/>.
        /// </summary>
        /// <param name="pointInTime">
        ///     Point in time before which the database backup to be found must have started; null for latest.
        /// </param>
        /// <param name="backupType">
        ///     Type of backup files to find.
        /// </param>
        /// <returns>
        ///     Sequence ordered by file start time <see cref="BackupFileInfo.StartTime"/> descending.
        /// </returns>
        /// <remarks>
        ///     Note that database backup (diff or full) restores database to a point at which reading from data files while performing backup finished,
        ///     which is in general some time after the backup start time. Thus in order to restore precisely to a point in time within the time period when
        ///     database backup Bn was being performed, one must go back and restore previous database backup followed by log backups up to and including
        ///     the one taken after the Bn backup. This is the reason to expose this method rather than provide just a method to retrieve the sequence
        ///     of files to use for restoration. One must analyze the contents of the database backup (diff or full) in order to understand whether
        ///     one can restore to a point in time within that file's time period. If not suitable, one must go back and check previous backup.
        ///     Passing <see cref="BackupFileInfo.StartTime"/> the caller shall never get the same file back; thus it is possible to iterate backwards.
        /// </remarks>
        public IEnumerable <BackupFileInfo> GetReverseBackupSequence(DateTime?pointInTime, SupportedBackupType backupType)
        {
            Check.DoCheckArgument(backupType != SupportedBackupType.None);

            foreach (var folder in GetPriorFolderSequence(pointInTime))
            {
                var files = folder.AllFiles
                            .Where(f => f.BackupType == backupType)
                            .Where(f => !pointInTime.HasValue || f.StartTime < pointInTime.Value)
                            .OrderByDescending(f => f.StartTime);

                foreach (var file in files)
                {
                    yield return(file);
                }
            }
        }
Example #7
0
        /// <summary>
        ///     Add new backup type mapping.
        /// </summary>
        /// <param name="nameSuffix">
        ///     Suffix of backup files, including extension, case insensitive
        /// </param>
        /// <param name="backupType">
        ///     Backup type
        /// </param>
        /// <param name="timePeriodExtractor">
        ///     Object implementing extraction of relevant information from file name, such as time period.
        /// </param>
        public void AddType(string nameSuffix, SupportedBackupType backupType, ITimePeriodFromFilesystemNameExtractor timePeriodExtractor)
        {
            Check.DoRequireArgumentNotNull(nameSuffix, "nameSuffix");
            Check.DoRequireArgumentNotNull(timePeriodExtractor, "timePeriodExtractor");
            Check.DoCheckArgument(null == GetTypeInfo(backupType), string.Format("Parser for {0} already mapped", backupType));
            Check.DoCheckArgument(backupType != SupportedBackupType.None, "Invalid backup type (None)");

            var intersectedType = _backupTypes.Values.Where(
                i => i.FileNameSuffix.EndsWith(nameSuffix, StringComparison.InvariantCultureIgnoreCase) ||
                nameSuffix.EndsWith(i.FileNameSuffix, StringComparison.InvariantCultureIgnoreCase))
                                  .FirstOrDefault();

            Check.DoCheckArgument(
                intersectedType == null
                , () => string.Format("Suffix {0} for {1} conflicts with suffix {2} for type {3}"
                                      , nameSuffix, backupType, intersectedType.FileNameSuffix, intersectedType.BackupType));

            var newTypeInfo = new BackupTypeInfo()
            {
                FileNameSuffix = nameSuffix, BackupType = backupType, TimePeriodExtractor = timePeriodExtractor
            };

            _backupTypes.Add(backupType, newTypeInfo);
        }