From 07d4ed335b9b9f60a5bc112b752a702eca1eca47 Mon Sep 17 00:00:00 2001 From: Aditya Niraula Date: Tue, 3 May 2022 17:07:18 +0100 Subject: [PATCH 1/3] fix(backup-chain): next log backup can have the same `LastLsn` --- src/BackupChain.cs | 122 ++++++++++++++++++++++----------------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/src/BackupChain.cs b/src/BackupChain.cs index 8584f49..c4547b3 100755 --- a/src/BackupChain.cs +++ b/src/BackupChain.cs @@ -1,11 +1,11 @@ -namespace AgDatabaseMove -{ - using System.Collections.Generic; - using System.Linq; - using Exceptions; - using SmoFacade; - - +namespace AgDatabaseMove +{ + using System.Collections.Generic; + using System.Linq; + using Exceptions; + using SmoFacade; + + public interface IBackupChain { IEnumerable OrderedBackups { get; } @@ -14,11 +14,11 @@ public interface IBackupChain /// /// Encapsulates the logic for determining the order to apply recent backups. /// - public class BackupChain : IBackupChain - { - private readonly IList _orderedBackups; - - // This also handles any striped backups + public class BackupChain : IBackupChain + { + private readonly IList _orderedBackups; + + // This also handles any striped backups private BackupChain(IList recentBackups) { if(recentBackups == null || recentBackups.Count == 0) @@ -54,51 +54,51 @@ public BackupChain(Database database) : this(database.MostRecentBackupChain()) { /// /// Backups ordered to have a full restore chain. /// - public IEnumerable OrderedBackups => _orderedBackups; - - private static IEnumerable MostRecentFullBackup(IEnumerable backups) - { - var fullBackupsOrdered = backups - .Where(b => b.BackupType == BackupFileTools.BackupType.Full) - .OrderByDescending(d => d.CheckpointLsn).ToList(); - - if(!fullBackupsOrdered.Any()) - throw new BackupChainException("Could not find any full backups"); - - var targetCheckpointLsn = fullBackupsOrdered.First().CheckpointLsn; - // get all the stripes of this backup - return fullBackupsOrdered.Where(fullBackup => fullBackup.CheckpointLsn == targetCheckpointLsn); - } - - private static IEnumerable MostRecentDiffBackup(IEnumerable backups, - BackupMetadata lastFullBackup) - { - var diffBackupsOrdered = backups - .Where(b => - b.BackupType == BackupFileTools.BackupType.Diff && - b.DatabaseBackupLsn == lastFullBackup.CheckpointLsn) - .OrderByDescending(b => b.LastLsn).ToList(); - - if(!diffBackupsOrdered.Any()) - return new List(); - - var targetLastLsn = diffBackupsOrdered.First().LastLsn; - // get all the stripes of this backup - return diffBackupsOrdered.Where(diffBackup => diffBackup.LastLsn == targetLastLsn); - } - - private static IEnumerable NextLogBackup(IEnumerable backups, - BackupMetadata prevBackup) - { - // also gets all the stripes of the next backup - return backups.Where(b => b.BackupType == BackupFileTools.BackupType.Log && - prevBackup.LastLsn >= b.FirstLsn && prevBackup.LastLsn + 1 < b.LastLsn); - } - - private static bool IsValidFilePath(BackupMetadata meta) - { - var path = meta.PhysicalDeviceName; - return BackupFileTools.IsValidFileUrl(path) || BackupFileTools.IsValidFilePath(path); - } - } -} \ No newline at end of file + public IEnumerable OrderedBackups => _orderedBackups; + + private static IEnumerable MostRecentFullBackup(IEnumerable backups) + { + var fullBackupsOrdered = backups + .Where(b => b.BackupType == BackupFileTools.BackupType.Full) + .OrderByDescending(d => d.CheckpointLsn).ToList(); + + if(!fullBackupsOrdered.Any()) + throw new BackupChainException("Could not find any full backups"); + + var targetCheckpointLsn = fullBackupsOrdered.First().CheckpointLsn; + // get all the stripes of this backup + return fullBackupsOrdered.Where(fullBackup => fullBackup.CheckpointLsn == targetCheckpointLsn); + } + + private static IEnumerable MostRecentDiffBackup(IEnumerable backups, + BackupMetadata lastFullBackup) + { + var diffBackupsOrdered = backups + .Where(b => + b.BackupType == BackupFileTools.BackupType.Diff && + b.DatabaseBackupLsn == lastFullBackup.CheckpointLsn) + .OrderByDescending(b => b.LastLsn).ToList(); + + if(!diffBackupsOrdered.Any()) + return new List(); + + var targetLastLsn = diffBackupsOrdered.First().LastLsn; + // get all the stripes of this backup + return diffBackupsOrdered.Where(diffBackup => diffBackup.LastLsn == targetLastLsn); + } + + private static IEnumerable NextLogBackup(IEnumerable backups, + BackupMetadata prevBackup) + { + // also gets all the stripes of the next backup + return backups.Where(b => b.BackupType == BackupFileTools.BackupType.Log && + prevBackup.LastLsn >= b.FirstLsn && prevBackup.LastLsn <= b.LastLsn); + } + + private static bool IsValidFilePath(BackupMetadata meta) + { + var path = meta.PhysicalDeviceName; + return BackupFileTools.IsValidFileUrl(path) || BackupFileTools.IsValidFilePath(path); + } + } +} From da3082a60efa2b3759facac51a6f770af21ffa3a Mon Sep 17 00:00:00 2001 From: Aditya Niraula Date: Thu, 5 May 2022 13:36:05 +0100 Subject: [PATCH 2/3] fix(backup-chain): infinite loop when getting next log backup --- src/BackupChain.cs | 4 +++- src/BackupMetadata.cs | 30 ++++++++++++++++++++++-------- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/BackupChain.cs b/src/BackupChain.cs index c4547b3..7155894 100755 --- a/src/BackupChain.cs +++ b/src/BackupChain.cs @@ -92,7 +92,9 @@ private static IEnumerable NextLogBackup(IEnumerable b.BackupType == BackupFileTools.BackupType.Log && - prevBackup.LastLsn >= b.FirstLsn && prevBackup.LastLsn <= b.LastLsn); + prevBackup.LastLsn >= b.FirstLsn && + prevBackup.LastLsn <= b.LastLsn && + !new BackupEqualityComparer().Equals(prevBackup, b)); } private static bool IsValidFilePath(BackupMetadata meta) diff --git a/src/BackupMetadata.cs b/src/BackupMetadata.cs index 5253f57..f2c9f37 100755 --- a/src/BackupMetadata.cs +++ b/src/BackupMetadata.cs @@ -5,12 +5,7 @@ namespace AgDatabaseMove using SmoFacade; - /// - /// Occasionally we wind up with the same entry for a backup on multiple instance's msdb. - /// For now we'll consider these backups to be equal despite their file location, - /// but perhaps there's value in being able to look for the file in multiple locations. - /// - public class BackupMetadataEqualityComparer : IEqualityComparer + public class BackupEqualityComparer : IEqualityComparer { public bool Equals(BackupMetadata x, BackupMetadata y) { @@ -18,18 +13,37 @@ public bool Equals(BackupMetadata x, BackupMetadata y) x.FirstLsn == y.FirstLsn && x.BackupType == y.BackupType && x.DatabaseName == y.DatabaseName && - x.PhysicalDeviceName == y.PhysicalDeviceName; + x.CheckpointLsn == y.CheckpointLsn && + x.DatabaseBackupLsn == x.DatabaseBackupLsn; } public int GetHashCode(BackupMetadata obj) { var hashCode = -1277603921; hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(obj.DatabaseName); - hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(obj.PhysicalDeviceName); hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(obj.BackupType); hashCode = hashCode * -1521134295 + obj.FirstLsn.GetHashCode(); hashCode = hashCode * -1521134295 + obj.LastLsn.GetHashCode(); + hashCode = hashCode * -1521134295 + obj.CheckpointLsn.GetHashCode(); + hashCode = hashCode * -1521134295 + obj.DatabaseBackupLsn.GetHashCode(); + return hashCode; + } + } + + public class BackupMetadataEqualityComparer : IEqualityComparer + { + public bool Equals(BackupMetadata x, BackupMetadata y) + { + return new BackupEqualityComparer() + .Equals(x, y) + && x.PhysicalDeviceName == y.PhysicalDeviceName; + } + + public int GetHashCode(BackupMetadata obj) + { + var hashCode = new BackupEqualityComparer().GetHashCode(obj); + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(obj.PhysicalDeviceName); return hashCode; } } From 3356fe15cc7bf89bb9a948626f8de9ea23a2c318 Mon Sep 17 00:00:00 2001 From: Aditya Niraula Date: Thu, 5 May 2022 17:37:30 +0100 Subject: [PATCH 3/3] refactor(backup chain): Combining the comparators into the same class --- src/BackupChain.cs | 2 +- src/BackupMetadata.cs | 37 +++++++++++++++++-------------------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/BackupChain.cs b/src/BackupChain.cs index 7155894..d182112 100755 --- a/src/BackupChain.cs +++ b/src/BackupChain.cs @@ -94,7 +94,7 @@ private static IEnumerable NextLogBackup(IEnumerable b.BackupType == BackupFileTools.BackupType.Log && prevBackup.LastLsn >= b.FirstLsn && prevBackup.LastLsn <= b.LastLsn && - !new BackupEqualityComparer().Equals(prevBackup, b)); + !new BackupMetadataEqualityComparer().EqualsExceptForPhysicalDeviceName(prevBackup, b)); } private static bool IsValidFilePath(BackupMetadata meta) diff --git a/src/BackupMetadata.cs b/src/BackupMetadata.cs index f2c9f37..375e547 100755 --- a/src/BackupMetadata.cs +++ b/src/BackupMetadata.cs @@ -4,10 +4,13 @@ namespace AgDatabaseMove using System.Collections.Generic; using SmoFacade; - - public class BackupEqualityComparer : IEqualityComparer + public class BackupMetadataEqualityComparer : IEqualityComparer { - public bool Equals(BackupMetadata x, BackupMetadata y) + /// + /// This is used for checking similar backups (like striped backups) + /// + /// bool + public bool EqualsExceptForPhysicalDeviceName(BackupMetadata x, BackupMetadata y) { return x.LastLsn == y.LastLsn && x.FirstLsn == y.FirstLsn && @@ -17,10 +20,21 @@ public bool Equals(BackupMetadata x, BackupMetadata y) x.DatabaseBackupLsn == x.DatabaseBackupLsn; } + /// + /// This is used for checking exactly the same backup (like finding duplicates) + /// + /// bool + public bool Equals(BackupMetadata x, BackupMetadata y) + { + return EqualsExceptForPhysicalDeviceName(x, y) + && x.PhysicalDeviceName == y.PhysicalDeviceName; + } + public int GetHashCode(BackupMetadata obj) { var hashCode = -1277603921; hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(obj.DatabaseName); + hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(obj.PhysicalDeviceName); hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(obj.BackupType); hashCode = hashCode * -1521134295 + obj.FirstLsn.GetHashCode(); @@ -31,23 +45,6 @@ public int GetHashCode(BackupMetadata obj) } } - public class BackupMetadataEqualityComparer : IEqualityComparer - { - public bool Equals(BackupMetadata x, BackupMetadata y) - { - return new BackupEqualityComparer() - .Equals(x, y) - && x.PhysicalDeviceName == y.PhysicalDeviceName; - } - - public int GetHashCode(BackupMetadata obj) - { - var hashCode = new BackupEqualityComparer().GetHashCode(obj); - hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(obj.PhysicalDeviceName); - return hashCode; - } - } - /// /// Metadata about backups from msdb.dbo.backupset and msdb.dbo.backupmediafamily ///