Skip to content

Commit

Permalink
fixed the issues with restore options (#431)
Browse files Browse the repository at this point in the history
* fixed the issues with restore options connecting to server without db name
  • Loading branch information
llali authored Aug 14, 2017
1 parent cd870e6 commit 4b97aa8
Show file tree
Hide file tree
Showing 13 changed files with 870 additions and 290 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ public class RestorePlanDetailInfo
/// </summary>
public object DefaultValue { get; set; }

/// <summary>
/// Error message if the current value is not valid
/// </summary>
public object ErrorMessage { get; set; }

internal static RestorePlanDetailInfo Create(string name, object currentValue, bool isReadOnly = false, bool isVisible = true, object defaultValue = null)
{
return new RestorePlanDetailInfo
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
using Microsoft.SqlTools.ServiceLayer.DisasterRecovery.Contracts;
using Microsoft.SqlTools.ServiceLayer.TaskServices;
using Microsoft.SqlTools.Utility;
using System.Collections.Concurrent;
using Microsoft.SqlTools.ServiceLayer.Utility;

namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
{
Expand All @@ -24,6 +26,7 @@ namespace Microsoft.SqlTools.ServiceLayer.DisasterRecovery.RestoreOperation
public class RestoreDatabaseHelper
{
public const string LastBackupTaken = "lastBackupTaken";
private ConcurrentDictionary<string, RestoreDatabaseTaskDataObject> sessions = new ConcurrentDictionary<string, RestoreDatabaseTaskDataObject>();

/// <summary>
/// Create a backup task for execution and cancellation
Expand Down Expand Up @@ -169,6 +172,16 @@ public RestorePlanResponse CreateRestorePlanResponse(RestoreDatabaseTaskDataObje
{
response.SessionId = restoreDataObject.SessionId;
response.DatabaseName = restoreDataObject.TargetDatabase;
response.PlanDetails.Add(RestoreOptionsHelper.TargetDatabaseName, RestorePlanDetailInfo.Create(
name: RestoreOptionsHelper.TargetDatabaseName,
currentValue: restoreDataObject.TargetDatabase,
isReadOnly: !CanChangeTargetDatabase(restoreDataObject)));
response.PlanDetails.Add(RestoreOptionsHelper.SourceDatabaseName, RestorePlanDetailInfo.Create(
name: RestoreOptionsHelper.SourceDatabaseName,
currentValue: restoreDataObject.RestorePlanner.DatabaseName));
response.PlanDetails.Add(RestoreOptionsHelper.ReadHeaderFromMedia, RestorePlanDetailInfo.Create(
name: RestoreOptionsHelper.ReadHeaderFromMedia,
currentValue: restoreDataObject.RestorePlanner.ReadHeaderFromMedia));
response.DbFiles = restoreDataObject.DbFiles.Select(x => new RestoreDatabaseFileInfo
{
FileType = x.DbFileType,
Expand All @@ -183,10 +196,11 @@ public RestorePlanResponse CreateRestorePlanResponse(RestoreDatabaseTaskDataObje
response.ErrorMessage = SR.RestoreNotSupported;
}

response.PlanDetails.Add(LastBackupTaken, RestorePlanDetailInfo.Create(LastBackupTaken, restoreDataObject.GetLastBackupTaken()));
response.PlanDetails.Add(LastBackupTaken,
RestorePlanDetailInfo.Create(name: LastBackupTaken, currentValue: restoreDataObject.GetLastBackupTaken(), isReadOnly: true));

response.BackupSetsToRestore = restoreDataObject.GetSelectedBakupSets();
var dbNames = restoreDataObject.GetSourceDbNames();
var dbNames = restoreDataObject.GetPossibleTargerDbNames();
response.DatabaseNamesFromBackupSets = dbNames == null ? new string[] { } : dbNames.ToArray();

RestoreOptionsHelper.AddOptions(response, restoreDataObject);
Expand Down Expand Up @@ -241,10 +255,15 @@ private static bool CanRestore(RestoreDatabaseTaskDataObject restoreDataObject)
public RestoreDatabaseTaskDataObject CreateRestoreDatabaseTaskDataObject(RestoreParams restoreParams)
{
RestoreDatabaseTaskDataObject restoreTaskObject = null;
restoreTaskObject = CreateRestoreForNewSession(restoreParams.OwnerUri, restoreParams.TargetDatabaseName);
string sessionId = string.IsNullOrWhiteSpace(restoreParams.SessionId) ? Guid.NewGuid().ToString() : restoreParams.SessionId;
if (!sessions.TryGetValue(sessionId, out restoreTaskObject))
{
restoreTaskObject = CreateRestoreForNewSession(restoreParams.OwnerUri, restoreParams.TargetDatabaseName);
}
restoreTaskObject.SessionId = sessionId;
restoreTaskObject.RestoreParams = restoreParams;
restoreTaskObject.TargetDatabase = restoreParams.TargetDatabaseName;
restoreTaskObject.RestorePlanner.DatabaseName = restoreParams.TargetDatabaseName;
return restoreTaskObject;
}

Expand Down Expand Up @@ -303,13 +322,26 @@ private void UpdateRestorePlan(RestoreDatabaseTaskDataObject restoreDataObject)
{
restoreDataObject.RestorePlanner.DatabaseName = restoreDataObject.RestoreParams.SourceDatabaseName;
}
restoreDataObject.TargetDatabase = restoreDataObject.RestoreParams.TargetDatabaseName;

RestoreOptionsHelper.UpdateOptionsInPlan(restoreDataObject);
if (CanChangeTargetDatabase(restoreDataObject))
{
restoreDataObject.TargetDatabase = restoreDataObject.RestoreParams.TargetDatabaseName;
}
else
{
restoreDataObject.TargetDatabase = restoreDataObject.Server.ConnectionContext.DatabaseName;
}



restoreDataObject.UpdateRestorePlan();
}

private bool CanChangeTargetDatabase(RestoreDatabaseTaskDataObject restoreDataObject)
{
return DatabaseUtils.IsSystemDatabaseConnection(restoreDataObject.Server.ConnectionContext.DatabaseName);
}

/// <summary>
/// Executes the restore operation
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ public interface IRestoreDatabaseTaskDataObject

RestoreOptions RestoreOptions { get; }

string GetDefaultStandbyFile(string databaseName);
bool IsTailLogBackupPossible(string databaseName);
bool IsTailLogBackupWithNoRecoveryPossible(string databaseName);
string DefaultStandbyFile { get; }
bool IsTailLogBackupPossible { get; }
bool IsTailLogBackupWithNoRecoveryPossible { get; }

bool TailLogWithNoRecovery { get; set; }

string TailLogBackupFile { get; set; }

string GetDefaultTailLogbackupFile(string databaseName);
string DefaultTailLogbackupFile { get; }

RestorePlan RestorePlan { get; }

Expand All @@ -54,6 +54,8 @@ public class RestoreDatabaseTaskDataObject : IRestoreDatabaseTaskDataObject
private DatabaseRestorePlanner restorePlanner;
private string tailLogBackupFile;
private BackupSetsFilterInfo backupSetsFilterInfo = new BackupSetsFilterInfo();
private bool? isTailLogBackupPossible = false;
private bool? isTailLogBackupWithNoRecoveryPossible = false;

public RestoreDatabaseTaskDataObject(Server server, String databaseName)
{
Expand Down Expand Up @@ -119,7 +121,7 @@ public bool IsValid
/// Database names includes in the restore plan
/// </summary>
/// <returns></returns>
public List<String> GetSourceDbNames()
public List<String> GetPossibleTargerDbNames()
{
return Util.GetSourceDbNames(this.restorePlanner.BackupMediaList, this.CredentialName);
}
Expand Down Expand Up @@ -169,7 +171,7 @@ public void AddFiles(string filePaths)
}
}

var itemsToRemove = this.RestorePlanner.BackupMediaList.Where(x => !files.Contains(x.Name));
var itemsToRemove = this.RestorePlanner.BackupMediaList.Where(x => !files.Contains(x.Name)).ToList();
foreach (var item in itemsToRemove)
{
this.RestorePlanner.BackupMediaList.Remove(item);
Expand Down Expand Up @@ -349,7 +351,7 @@ public string DataFilesFolder
}
else
{
this.dataFilesFolder = PathWrapper.GetDirectoryName(value);
this.dataFilesFolder = PathWrapper.GetDirectoryName(value + PathWrapper.PathSeparatorFromServerConnection(Server.ConnectionContext));
}
if (string.IsNullOrEmpty(this.dataFilesFolder))
{
Expand Down Expand Up @@ -397,7 +399,7 @@ public string LogFilesFolder
}
else
{
this.logFilesFolder = PathWrapper.GetDirectoryName(value);
this.logFilesFolder = PathWrapper.GetDirectoryName(value + PathWrapper.PathSeparatorFromServerConnection(Server.ConnectionContext));
}
if (string.IsNullOrEmpty(this.logFilesFolder))
{
Expand All @@ -419,32 +421,44 @@ public string LogFilesFolder
/// <returns>
/// <c>true</c> if [is tail log backup possible]; otherwise, <c>false</c>.
/// </returns>
public bool IsTailLogBackupPossible(string databaseName)
public bool IsTailLogBackupPossible
{
if (this.Server.Version.Major < 9 || String.IsNullOrEmpty(this.restorePlanner.DatabaseName))
{
return false;
}

Database db = this.Server.Databases[databaseName];
if (db == null)
{
return false;
}
else
get
{
db.Refresh();
}
if (!isTailLogBackupPossible.HasValue)
{
if (this.Server.Version.Major < 9 || String.IsNullOrEmpty(this.restorePlanner.DatabaseName))
{
isTailLogBackupPossible = false;
}
else
{
Database db = this.Server.Databases[this.RestorePlanner.DatabaseName];
if (db == null)
{
isTailLogBackupPossible = false;
}
else
{
db.Refresh();
if (db.Status != DatabaseStatus.Normal && db.Status != DatabaseStatus.Suspect && db.Status != DatabaseStatus.EmergencyMode)
{
isTailLogBackupPossible = false;
}
else if (db.RecoveryModel == RecoveryModel.Full || db.RecoveryModel == RecoveryModel.BulkLogged)
{
isTailLogBackupPossible = true;
}
else
{
isTailLogBackupPossible = false;
}
}
}
}

if (db.Status != DatabaseStatus.Normal && db.Status != DatabaseStatus.Suspect && db.Status != DatabaseStatus.EmergencyMode)
{
return false;
return isTailLogBackupPossible.Value;
}
if (db.RecoveryModel == RecoveryModel.Full || db.RecoveryModel == RecoveryModel.BulkLogged)
{
return true;
}
return false;
}

/// <summary>
Expand All @@ -453,37 +467,56 @@ public bool IsTailLogBackupPossible(string databaseName)
/// <returns>
/// <c>true</c> if [is tail log backup with NORECOVERY possible]; otherwise, <c>false</c>.
/// </returns>
public bool IsTailLogBackupWithNoRecoveryPossible(string databaseName)
public bool IsTailLogBackupWithNoRecoveryPossible
{
if (!IsTailLogBackupPossible(databaseName))
{
return false;
}

Database db = this.Server.Databases[databaseName];
if (db == null)
{
return false;
}
if (Server.Version.Major > 10 && db.DatabaseEngineType == DatabaseEngineType.Standalone && !String.IsNullOrEmpty(db.AvailabilityGroupName))
{
return false;
}
if (db.DatabaseEngineType == DatabaseEngineType.Standalone && db.IsMirroringEnabled)
get
{
return false;
if (!isTailLogBackupWithNoRecoveryPossible.HasValue)
{
string databaseName = this.RestorePlanner.DatabaseName;
if (!IsTailLogBackupPossible)
{
isTailLogBackupWithNoRecoveryPossible = false;
}
else
{
Database db = this.Server.Databases[databaseName];
if (db == null)
{
isTailLogBackupWithNoRecoveryPossible = false;
}
else if (Server.Version.Major > 10 && db.DatabaseEngineType == DatabaseEngineType.Standalone && !String.IsNullOrEmpty(db.AvailabilityGroupName))
{
isTailLogBackupWithNoRecoveryPossible = false;
}
else if (db.DatabaseEngineType == DatabaseEngineType.Standalone && db.IsMirroringEnabled)
{
isTailLogBackupWithNoRecoveryPossible = false;
}
else
{
isTailLogBackupWithNoRecoveryPossible = true;
}
}
}
return isTailLogBackupWithNoRecoveryPossible.Value;
}
return true;
}

public string GetDefaultStandbyFile(string databaseName)
public string DefaultStandbyFile
{
return Util.GetDefaultStandbyFile(databaseName);
get
{
return Util.GetDefaultStandbyFile(this.RestorePlan != null ? this.RestorePlan.DatabaseName : string.Empty);
}
}

public string GetDefaultTailLogbackupFile(string databaseName)
public string DefaultTailLogbackupFile
{
return Util.GetDefaultTailLogbackupFile(databaseName);
get
{
return Util.GetDefaultTailLogbackupFile(this.RestorePlan != null ? this.RestorePlan.DatabaseName : string.Empty);
}
}

/// <summary>
Expand Down Expand Up @@ -605,7 +638,7 @@ public string DefaultDbName
{
get
{
var dbNames = GetSourceDbNames();
var dbNames = GetPossibleTargerDbNames();
string dbName = dbNames.FirstOrDefault();
return dbName;
}
Expand Down Expand Up @@ -663,10 +696,6 @@ public IEnumerable<BackupSetInfo> GetBackupSetInfo()
foreach (Restore restore in RestorePlan.RestoreOperations)
{
BackupSetInfo backupSetInfo = BackupSetInfo.Create(restore, Server);
if (this.backupSetsFilterInfo.IsBackupSetSelected(restore.BackupSet))
{

}
result.Add(backupSetInfo);
}

Expand Down Expand Up @@ -761,11 +790,21 @@ internal RestorePlan CreateRestorePlan(DatabaseRestorePlanner planner, RestoreOp
return ret;
}

private void ResetOptions()
{
isTailLogBackupPossible = null;
isTailLogBackupWithNoRecoveryPossible = null;
bool isTailLogBackupPossibleValue = IsTailLogBackupPossible;
bool isTailLogBackupWithNoRecoveryPossibleValue = isTailLogBackupPossibleValue;
}

/// <summary>
/// Updates restore plan
/// </summary>
public void UpdateRestorePlan()
{

ResetOptions();
this.ActiveException = null; //Clear any existing exceptions as the plan is getting recreated.
//Clear any existing exceptions as new plan is getting recreated.
this.CreateOrUpdateRestorePlanException = null;
Expand All @@ -781,6 +820,7 @@ public void UpdateRestorePlan()
{
this.RestorePlan = this.CreateRestorePlan(this.RestorePlanner, this.RestoreOptions);
this.Util.AddCredentialNameForUrlBackupSet(this.restorePlan, this.CredentialName);
RestoreOptionsHelper.UpdateOptionsInPlan(this);
if (this.ActiveException == null)
{
this.dbFiles = this.GetDbFiles();
Expand Down Expand Up @@ -979,6 +1019,7 @@ public void UpdateSelectedBackupSets()
// If the collection client sent is null, select everything; otherwise select the items that are selected in client
bool backupSetSelected = selectedBackupSetsFromClient == null || selectedBackupSetsFromClient.Any(x => BackUpSetGuidEqualsId(backupSet, x));


if (backupSetSelected)
{
AddBackupSetsToSelected(index, index);
Expand Down Expand Up @@ -1016,6 +1057,22 @@ public void UpdateSelectedBackupSets()
{
break;
}

//If the second item is not selected and it's a diff backup
if (index == 1 && backupSet.BackupSetType == BackupSetType.Differential)
{
if (this.Server.Version.Major < 9 ||
(this.RestorePlan.RestoreOperations.Count >= 3 &&
BackupSet.IsBackupSetsInSequence(this.RestorePlan.RestoreOperations[0].BackupSet, this.RestorePlan.RestoreOperations[2].BackupSet)))
{
// only the item at index 1 won't be selected
}
else
{
// nothing after index 1 should be selected
break;
}
}
}
}
}
Expand Down
Loading

0 comments on commit 4b97aa8

Please sign in to comment.