/// <summary> /// Gets Invoked When a policy is created. /// </summary> /// <returns></returns> internal async Task CreatePolicyAsync(BackupPolicy backupPolicy, TimeSpan timeout, CancellationToken cancellationToken, ITransaction transaction) { // create a metadata and initialise the RetentionMetadata. BackupRestoreTrace.TraceSource.WriteInfo(TraceType, "Scheduling retention for backupPolicy : {0}", backupPolicy.Name); RetentionPolicy retentionPolicy = backupPolicy.RetentionPolicy; if (null == retentionPolicy) { // there is nothing to be done. BackupRestoreTrace.TraceSource.WriteInfo(TraceType, "RetentionPolicy for backupPolicy : {0} is not defined.", backupPolicy.Name); } else { RetentionMetadata retentionMetadata = new RetentionMetadata(backupPolicy.RetentionPolicy); await this.RetentionStore.AddAsync(backupPolicy.Name, retentionMetadata, timeout, cancellationToken, transaction); RetentionScheduler retentionScheduler = new RetentionScheduler(backupPolicy.Name, backupPolicy.RetentionPolicy, timerCallback); if (!RetentionSchedulerDict.TryAdd(backupPolicy.Name, retentionScheduler)) { BackupRestoreTrace.TraceSource.WriteError(TraceType, "CreatePolicyAsync: Not able to add retention scheduler for backupPolicy : {0}", backupPolicy.Name); throw new InvalidOperationException(string.Format("{0}: Key already exists ", backupPolicy.Name)); } retentionScheduler.ArmTimer(retentionMetadata); } }
// It should be called when cancellationToken is set. internal void StopRetentionManager() { try { // It is better if all the tasks running retentionSchedulerDict are deleted. this.tokenSource.Cancel(); // Wait for all the running tasks to cancel. Task.Delay(TimeSpan.FromSeconds(waitTimeInSecondForTasksToClose)); // Stop the timers. foreach (var tuple in this.RetentionSchedulerDict) { RetentionScheduler retentionScheduler = tuple.Value; retentionScheduler.Stop(); } // Delete all the key value pairs. this.RetentionSchedulerDict.Clear(); } catch (Exception ex) { BackupRestoreTrace.TraceSource.WriteError(TraceType, "RetentionManager was not stopped properly. ExceptionThrown: {0}", ex); } finally { this.tokenSource.Dispose(); } }
/// <summary> /// Gets called when a policy is updated /// </summary> internal async Task UpdatePolicyAsync(string backupPolicyName, TimeSpan timeout, CancellationToken cancellationToken, ITransaction transaction) { /** * Cases: * 1. UpdateRetention ----> Re-arm the timer. * 0. Add Retention. * a. Remove retention --> dispose the timer. * b. update the retention. * 2. UpdateStorage ----> * 3. Update Backup Schedule. --> no need to do anything/ * */ try { BackupRestoreTrace.TraceSource.WriteInfo(TraceType, " In UpdatePolicyAsync of Retention Manager for Backup policy: {0}", backupPolicyName); var backupPolicyStore = await BackupPolicyStore.CreateOrGetBackupPolicyStore(this.StatefulService); RetentionMetadata retentionMetadata = await this.RetentionStore.GetValueAsync(backupPolicyName, timeout, cancellationToken, transaction); BackupPolicy backupPolicy = await backupPolicyStore.GetValueAsync(backupPolicyName, timeout, cancellationToken, transaction); if (retentionMetadata == null) { if (backupPolicy.RetentionPolicy != null) { retentionMetadata = new RetentionMetadata(backupPolicy.RetentionPolicy); await this.RetentionStore.AddAsync(backupPolicyName, retentionMetadata, timeout, cancellationToken, transaction); RetentionScheduler retentionScheduler = new RetentionScheduler(backupPolicy.Name, backupPolicy.RetentionPolicy, timerCallback); // Here we have updated the policy to introduce retention. retentionScheduler.ArmTimer(retentionMetadata, true); if (!RetentionSchedulerDict.TryAdd(backupPolicyName, retentionScheduler)) { // If we are not able to add retention in RetentionSchedulerDict then, stop timer in retention scheduler retentionScheduler.Stop(); BackupRestoreTrace.TraceSource.WriteWarning(TraceType, "UpdatePolicyAsync, Not able to add retentionScheduler to dict for policy : {0} ", backupPolicyName); throw new InvalidOperationException(string.Format("{0}: Key already exists.", backupPolicyName)); } } } else if (backupPolicy.RetentionPolicy == null) { // need to remove the retentionScheduler from RetentionStore. Func <bool> condition = () => { if (retentionMetadata.LastRetentionCompletionTime > retentionMetadata.LastRetentionStartTime || retentionMetadata.LastRetentionStartTime == DateTime.MinValue) { return(true); } return(false); }; bool disposeComplete = await BackupRestoreUtility.TryPerformOperationWithWaitAsync( (policyName, token) => { return(DisposeRetentionScheduler(policyName, timeout, token, transaction)); }, condition, backupPolicyName, cancellationToken, minimumWaitTimeForRetryOperationInMs, maxRetryCountForDisposingRetention, minimumWaitTimeForRetryOperationInMs); if (!disposeComplete) { BackupRestoreTrace.TraceSource.WriteError(TraceType, "Dispose retention did not complete for {0}", backupPolicyName); throw new FabricBackupRestoreLocalRetryException(); } } else { if (retentionMetadata.UpdateRetentionPolicyMetadata(backupPolicy.RetentionPolicy)) { // Update the retention Scheduler store and arm the timer. RetentionScheduler retentionScheduler; if (!RetentionSchedulerDict.TryGetValue(backupPolicyName, out retentionScheduler)) { BackupRestoreTrace.TraceSource.WriteError(TraceType, "UpdateBackupPolicy: Not able to get retention scheduler for backupPolicy {0}", backupPolicyName); throw new KeyNotFoundException(); } retentionScheduler.RearmTimer(false, retentionMetadata); await this.RetentionStore.UpdateValueAsync(backupPolicyName, retentionMetadata, timeout, cancellationToken, transaction); } } } catch (Exception ex) { if (ex is OperationCanceledException) { BackupRestoreTrace.TraceSource.WriteWarning(TraceType, " DisposeRetentionScheduler ended with Timeout as the operation was cencelled: {0}", backupPolicyName); BackupRestoreTrace.TraceSource.WriteWarning(TraceType, " It could be because the retention was in progress and user tried to remove the retention policy during UpdatePolicy: {0}", backupPolicyName); } else { // Check for the exceptions of DisposeRetentionScheduler Timeout Retries. BackupRestoreTrace.TraceSource.WriteError(TraceType, " UpdateBackupPolicy resulted in the exception : {0}", backupPolicyName); } throw; } }