private void CopyCallerHoldsReaderLock(string source, string destination, CopyFlag copyFlag, TimeoutHelper helper) { string destinationDirectory = FabricPath.GetDirectoryName(destination); if (!string.IsNullOrEmpty(destinationDirectory) && !FabricDirectory.Exists(destinationDirectory)) { FabricDirectory.CreateDirectory(destinationDirectory); } using (FileWriterLock writerLock = new FileWriterLock(destination)) { if (!writerLock.Acquire()) { throw new FabricTransientException(StringResources.Error_ImageStoreAcquireFileLockFailed, FabricErrorCode.ImageStoreAcquireFileLockFailed); } if (helper != null) { helper.ThrowIfExpired(); } if (FabricFile.Exists(source)) { // This is a file copy if (FabricFile.Exists(destination)) { FabricFile.Delete(destination, deleteReadonly: true); } int retryCount = 0; while (helper == null || !TimeoutHelper.HasExpired(helper)) { try { bool shouldOverwrite = (copyFlag != CopyFlag.AtomicCopySkipIfExists); FabricFile.Copy(source, destination, shouldOverwrite); break; } catch (UnauthorizedAccessException) { TraceSource.WriteInfo( TraceType, "Uploading {0} to {1} caused UnauthorizedAccessException. RetryCount: {2}.", source, destination, retryCount); if (retryCount++ > 3) { throw; } // This could happen when a file is marked for delete and we try to delete // it again or try to open the file. Retrying after sometime should fix the issue. Thread.Sleep(TimeSpan.FromSeconds(retryCount)); } if (helper != null) { helper.ThrowIfExpired(); } } } else { // This is a folder copy using (FolderCopy fc = new FolderCopy(copyFlag, null)) { fc.Copy(source, destination); } } } }
/// <summary> /// Remove tag from store and clear the data associated with tag. /// </summary> /// <param name="tag">Location (relative to RootUri) from where to delete the content.</param> /// <param name="timeout">The timeout for performing the delete operation.</param> public void DeleteContent(string tag, TimeSpan timeout) { TimeoutHelper helper = (timeout == TimeSpan.MaxValue) ? null : new TimeoutHelper(timeout); #if !DotNetCoreClr using (WindowsImpersonationContext impersonationContext = this.GetImpersonationContext()) #endif { try { string smbTag = this.ConvertTagToSMBPath(tag); if ((!FabricFile.Exists(smbTag)) && (!FabricDirectory.Exists(smbTag))) { return; } using (FileWriterLock fileWriterLock = new FileWriterLock(smbTag)) { if (!fileWriterLock.Acquire()) { throw new FabricTransientException(StringResources.Error_ImageStoreAcquireFileLockFailed, FabricErrorCode.ImageStoreAcquireFileLockFailed); } if (helper != null) { helper.ThrowIfExpired(); } if (FabricFile.Exists(smbTag)) { FabricFile.Delete(smbTag, deleteReadonly: true); } else if (FabricDirectory.Exists(smbTag)) { FabricDirectory.Delete(smbTag, recursive: true, deleteReadOnlyFiles: true); } } } catch (IOException exception) { // HResult 0x80070020: THE PROCESS CANNOT ACCESS THE FILE BECAUSE IT IS BEING USED BY ANOTHER PROCESS // This work-around is done here since when we read a file from a folder we only take a reader lock on the file and not the // entire folder. When we delete a folder, we only take writer lock on the folder and hence we might run into scenarios // where a folder is attempted to be deleted even when a file in it is being read. // Returning FabricImageStoreException, causes CM to retry the delete operation. int hrError = Marshal.GetHRForException(exception); TraceSource.WriteWarning( TraceType, "Delete of {0} failed because of {1}, hrError {2:X}.", tag, exception.Message, hrError); if (hrError == unchecked ((int)0x80070020)) { throw new FabricTransientException(StringResources.Error_ImageStoreAcquireFileLockFailed, exception, FabricErrorCode.ImageStoreAcquireFileLockFailed); } throw; } } }