Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 364f8fa

Browse files
Merge pull request dataplat#3874 from sqlcollaborative/diffcontinue
Diff continuing restores, and better coping with multiple databases during continues merging now it's been approved.
2 parents 385fc6d + 165c3b9 commit 364f8fa

File tree

5 files changed

+206
-42
lines changed

5 files changed

+206
-42
lines changed

‎functions/Restore-DbaDatabase.ps1

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -458,9 +458,9 @@ function Restore-DbaDatabase {
458458
return
459459
}
460460
if ($Continue) {
461+
Write-Message -Message "Called with continue, so assume we have an existing db in norecovery"
461462
$ContinuePoints = Get-RestoreContinuableDatabase -SqlInstance $RestoreInstance
462-
#$WithReplace = $true
463-
#$ContinuePoints
463+
$LastRestoreType = Get-DbaRestoreHistory -SqlInstance $RestoreInstance -Last
464464
}
465465
if (!($PSBoundParameters.ContainsKey("DataBasename"))) {
466466
$PipeDatabaseName = $true
@@ -612,8 +612,17 @@ function Restore-DbaDatabase {
612612
if ($StopAfterGetBackupInformation) {
613613
return
614614
}
615+
616+
$null = $BackupHistory | Format-DbaBackupInformation -DataFileDirectory $DestinationDataDirectory -LogFileDirectory $DestinationLogDirectory -DestinationFileStreamDirectory $DestinationFileStreamDirectory -DatabaseFileSuffix $DestinationFileSuffix -DatabaseFilePrefix $DestinationFilePrefix -DatabaseNamePrefix $RestoredDatabaseNamePrefix -ReplaceDatabaseName $DatabaseName -Continue:$Continue -ReplaceDbNameInFile:$ReplaceDbNameInFile -FileMapping $FileMapping
615617

616-
$FilteredBackupHistory = $BackupHistory | Select-DbaBackupInformation -RestoreTime $RestoreTime -IgnoreLogs:$IgnoreLogBackups -ContinuePoints $ContinuePoints
618+
if (Test-Bound -ParameterName FormatBackupInformation) {
619+
Set-Variable -Name $FormatBackupInformation -Value $BackupHistory -Scope Global
620+
}
621+
if ($StopAfterFormatBackupInformation) {
622+
return
623+
}
624+
625+
$FilteredBackupHistory = $BackupHistory | Select-DbaBackupInformation -RestoreTime $RestoreTime -IgnoreLogs:$IgnoreLogBackups -ContinuePoints $ContinuePoints -LastRestoreType $LastRestoreType -DatabaseName $DatabaseName
617626

618627
if (Test-Bound -ParameterName SelectBackupInformation) {
619628
Write-Message -Message "Setting $SelectBackupInformation to FilteredBackupHistory" -Level Verbose
@@ -624,15 +633,6 @@ function Restore-DbaDatabase {
624633
return
625634
}
626635

627-
$null = $FilteredBackupHistory | Format-DbaBackupInformation -DataFileDirectory $DestinationDataDirectory -LogFileDirectory $DestinationLogDirectory -DestinationFileStreamDirectory $DestinationFileStreamDirectory -DatabaseFileSuffix $DestinationFileSuffix -DatabaseFilePrefix $DestinationFilePrefix -DatabaseNamePrefix $RestoredDatabaseNamePrefix -ReplaceDatabaseName $DatabaseName -Continue:$Continue -ReplaceDbNameInFile:$ReplaceDbNameInFile -FileMapping $FileMapping
628-
629-
if (Test-Bound -ParameterName FormatBackupInformation) {
630-
Set-Variable -Name $FormatBackupInformation -Value $FilteredBackupHistory -Scope Global
631-
}
632-
if ($StopAfterFormatBackupInformation) {
633-
return
634-
}
635-
636636
try {
637637
Write-Message -Level Verbose -Message "VerifyOnly = $VerifyOnly"
638638
$null = $FilteredBackupHistory | Test-DbaBackupInformation -SqlInstance $RestoreInstance -WithReplace:$WithReplace -Continue:$Continue -VerifyOnly:$VerifyOnly -EnableException:$true

‎functions/Select-DbaBackupInformation.ps1

Lines changed: 80 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ function Select-DbaBackupInformation {
2828
The Output of Get-RestoreContinuableDatabase while provides 'Database',redo_start_lsn,'FirstRecoveryForkID' values. Used to filter backups to continue a restore on a database
2929
Sets IgnoreDiffs, and also filters databases to only those within the ContinuePoints object, or the ContinuePoints object AND DatabaseName if both specified
3030
31+
.PARAMETER LastRestoreType
32+
The Output of Get-DbaRestoreHistory -last
33+
This is used to check the last type of backup to a database to see if a differential backup can be restored
34+
3135
.PARAMETER EnableException
3236
By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message.
3337
This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting.
@@ -78,16 +82,16 @@ function Select-DbaBackupInformation {
7882
[string[]]$DatabaseName,
7983
[string[]]$ServerName,
8084
[object]$ContinuePoints,
85+
[object]$LastRestoreType,
8186
[switch]$EnableException
8287
)
8388
begin {
8489
$InternalHistory = @()
85-
90+
$IgnoreFull=$false
8691
if ((Test-Bound -ParameterName ContinuePoints) -and $null -ne $ContinuePoints) {
8792
Write-Message -Message "ContinuePoints provided so setting up for a continue" -Level Verbose
88-
89-
$IgnoreDiffs = $true
9093
$IgnoreFull = $true
94+
$Continue = $True
9195
if (Test-Bound -ParameterName DatabaseName) {
9296
$DatabaseName = $DatabaseName | Where-Object {$_ -in ($ContinuePoints | Select-Object -Property Database).Database}
9397

@@ -113,59 +117,111 @@ function Select-DbaBackupInformation {
113117
}
114118
if ((Test-Bound -ParameterName DatabaseName) -and '' -ne $DatabaseName) {
115119
Write-Message -Message "Filtering by DatabaseName" -Level Verbose
116-
$InternalHistory = $InternalHistory | Where-Object {$_.Database -in $DatabaseName}
120+
# $InternalHistory = $InternalHistory | Where-Object {$_.Database -in $DatabaseName}
117121
}
122+
118123
if (Test-Bound -ParameterName ServerName) {
119124
Write-Message -Message "Filtering by ServerName" -Level Verbose
120125
$InternalHistory = $InternalHistory | Where-Object {$_.InstanceName -in $servername}
121126
}
122127

123128
$Databases = ($InternalHistory | Select-Object -Property Database -unique).Database
129+
if ($continue -and $Databases.count -gt 1 -and $DatabaseName.count -gt 1){
130+
Stop-Function -Message "Cannot perform continuing restores on multiple databases with renames, exiting"
131+
return
132+
}
133+
134+
124135
ForEach ($Database in $Databases) {
125-
Write-Message -Message "Processing Db $Database" -Level Verbose
126-
$DatabaseHistory = $InternalHistory | Where-Object {$_.Database -eq $Database}
136+
#Cope with restores renaming the db
137+
# $database = the name of database in the backups being scanned
138+
# $databasefilter = the name of the database the backups are being restore to/against
139+
if ($null -ne $DatabaseName) {
140+
$databasefilter = $DatabaseName
141+
}
142+
else {
143+
$databasefilter = $database
144+
}
145+
146+
if ($true -eq $Continue){
147+
#Test if Database is in a continuing state and the LSN to continue from:
148+
if ($Databasefilter -in ($ContinuePoints | Select-Object -Property Database).Database) {
149+
Write-Message -Message "$Database in ContinuePoints, will attmept to continue" -Level verbose
150+
$IgnoreFull = $True
151+
#Check what the last backup restored was
152+
if (($LastRestoreType | Where-Object {$_.Database -eq $Databasefilter}).RestoreType -eq 'Database') {
153+
#Full Backup last restored, so diffs can be used
154+
$IgnoreDiffs = $false
155+
}
156+
else {
157+
#Last restore was a diff or log, so can only restore more logs
158+
$IgnoreDiffs = $true
159+
}
160+
}
161+
else {
162+
Write-Message -Message "$Database not in ContinuePoints, will attmept normal restore" -Level Warning
163+
}
164+
}
127165

128-
$dbHistory = @()
129-
#Find the Last Full Backup before RestoreTime
130-
if ($true -ne $IgnoreFull) {
166+
$dbhistory = @()
167+
$DatabaseHistory = $internalhistory | Where-Object {$_.Database -eq $Database}
168+
#For a standard restore, work out the full backup
169+
if ($false -eq $IgnoreFull){
131170
$Full = $DatabaseHistory | Where-Object {$_.Type -in ('Full', 'Database') -and $_.Start -le $RestoreTime} | Sort-Object -Property LastLsn -Descending | Select-Object -First 1
132171
$full.Fullname = ($DatabaseHistory | Where-Object {$_.Type -in ('Full', 'Database') -and $_.BackupSetID -eq $Full.BackupSetID}).Fullname
133172
$dbHistory += $full
134173
}
135-
#Find the Last diff between Full and RestoreTime
136-
if ($true -ne $IgnoreDiffs) {
174+
elseif ($true -eq $IgnoreFull -and $false -eq $IgnoreDiffs) {
175+
#Fake the Full backup
176+
Write-Message -Message "Continuing, so setting a fake full backup from the existing database"
177+
$Full = [PsCustomObject]@{
178+
CheckpointLSN = ($ContinuePoints | Where-Object {$_.Database -eq $DatabaseFilter}).differential_base_lsn
179+
}
180+
}
181+
182+
if ($false -eq $IgnoreDiffs){
183+
Write-Message -Message "processing diffs" -Level Verbose
137184
$Diff = $DatabaseHistory | Where-Object {$_.Type -in ('Differential', 'Database Differential') -and $_.Start -le $RestoreTime -and $_.DatabaseBackupLSN -eq $Full.CheckpointLSN} | Sort-Object -Property LastLsn -Descending | Select-Object -First 1
138185
if ($null -ne $Diff) {
139186
$Diff.FullName = ($DatabaseHistory | Where-Object {$_.Type -in ('Differential', 'Database Differential') -and $_.BackupSetID -eq $diff.BackupSetID}).Fullname
140187
$dbhistory += $Diff
141188
}
142189
}
143-
#Get All t-logs up to restore time
144-
if ($IgnoreFull -eq $true) {
145-
[bigint]$LogBaseLsn = ($ContinuePoints | Where-Object {$_.Database -eq $Database}).redo_start_lsn
146-
$FirstRecoveryForkID = ($ContinuePoints | Where-Object {$_.Database -eq $Database}).FirstRecoveryForkID
147-
Write-Message -Message "Continuing, setting fake LastLsn - $LogBaseLSN" -Level Verbose
148-
}
149-
else {
150-
Write-Message -Message "Setting LogBaseLSN" -Level Verbose
190+
191+
#Sort out the LSN for the log restores
192+
if ($null -ne ($dbHistory | Sort-Object -Property LastLsn -Descending | select-object -First 1).lastLsn) {
193+
#We have history so use this
151194
[bigint]$LogBaseLsn = ($dbHistory | Sort-Object -Property LastLsn -Descending | select-object -First 1).lastLsn.ToString()
152195
$FirstRecoveryForkID = $Full.FirstRecoveryForkID
153196
}
197+
else {
198+
Write-Message -Message "No full or diff, so attempting to pull from Continue informmation" -Level Verbose
199+
try {
200+
[bigint]$LogBaseLsn = ($ContinuePoints | Where-Object {$_.Database -eq $DatabaseFilter}).redo_start_lsn
201+
$FirstRecoveryForkID = ($ContinuePoints | Where-Object {$_.Database -eq $DatabaseFilter}).FirstRecoveryForkID
202+
}
203+
catch{
204+
Stop-Function -Message "Failed to find LSN or RecoveryForkID for $DatabaseFilter" -Category InvalidOperation -Target $DatabaseFilter
205+
}
206+
}
154207

155-
if ($true -ne $IgnoreLogs) {
208+
if ($true -eq $IgnoreFull -and $true -eq $IgnoreDiffs){
209+
#Set a Fake starting LSN
210+
}
211+
212+
if ($false -eq $IgnoreLogs){
156213
$FilteredLogs = $DatabaseHistory | Where-Object {$_.Type -in ('Log', 'Transaction Log') -and $_.Start -le $RestoreTime -and $_.LastLSN.ToString() -ge $LogBaseLsn -and $_.FirstLSN -ne $_.LastLSN} | Sort-Object -Property LastLsn, FirstLsn
157214
$GroupedLogs = $FilteredLogs | Group-Object -Property LastLSN, FirstLSN
158215
ForEach ($Group in $GroupedLogs) {
159216
$Log = $DatabaseHistory | Where-Object {$_.BackupSetID -eq $Group.group[0].BackupSetID} | select-object -First 1
160217
$Log.FullName = ($DatabaseHistory | Where-Object {$_.BackupSetID -eq $Group.group[0].BackupSetID}).Fullname
161-
$dbhistory += $Log
162-
#$dbhistory += $DatabaseHistory | Where-Object {$_.BackupSetID -eq $Group.group[0].BackupSetID}
218+
#$dbhistory += $Log
219+
$dbhistory += $DatabaseHistory | Where-Object {$_.BackupSetID -eq $Group.group[0].BackupSetID}
163220
}
164221
# Get Last T-log
165222
$dbHistory += $DatabaseHistory | Where-Object {$_.Type -in ('Log', 'Transaction Log') -and $_.End -ge $RestoreTime -and $_.DatabaseBackupLSN -eq $Full.CheckpointLSN} | Sort-Object -Property LastLsn, FirstLsn | Select-Object -First 1
166223
}
167-
168-
$dbHistory #| Group-Object -Property BackupSetId # -Unique
224+
$dbhistory
169225
}
170226
}
171227
}

‎internal/functions/Get-RestoreContinuableDatabase.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ function Get-RestoreContinuableDatabase {
2525
break
2626
}
2727
if ($Server.VersionMajor -ge 9) {
28-
$sql = "select distinct db_name(database_id) as 'Database', redo_start_lsn, redo_start_fork_guid as 'FirstRecoveryForkID' from master.sys.master_files where redo_start_lsn is not NULL"
28+
$sql = "select distinct db_name(database_id) as 'Database', differential_base_lsn, redo_start_lsn, redo_start_fork_guid as 'FirstRecoveryForkID' from master.sys.master_files where redo_start_lsn is not NULL"
2929
}
3030
else {
3131
$sql = "

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /