private static void CopyContainer(CloudBlobDirectory sourceDirectory, CloudBlobDirectory destDirectory)
        {
            // This function copies an entire Storage container using the data movement library.
            // See https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.storage.datamovement.copydirectoryoptions?view=azure-dotnet for the API
            // and https://docs.microsoft.com/en-us/azure/storage/common/storage-use-data-movement-library for a general overview.

            ProgressRecorder recorder  = new ProgressRecorder();
            Stopwatch        stopWatch = Stopwatch.StartNew();

            CopyDirectoryOptions copyDirectoryOptions = new CopyDirectoryOptions
            {
                // Needs to be true to copy the contents of the directory / container.  If this is false the contents will
                // not be copied.
                Recursive = true
            };
            // Copy all files under root folder
            DirectoryTransferContext context = new DirectoryTransferContext
            {
                ProgressHandler = recorder
            };

            TransferStatus copyStatus = TransferManager.CopyDirectoryAsync(sourceDirectory, destDirectory, CopyMethod.ServiceSideAsyncCopy, copyDirectoryOptions, context).Result;

            stopWatch.Stop();
            // Get the elapsed time as a TimeSpan value.
            TimeSpan ts = stopWatch.Elapsed;

            // Format and display the TimeSpan value.
            string elapsedTime = string.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                                               ts.Hours, ts.Minutes, ts.Seconds,
                                               ts.Milliseconds / 10);

            Console.WriteLine($"Elapsed:{elapsedTime} T File transferred: {copyStatus.NumberOfFilesTransferred} total bytes:{copyStatus.BytesTransferred}, failed: {copyStatus.NumberOfFilesFailed}, skipped:{copyStatus.NumberOfFilesSkipped}");
        }
示例#2
0
        private static async Task BlobDirectoryCopySample()
        {
            var sourceBlobDir = await Util.GetCloudBlobDirectoryAsync("sourcecontainer", "dir1");

            var destBlobDir = await Util.GetCloudBlobDirectoryAsync("targetcontainer", "dir2");

            var options = new CopyDirectoryOptions()
            {
                Recursive = true,
            };

            var context = new DirectoryTransferContext();

            context.FileTransferred += FileTransferredCallback;
            context.FileFailed      += FileFailedCallback;
            context.FileSkipped     += FileSkippedCallback;

            TransferManager.Configurations.ParallelOperations = 50;
            Console.WriteLine("Transfer started");

            try
            {
                Task  task = TransferManager.CopyDirectoryAsync(sourceBlobDir, destBlobDir, false, options, context);
                await task;
            }
            catch (Exception e)
            {
                Console.WriteLine("The transfer is cancelled: {0}", e.Message);
            }

            Console.WriteLine("The transfer is completed.");
        }
        public static object GetDefaultTransferDirectoryOptions(DMLibDataType sourceType, DMLibDataType destType)
        {
            if (DMLibTestBase.IsLocal(sourceType))
            {
                var result = new UploadDirectoryOptions();

                if (IsCloudBlob(destType))
                {
                    result.BlobType = MapBlobDataTypeToXSCLBlobType(destType);
                }

                return(result);
            }
            else if (DMLibTestBase.IsLocal(destType))
            {
                return(new DownloadDirectoryOptions());
            }
            else
            {
                var result = new CopyDirectoryOptions();

                if (IsCloudBlob(destType))
                {
                    result.BlobType = MapBlobDataTypeToXSCLBlobType(destType);
                }

                return(result);
            }
        }
示例#4
0
            /// <summary>
            /// Legacy convenience function that exposes transform & Retry count
            /// </summary>
            /// <param name="SourceDirPath"></param>
            /// <param name="DestDirPath"></param>
            /// <param name="Mode"></param>
            /// <param name="Transform"></param>
            /// <param name="RetryCount"></param>
            public static void CopyDirectory(string SourceDirPath, string DestDirPath, CopyOptions Mode, Func <string, string> Transform, int RetryCount = 5)
            {
                CopyDirectoryOptions Options = new CopyDirectoryOptions();

                Options.Retries   = RetryCount;
                Options.Mode      = Mode;
                Options.Transform = Transform;

                CopyDirectory(SourceDirPath, DestDirPath, Options);
            }
        public async Task <List <BlobInfo> > CopyDirectory(
            IBlobContainer sourceContainerName,
            string sourceDirectoryPath,
            IBlobContainer destinationContainerName,
            string destinationDirectoryPath,
            IBlobStorageService.CopyDirectoryOptions?options = null)
        {
            _logger.LogInformation(
                "Copying directory from {0}/{1} to {2}/{3}",
                sourceContainerName,
                sourceDirectoryPath,
                destinationContainerName,
                destinationDirectoryPath
                );

            var sourceContainer = await GetCloudBlobContainer(sourceContainerName);

            var destinationContainer = await GetCloudBlobContainer(
                destinationContainerName,
                connectionString : options?.DestinationConnectionString
                );

            var sourceDirectory      = sourceContainer.GetDirectoryReference(sourceDirectoryPath);
            var destinationDirectory = destinationContainer.GetDirectoryReference(destinationDirectoryPath);

            var copyDirectoryOptions = new CopyDirectoryOptions
            {
                Recursive = true
            };

            var filesTransferred = new List <BlobInfo>();

            var context = new DirectoryTransferContext();

            context.FileTransferred              += (sender, args) => FileTransferredCallback(sender, args, filesTransferred);
            context.FileFailed                   += FileFailedCallback;
            context.FileSkipped                  += FileSkippedCallback;
            context.SetAttributesCallbackAsync   += options?.SetAttributesCallbackAsync;
            context.ShouldTransferCallbackAsync  += options?.ShouldTransferCallbackAsync;
            context.ShouldOverwriteCallbackAsync += options?.ShouldOverwriteCallbackAsync;

            await TransferManager.CopyDirectoryAsync(
                sourceDirectory,
                destinationDirectory,
                CopyMethod.ServiceSideAsyncCopy,
                copyDirectoryOptions,
                context
                );

            return(filesTransferred);
        }
        private Task <TransferStatus> CopyDirectory(dynamic sourceObject, dynamic destObject, TransferItem item)
        {
            CopyDirectoryOptions     copyDirectoryOptions = item.Options as CopyDirectoryOptions;
            DirectoryTransferContext transferContext      = item.TransferContext as DirectoryTransferContext;
            CancellationToken        cancellationToken    = item.CancellationToken;

            if (cancellationToken == null || cancellationToken == CancellationToken.None)
            {
                return(TransferManager.CopyDirectoryAsync(sourceObject, destObject, item.IsServiceCopy, copyDirectoryOptions, transferContext));
            }
            else
            {
                return(TransferManager.CopyDirectoryAsync(sourceObject, destObject, item.IsServiceCopy, copyDirectoryOptions, transferContext, cancellationToken));
            }
        }
示例#7
0
        /// <summary>
        /// Moves a folder with its contents to the path given
        /// </summary>
        /// <param name="folder"></param>
        /// <param name="path"></param>
        /// <returns></returns>
        public async Task <BlobDto> MoveFolder(BlobDto folder, string path)
        {
            var container = await GetContainer();

            if (path[path.Length - 1] != '/')
            {
                path = path + "/";
            }

            string newPath = $"{path}{folder.Name}";

            var sourceBlobDir = container.GetDirectoryReference(folder.Path);
            var destBlobDir   = container.GetDirectoryReference(newPath);

            TransferManager.Configurations.ParallelOperations = 64;
            // Setup the transfer context and track the upoload progress
            DirectoryTransferContext context = new DirectoryTransferContext
            {
                ProgressHandler = new Progress <TransferStatus>((progress) =>
                {
                    Console.WriteLine("Bytes uploaded: {0}", progress.BytesTransferred);
                })
            };

            var copyDirOptions = new CopyDirectoryOptions
            {
                Recursive        = true,
                IncludeSnapshots = true
            };

            await TransferManager.CopyDirectoryAsync(sourceBlobDir, destBlobDir, true, copyDirOptions, context);

            await DeleteFile(folder.Path);

            folder.Path         = newPath;
            folder.StoragePath  = destBlobDir.Uri.ToString();
            folder.DateModified = DateTime.UtcNow;

            return(folder);
        }
示例#8
0
        public async Task RunAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            var copyDirectoryOptions = new CopyDirectoryOptions
            {
                Recursive = true
            };

            var directoryTransferContext = new DirectoryTransferContext
            {
                //ProgressHandler = new Progress<TransferStatus>(progress => Log.Trace(() => $"Progress: transferred: {progress.NumberOfFilesTransferred}, failed: {progress.NumberOfFilesFailed}, skipped: {progress.NumberOfFilesSkipped}, bytes transferred: {progress.BytesTransferred}"))
            };

            directoryTransferContext.FileTransferred += (sender, args) => Log.Trace(() => $"Transferred {(args.Source as CloudFile)?.Name} -> {(args.Destination as CloudFile)?.Name}");
            directoryTransferContext.FileSkipped     += (sender, args) => Log.Trace(() => $"Skipped {(args.Source as CloudFile)?.Name} -> {(args.Destination as CloudFile)?.Name}");
            directoryTransferContext.FileFailed      += (sender, args) => Log.Error(() => $"Failed {(args.Source as CloudFile)?.Name} -> {(args.Destination as CloudFile)?.Name}");

            Log.Info(() => $"Starting server side copy from {this.sourceDirectory.Uri} to {this.targetDirectory.Uri}");

            var status = await TransferManager.CopyDirectoryAsync(sourceDirectory, targetDirectory, true, copyDirectoryOptions, directoryTransferContext, cancellationToken);

            Log.Info(() => $"Finished server side copy, transferred: {status.NumberOfFilesTransferred}, failed: {status.NumberOfFilesFailed}, skipped: {status.NumberOfFilesSkipped}, bytes transferred: {status.BytesTransferred}");
        }
示例#9
0
        /// <summary>
        /// Copy data between Azure storage.
        ///   1. Copy a CloudBlobDirectory
        ///   2. Cancel the transfer before it finishes with a CancellationToken
        ///   3. Store the transfer checkpoint into a file after transfer being cancelled
        ///   4. Reload checkpoint from the file
        ///   4. Resume the transfer with the loaded checkpoint
        /// </summary>
        private static async Task BlobDirectoryCopySample()
        {
            CloudBlobDirectory sourceBlobDir = await Util.GetCloudBlobDirectoryAsync(ContainerName, "blobdir");

            CloudBlobDirectory destBlobDir = await Util.GetCloudBlobDirectoryAsync(ContainerName, "blobdir2");

            // When source is CloudBlobDirectory:
            //   1. If recursive is set to true, data movement library matches the source blob name against SearchPattern as prefix.
            //   2. Otherwise, data movement library matches the blob with the exact name specified by SearchPattern.
            //
            // You can also replace the source directory with a CloudFileDirectory instance to copy data from Azure File Storage. If so:
            //   1. If recursive is set to true, SearchPattern is not supported. Data movement library simply transfer all azure files
            //      under the source CloudFileDirectory and its sub-directories.
            //   2. Otherwise, data movement library matches the azure file with the exact name specified by SearchPattern.
            //
            // In the following case, data movement library will copy all blobs with the prefix "azure" in source blob directory.
            CopyDirectoryOptions options = new CopyDirectoryOptions()
            {
                SearchPattern = "azure",
                Recursive     = true,
            };

            DirectoryTransferContext context = new DirectoryTransferContext();

            context.FileTransferred += FileTransferredCallback;
            context.FileFailed      += FileFailedCallback;
            context.FileSkipped     += FileSkippedCallback;

            // Create CancellationTokenSource used to cancel the transfer
            CancellationTokenSource cancellationSource = new CancellationTokenSource();

            TransferCheckpoint checkpoint    = null;
            TransferStatus     trasferStatus = null;

            try
            {
                Task <TransferStatus> task = TransferManager.CopyDirectoryAsync(sourceBlobDir, destBlobDir, false /* isServiceCopy */, options, context, cancellationSource.Token);

                // Sleep for 1 seconds and cancel the transfer.
                // It may fail to cancel the transfer if transfer is done in 1 second. If so, no file will be copied after resume.
                Thread.Sleep(1000);
                Console.WriteLine("Cancel the transfer.");
                cancellationSource.Cancel();

                trasferStatus = await task;
            }
            catch (Exception e)
            {
                Console.WriteLine("The transfer is cancelled: {0}", e.Message);
            }

            // Store the transfer checkpoint
            checkpoint = context.LastCheckpoint;

            // Serialize the checkpoint into a file
#if DOTNET5_4
            var formatter = new DataContractSerializer(typeof(TransferCheckpoint));
#else
            IFormatter formatter = new BinaryFormatter();
#endif

            string tempFileName = Guid.NewGuid().ToString();
            using (var stream = new FileStream(tempFileName, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                formatter.Serialize(stream, checkpoint);
            }

            // Deserialize the checkpoint from the file
            using (var stream = new FileStream(tempFileName, FileMode.Open, FileAccess.Read, FileShare.None))
            {
                checkpoint = formatter.Deserialize(stream) as TransferCheckpoint;
            }

            File.Delete(tempFileName);

            // Create a new TransferContext with the store checkpoint
            DirectoryTransferContext resumeContext = new DirectoryTransferContext(checkpoint);
            resumeContext.FileTransferred += FileTransferredCallback;
            resumeContext.FileFailed      += FileFailedCallback;
            resumeContext.FileSkipped     += FileSkippedCallback;

            // Record the overall progress
            ProgressRecorder recorder = new ProgressRecorder();
            resumeContext.ProgressHandler = recorder;

            // Resume transfer from the stored checkpoint
            Console.WriteLine("Resume the cancelled transfer.");
            trasferStatus = await TransferManager.CopyDirectoryAsync(sourceBlobDir, destBlobDir, false /* isServiceCopy */, options, resumeContext);

            // Print out the final transfer state
            Console.WriteLine("Final transfer state: {0}", TransferStatusToString(trasferStatus));
        }
        /// <summary>
        /// Copies the content of one directory to another on the server side.
        /// Avoids having to download all items and reupload them to somewhere else on the client side.
        /// </summary>
        /// <param name="sourceDirectoryPath">The path to the directory containing the files to be transferred</param>
        /// <param name="destinationDirectoryPath">The path to the destination directory </param>
        /// <param name="transferEvent">Action callback for tracking progress of each file when transferring.</param>
        /// <returns>Result from the  server side transfer.</returns>
        public async Task <ITransferResult> CopyDirectory(string sourceDirectoryPath, string destinationDirectoryPath, Action <Core.TransferEventType, ITransferEvent> transferEvent = null)
        {
            var sourceContainerName      = GetContainerFromPath(sourceDirectoryPath);
            var destinationContainerName = GetContainerFromPath(destinationDirectoryPath);

            // Ensure destination folder exists if we've configured to create automatically.
            if (CreateFolderIfNotExists)
            {
                GetContainer(destinationContainerName, true);
            }

            var directoryTransferContext = new DirectoryTransferContext();

            // Subscribe to the transfer events if an action method was passed.
            if (transferEvent != null)
            {
                directoryTransferContext.FileTransferred += (fileTransferSender, fileTransferredEventArgs) =>
                {
                    ITransferEvent i = (TransferEvent)fileTransferredEventArgs;
                    transferEvent(Core.TransferEventType.Transferred, i);
                };

                directoryTransferContext.FileFailed += (fileFailedSender, fileTransferredEventArgs) =>
                {
                    ITransferEvent i = (TransferEvent)fileTransferredEventArgs;
                    transferEvent(Core.TransferEventType.Failed, i);
                };

                directoryTransferContext.FileSkipped += (fileSkippedSender, fileTransferredEventArgs) =>
                {
                    ITransferEvent i = (TransferEvent)fileTransferredEventArgs;
                    transferEvent(Core.TransferEventType.Skipped, i);
                };
            }

            directoryTransferContext.ShouldOverwriteCallbackAsync = (source, destination) => Task.FromResult(true);

            var copyOptions = new CopyDirectoryOptions {
                BlobType = BlobType.AppendBlob, Recursive = true
            };

            var sourceContainer   = CloudBlobClient.GetContainerReference(sourceContainerName);
            var sourceRelativeUrl = GetPathWithoutContainer(sourceDirectoryPath);
            var sourceDirectory   = sourceContainer.GetDirectoryReference(sourceRelativeUrl);

            var destinationContainer   = CloudBlobClient.GetContainerReference(destinationContainerName);
            var destinationRelativeUrl = GetPathWithoutContainer(destinationDirectoryPath);
            var destinationDirectory   = destinationContainer.GetDirectoryReference(destinationRelativeUrl);

            var transferTask = TransferManager.CopyDirectoryAsync(sourceDirectory, destinationDirectory, CopyMethod.ServiceSideSyncCopy, copyOptions, directoryTransferContext);
            var result       = await transferTask;

            // Output the result from the transfer.
            return(new TransferResult
            {
                BytesTransferred = result.BytesTransferred,
                NumberOfFilesFailed = result.NumberOfFilesFailed,
                NumberOfFilesSkipped = result.NumberOfFilesSkipped,
                NumberOfFilesTransferred = result.NumberOfFilesTransferred
            });
        }
示例#11
0
        public async static Task ProcessMessage([QueueTrigger("backupqueue")] CopyItem copyItem, TextWriter log, CancellationToken cancelToken)
        {
            // Copy TextWrite into Log Helper class
            Logger.log = log;

            // Log Job Start
            await Logger.JobStartAsync(copyItem.JobName);

            // This class accumulates transfer data during the copy
            ProgressRecorder progressRecorder = new ProgressRecorder();

            try
            {
                // OpContext to track PreCopy Retries on Azure Storage
                // DML has its own context object and retry
                _opContext           = new OperationContext();
                _opContext.Retrying += StorageRequest_Retrying;

                // Define Blob Request Options
                _blobRequestOptions = new BlobRequestOptions
                {
                    // Defined Exponential Retry Policy above
                    RetryPolicy = _retryPolicy
                };

                // Set the number of parallel tasks in DML.
                // This allows it to copy multiple items at once when copying a container or directory
                // The best (and default value) is Environment.ProcessorCount * 8
                int parallelTasks = Environment.ProcessorCount * 8;
                TransferManager.Configurations.ParallelOperations = parallelTasks;

                // Set the number of connections.
                // This should match ParallelOperations so each DML copy task has its own connection to Azure Storage
                ServicePointManager.DefaultConnectionLimit = parallelTasks;

                // Short circuit additional request round trips. We are not chunking and
                // uploading large amounts of data where we'd send 100's so set to false
                ServicePointManager.Expect100Continue = false;

                // User Agent for tracing
                TransferManager.Configurations.UserAgentPrefix = "AzureDmlBackup";

                // CancellationTokenSource used to cancel the transfer
                CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

                // Open connections to both storage accounts
                CloudStorageAccount sourceAccount      = GetAccount(copyItem.SourceAccountToken);
                CloudStorageAccount destinationAccount = GetAccount(copyItem.DestinationAccountToken);

                // Represents a checkpoint from which a transfer may be resumed and continued.
                // This is initalized as null first time then hydrated within CopyDirectoryAsync().
                // However if this job is being resumed from a previous failure this function will hydrate
                // from a serialized checkpoint saved to blob storage.
                TransferCheckpoint transferCheckpoint = await GetTransferCheckpoint(copyItem.JobId);


                // Context object for the transfer, provides additional runtime information about its execution
                // If this is a resumed copy operation then pass the checkpoint to the TransferContext so it can resume the copy
                TransferContext transferContext = new TransferContext(transferCheckpoint)
                {
                    // Pipe transfer progress data to ProgressRecorder
                    // ProgressRecorder is used to log the results of the copy operation
                    ProgressHandler = progressRecorder,

                    // If the destination already exists this delegate is called.
                    // Return true to overwrite or false to skip the file during the transfer
                    OverwriteCallback = (source, destination) =>
                    {
                        return(OverwriteFile(source, destination, sourceAccount, destinationAccount, copyItem.IsIncremental));
                    }
                };

                // This event is used to log files skipped during the transfer
                transferContext.FileSkipped += TransferContext_FileSkipped;

                // This event is used to catch exceptions for files that fail during a transfer
                transferContext.FileFailed += TransferContext_FileFailed;

                // Set Options for copying the container such as search patterns, recursive, etc.
                CopyDirectoryOptions copyDirectoryOptions = new CopyDirectoryOptions
                {
                    IncludeSnapshots = true,
                    Recursive        = true
                };

                // Get the root source and destination directories for the two containers to be copied
                CloudBlobDirectory sourceDirectory = await GetDirectoryAsync(sourceAccount, copyItem.SourceContainer, copyItem.SourceDirectory);

                CloudBlobDirectory destinationDirectory = await GetDirectoryAsync(destinationAccount, copyItem.DestinationContainer, copyItem.DestinationDirectory);


                // Copy the container
                await CopyDirectoryAsync(copyItem.JobId, sourceDirectory, destinationDirectory, copyDirectoryOptions, transferContext, transferCheckpoint, cancellationTokenSource);


                // Check if any files failed during transfer
                if (_failedFiles.Count > 0)
                {
                    // Save a Checkpoint so we can restart the transfer
                    transferCheckpoint = transferContext.LastCheckpoint;
                    SaveTransferCheckpoint(copyItem.JobId, transferCheckpoint);
                    // Throw an exception to fail the job so WebJobs will rerun it
                    throw new Exception("One or more errors occurred during the transfer.");
                }

                // Log job completion
                await Logger.JobCompleteAsync(copyItem.JobName, progressRecorder, _skippedFiles);
            }
            catch (Exception ex)
            {
                // Log Job Error
                await Logger.JobErrorAsync(copyItem.JobName, ex.Message, progressRecorder, _failedFiles, _skippedFiles);

                // Rethrow the error to fail the web job
                throw ex;
            }
        }
示例#12
0
        private async static Task CopyDirectoryAsync(string jobId, CloudBlobDirectory sourceDirectory, CloudBlobDirectory destinationDirectory, CopyDirectoryOptions copyDirectoryOptions, TransferContext transferContext, TransferCheckpoint transferCheckpoint, CancellationTokenSource cancellationTokenSource)
        {
            // Start the transfer
            try
            {
                await TransferManager.CopyDirectoryAsync(
                    sourceBlobDir : sourceDirectory,
                    destBlobDir : destinationDirectory,
                    isServiceCopy : false,
                    options : copyDirectoryOptions,
                    context : transferContext,
                    cancellationToken : cancellationTokenSource.Token);

                // Store the transfer checkpoint to record the completed copy operation
                transferCheckpoint = transferContext.LastCheckpoint;
            }
            catch (TransferException)
            {
                // Swallow all transfer exceptions here. Files skipped in the OverwriteCallback throw an exception here
                // even in an Incremental copy where the source is skipped because it and destination are identical
                // Instead all exceptions from transfers are handled in the FileFailed event handler.
            }
            catch (Exception ex)
            {
                // Fatal or other exceptions resulting in the transfer being cancelled will still appear here

                // Save a Checkpoint so we can restart the transfer
                transferCheckpoint = transferContext.LastCheckpoint;
                SaveTransferCheckpoint(jobId, transferCheckpoint);

                throw new Exception("Error in CopyDirectoryAsync(): " + ex.Message);
            }
        }
示例#13
0
            /// <summary>
            /// Copies src to dest by comparing files sizes and time stamps and only copying files that are different in src. Basically a more flexible
            /// robocopy
            /// </summary>
            /// <param name="SourcePath"></param>
            /// <param name="DestPath"></param>
            /// <param name="Verbose"></param>
            public static void CopyDirectory(string SourceDirPath, string DestDirPath, CopyDirectoryOptions Options)
            {
                DateTime StartTime = DateTime.Now;

                DirectoryInfo SourceDir = new DirectoryInfo(SourceDirPath);
                DirectoryInfo DestDir   = new DirectoryInfo(DestDirPath);

                if (DestDir.Exists == false)
                {
                    DestDir = Directory.CreateDirectory(DestDir.FullName);
                }

                bool IsMirroring = (Options.Mode & CopyOptions.Mirror) == CopyOptions.Mirror;

                if (IsMirroring && !Options.IsDirectoryPattern)
                {
                    Log.Warning("Can only use mirror with pattern that includes whole directories (e.g. '*')");
                    IsMirroring = false;
                }

                IEnumerable <FileInfo> SourceFiles = null;

                FileInfo[] DestFiles = null;

                // find all files. If a directory get them all, else use the pattern/regex
                if (Options.IsDirectoryPattern)
                {
                    SourceFiles = SourceDir.GetFiles("*", Options.Recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
                }
                else
                {
                    if (Options.Regex == null)
                    {
                        SourceFiles = SourceDir.GetFiles(Options.Pattern, Options.Recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
                    }
                    else
                    {
                        SourceFiles = SourceDir.GetFiles("*", Options.Recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);

                        SourceFiles = SourceFiles.Where(F => Options.Regex.IsMatch(F.Name));
                    }
                }

                // Convert dest into a map of relative paths to absolute
                Dictionary <string, System.IO.FileInfo> DestStructure = new Dictionary <string, System.IO.FileInfo>();

                if (IsMirroring)
                {
                    DestFiles = DestDir.GetFiles("*", SearchOption.AllDirectories);

                    foreach (FileInfo Info in DestFiles)
                    {
                        string RelativePath = Info.FullName.Replace(DestDir.FullName, "");

                        // remove leading seperator
                        if (RelativePath.First() == Path.DirectorySeparatorChar)
                        {
                            RelativePath = RelativePath.Substring(1);
                        }

                        DestStructure[RelativePath] = Info;
                    }
                }

                // List of relative-path files to copy to dest
                List <string> CopyList = new List <string>();

                // List of relative path files in dest to delete
                List <string> DeletionList = new List <string>();

                foreach (FileInfo SourceInfo in SourceFiles)
                {
                    string SourceFilePath = SourceInfo.FullName.Replace(SourceDir.FullName, "");

                    // remove leading seperator
                    if (SourceFilePath.First() == Path.DirectorySeparatorChar)
                    {
                        SourceFilePath = SourceFilePath.Substring(1);
                    }

                    string DestFilePath = Options.Transform(SourceFilePath);

                    FileInfo DestInfo = null;

                    // We may have destination info if mirroring where we prebuild it all, if not
                    // grab it now
                    if (DestStructure.ContainsKey(DestFilePath))
                    {
                        DestInfo = DestStructure[DestFilePath];
                    }
                    else
                    {
                        string FullDestPath = Path.Combine(DestDir.FullName, DestFilePath);
                        if (File.Exists(FullDestPath))
                        {
                            DestInfo = new FileInfo(FullDestPath);
                        }
                    }

                    if (DestInfo == null)
                    {
                        // No copy in dest, add it to the list
                        CopyList.Add(SourceFilePath);
                    }
                    else
                    {
                        // Check the file is the same version

                        // Difference in ticks. Even though we set the dest to the src there still appears to be minute
                        // differences in ticks. 1ms is 10k ticks...
                        Int64 TimeDelta  = Math.Abs(DestInfo.LastWriteTime.Ticks - SourceInfo.LastWriteTime.Ticks);
                        Int64 Threshhold = 100000;

                        if (DestInfo.Length != SourceInfo.Length ||
                            TimeDelta > Threshhold)
                        {
                            CopyList.Add(SourceFilePath);
                        }
                        else
                        {
                            if (Options.Verbose)
                            {
                                Log.Info("Will skip copy to {0}. File up to date.", DestInfo.FullName);
                            }
                            else
                            {
                                Log.Verbose("Will skip copy to {0}. File up to date.", DestInfo.FullName);
                            }
                        }

                        // Remove it from the map
                        DestStructure.Remove(DestFilePath);
                    }
                }

                // If set to mirror, delete all the files that were not in source
                if (IsMirroring)
                {
                    // Now go through the remaining map items and delete them
                    foreach (var Pair in DestStructure)
                    {
                        DeletionList.Add(Pair.Key);
                    }

                    foreach (string RelativePath in DeletionList)
                    {
                        FileInfo DestInfo = new FileInfo(Path.Combine(DestDir.FullName, RelativePath));

                        if (Options.Verbose)
                        {
                            Log.Info("Deleting extra file {0}", DestInfo.FullName);
                        }
                        else
                        {
                            Log.Verbose("Deleting extra file {0}", DestInfo.FullName);
                        }

                        try
                        {
                            // avoid an UnauthorizedAccessException by making sure file isn't read only
                            DestInfo.IsReadOnly = false;
                            DestInfo.Delete();
                        }
                        catch (Exception Ex)
                        {
                            Log.Warning("Failed to delete file {0}. {1}", DestInfo.FullName, Ex);
                        }
                    }

                    // delete empty directories
                    DirectoryInfo DestDirInfo = new DirectoryInfo(DestDirPath);

                    DirectoryInfo[] AllSubDirs = DestDirInfo.GetDirectories("*", SearchOption.AllDirectories);

                    foreach (DirectoryInfo SubDir in AllSubDirs)
                    {
                        try
                        {
                            if (SubDir.GetFiles().Length == 0 && SubDir.GetDirectories().Length == 0)
                            {
                                if (Options.Verbose)
                                {
                                    Log.Info("Deleting empty dir {0}", SubDir.FullName);
                                }
                                else
                                {
                                    Log.Verbose("Deleting empty dir {0}", SubDir.FullName);
                                }

                                SubDir.Delete(true);
                            }
                        }
                        catch (Exception Ex)
                        {
                            // handle the case where a file is locked
                            Log.Info("Failed to delete directory {0}. {1}", SubDir.FullName, Ex);
                        }
                    }
                }

                CancellationTokenSource CTS = new CancellationTokenSource();

                // todo - make param..
                var POptions = new ParallelOptions {
                    MaxDegreeOfParallelism = 1, CancellationToken = CTS.Token
                };

                // install a cancel handler so we can stop parallel-for gracefully
                Action CancelHandler = delegate()
                {
                    CTS.Cancel();
                };

                Globals.AbortHandlers.Add(CancelHandler);

                // now do the work
                Parallel.ForEach(CopyList, POptions, RelativePath =>
                {
                    // ensure path exists
                    string DestPath = Path.Combine(DestDir.FullName, RelativePath);

                    if (Options.Transform != null)
                    {
                        DestPath = Options.Transform(DestPath);
                    }

                    string SourcePath = Path.Combine(SourceDir.FullName, RelativePath);
                    FileInfo DestInfo;
                    FileInfo SrcInfo;

                    // wrap FileInfo creation with exception handler as can throw and want informative error
                    try
                    {
                        DestInfo = new FileInfo(DestPath);
                        SrcInfo  = new FileInfo(SourcePath);
                    }
                    catch (Exception Ex)
                    {
                        throw new Exception(string.Format("FileInfo creation failed for Source:{0}, Dest:{1}, with: {2}", SourcePath, DestPath, Ex.Message));
                    }

                    // ensure directory exists
                    DestInfo.Directory.Create();

                    string DestFile = DestInfo.FullName;

                    if (Options.Transform != null)
                    {
                        DestFile = Options.Transform(DestFile);
                    }

                    int Tries   = 0;
                    bool Copied = false;

                    do
                    {
                        try
                        {
                            if (Options.Verbose)
                            {
                                Log.Info("Copying to {0}", DestFile);
                            }
                            else
                            {
                                Log.Verbose("Copying to {0}", DestFile);
                            }

                            SrcInfo.CopyTo(DestFile, true);

                            // Clear and read-only attrib and set last write time
                            FileInfo DestFileInfo      = new FileInfo(DestFile);
                            DestFileInfo.IsReadOnly    = false;
                            DestFileInfo.LastWriteTime = SrcInfo.LastWriteTime;
                            Copied = true;
                        }
                        catch (Exception ex)
                        {
                            if (Tries++ < Options.Retries)
                            {
                                Log.Info("Copy to {0} failed, retrying {1} of {2} in 30 secs..", DestFile, Tries, Options.Retries);
                                // todo - make param..
                                Thread.Sleep(30000);
                            }
                            else
                            {
                                using (var PauseEC = new ScopedSuspendECErrorParsing())
                                {
                                    Log.Error("File Copy failed with {0}.", ex.Message);
                                }
                                throw new Exception(string.Format("File Copy failed with {0}.", ex.Message));
                            }
                        }
                    } while (Copied == false);
                });

                TimeSpan Duration = DateTime.Now - StartTime;

                if (Duration.TotalSeconds > 10)
                {
                    if (Options.Verbose)
                    {
                        Log.Info("Copied Directory in {0}", Duration.ToString(@"mm\m\:ss\s"));
                    }
                    else
                    {
                        Log.Verbose("Copied Directory in {0}", Duration.ToString(@"mm\m\:ss\s"));
                    }
                }

                // remove cancel handler
                Globals.AbortHandlers.Remove(CancelHandler);
            }
示例#14
0
        async void RenameToolStripMenuItem_ClickAsync(object sender, EventArgs e)
        {
            TreeNode node = Containers.SelectedNode;

            if (node == null)
            {
                MessageBox.Show("Choose an item to rename first");
                return;
            }

            CloudBlobDirectory sourceDir;
            CloudBlobDirectory targetDir;
            var options = new CopyDirectoryOptions {
                Recursive = true
            };
            TreeNode parentNode = node.Parent;

            switch (node.ImageIndex)
            {
            case 0:
                new AskForm("Rename Container").ShowDialog();
                if (Answer == null)
                {
                    return;
                }

                if (!Answer.Any(n => n.IsLetter()))
                {
                    MessageBox.Show("Russian is not allowed");
                    return;
                }
                ProgressBar.Visible = true;

                CloudBlobContainer sourceC = Client.GetContainerReference(node.Text);
                CloudBlobContainer targetC = Client.GetContainerReference(Answer);
                await targetC.CreateIfNotExistsAsync();

                foreach (var blob in sourceC.ListBlobs())
                {
                    switch (blob)
                    {
                    case CloudBlobDirectory cbd:
                        sourceDir = sourceC.GetDirectoryReference(blob.Uri.Directory());
                        targetDir = targetC.GetDirectoryReference(blob.Uri.Directory());
                        await TransferManager.CopyDirectoryAsync(sourceDir, targetDir, true, options, null);

                        break;

                    case CloudBlob cb:
                        CloudBlob sourceBlob = sourceC.GetBlobReference(blob.Uri.File());
                        CloudBlob targetBlob = targetC.GetBlobReference(blob.Uri.File());
                        await TransferManager.CopyAsync(sourceBlob, targetBlob, true);

                        break;
                    }
                }
                await sourceC.DeleteIfExistsAsync();

                break;

            case 1:
                switch (parentNode.ImageIndex)
                {
                case 0:
                    CloudBlobContainer container = Client.GetContainerReference(parentNode.Text);
                    sourceDir = container.GetDirectoryReference(node.Text);

                    new AskForm("Rename Directory").ShowDialog();
                    if (Answer == null)
                    {
                        return;
                    }
                    ProgressBar.Visible = true;

                    targetDir = container.GetDirectoryReference(Answer);
                    await TransferManager.CopyDirectoryAsync(sourceDir, targetDir, true, options, null);
                    await DeleteDirectory(sourceDir);

                    break;

                case 1:
                    (TreeNode containerNode, int count, string[] hier) = GetContainerNode(parentNode);
                    Array.Reverse(hier);

                    container = Client.GetContainerReference(containerNode.Text);
                    sourceDir = container.GetDirectoryReference(hier[0]);

                    for (int i = 0; i < count; i++)
                    {
                        sourceDir = sourceDir.GetDirectoryReference(hier[i + 1]);
                    }
                    sourceDir = sourceDir.GetDirectoryReference(node.Text);

                    new AskForm("Rename Directory").ShowDialog();
                    if (Answer == null)
                    {
                        return;
                    }
                    ProgressBar.Visible = true;

                    targetDir = sourceDir.Parent.GetDirectoryReference(Answer);
                    await TransferManager.CopyDirectoryAsync(sourceDir, targetDir, true, options, null);
                    await DeleteDirectory(sourceDir);

                    break;
                }
                break;

            case 2:
                switch (parentNode.ImageIndex)
                {
                case 0:
                    CloudBlobContainer container  = Client.GetContainerReference(parentNode.Text);
                    CloudBlob          sourceBlob = container.GetBlobReference(node.Text);

                    new AskForm("Rename Cloud Blob").ShowDialog();
                    if (Answer == null)
                    {
                        return;
                    }
                    ProgressBar.Visible = true;

                    CloudBlob targetBlob = container.GetBlobReference(Answer);
                    await TransferManager.CopyAsync(sourceBlob, targetBlob, true);

                    await sourceBlob.DeleteIfExistsAsync();

                    break;

                case 1:
                    (TreeNode containerNode, int count, string[] hier) = GetContainerNode(parentNode);
                    Array.Reverse(hier);

                    container = Client.GetContainerReference(containerNode.Text);
                    sourceDir = container.GetDirectoryReference(hier[0]);

                    for (int i = 0; i < count; i++)
                    {
                        sourceDir = sourceDir.GetDirectoryReference(hier[i + 1]);
                    }
                    sourceBlob = sourceDir.GetBlobReference(node.Text);

                    new AskForm("Rename Cloud Blob").ShowDialog();
                    if (Answer == null)
                    {
                        return;
                    }
                    ProgressBar.Visible = true;

                    targetBlob = sourceDir.GetBlobReference(Answer);
                    await TransferManager.CopyAsync(sourceBlob, targetBlob, true);

                    await sourceBlob.DeleteIfExistsAsync();

                    break;
                }
                break;
            }
            RefreshAll();
            ProgressBar.Visible = false;
        }
示例#15
0
        private async static Task CopyDirectoryAsync(CloudBlobDirectory sourceDirectory, CloudBlobDirectory destinationDirectory, CopyDirectoryOptions copyDirectoryOptions, TransferContext transferContext, TransferCheckpoint transferCheckpoint, CancellationTokenSource cancellationTokenSource)
        {
            // Start the transfer
            try
            {
                await TransferManager.CopyDirectoryAsync(
                    sourceBlobDir : sourceDirectory,
                    destBlobDir : destinationDirectory,
                    isServiceCopy : true,
                    options : copyDirectoryOptions,
                    context : transferContext,
                    cancellationToken : cancellationTokenSource.Token);

                // Store the transfer checkpoint.
                transferCheckpoint = transferContext.LastCheckpoint;
            }
            catch (TransferException te)
            {
                // Swallow Exceptions from skipped files in Overwrite Callback
                // Log any other Transfer Exceptions
                if (te.ErrorCode != TransferErrorCode.SubTransferFails)
                {
                    StringBuilder sb = new StringBuilder();
                    sb.AppendLine("Transfer Error: " + te.Message);
                    sb.AppendLine("Transfer Error Code: " + te.ErrorCode);
                    await _log.WriteLineAsync(sb.ToString());
                }
            }
        }
示例#16
0
        // This version uses CopyDirectoryAsync in DML 0.2. I'm not sure it is faster than what I did above copying them manually in DML 0.1
        public async static Task ProcessQueueMessage2([QueueTrigger("backupqueue")] CopyItem copyItem, TextWriter log, CancellationToken cancelToken)
        {
            _log = log;
            log.WriteLine("Job Start: " + copyItem.JobName);

            // This class accumulates transfer data during the process
            ProgressRecorder progressRecorder = new ProgressRecorder();

            try
            {
                // OpContext to track PreCopy Retries on Azure Storage
                // DML has its own context object and retry
                OperationContext opContext = new OperationContext();
                opContext.Retrying += StorageRequest_Retrying;

                // Define Blob Request Options
                BlobRequestOptions blobRequestOptions = new BlobRequestOptions
                {
                    // Defined Exponential Retry Policy above
                    RetryPolicy = _retryPolicy
                };

                // Set the number of parallel tasks in DML. This allows it to copy multiple
                // items at once when copying a container or directory
                //int parallelTasks = Environment.ProcessorCount * 8;
                int parallelTasks = Convert.ToInt32(ConfigurationManager.AppSettings["ParallelTasks"]);

                // Set the number of connections so each DML copy task has its own connection to Azure Storage
                ServicePointManager.DefaultConnectionLimit = Environment.ProcessorCount * 8;

                TransferManager.Configurations.ParallelOperations = parallelTasks; //64;

                log.WriteLine("Parallel Operations = " + parallelTasks.ToString());

                // Short circuit additional request round trips. We are not chunking and
                // uploading large amounts of data where we'd send 100's so set to false
                ServicePointManager.Expect100Continue = false;

                // CancellationTokenSource used to cancel the transfer
                CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();

                // Represents a checkpoint from which a transfer may be resumed and continued
                // This is set within the CopyContainerAsync function
                TransferCheckpoint transferCheckpoint = null;

                // Open connections to both storage accounts
                CloudStorageAccount sourceAccount      = GetAccount(copyItem.SourceAccountToken);
                CloudStorageAccount destinationAccount = GetAccount(copyItem.DestinationAccountToken);

                // Context object for the transfer, provides additional runtime information about its execution
                TransferContext transferContext = new TransferContext
                {
                    // Pipe transfer progress data to ProgressRecorder
                    ProgressHandler = progressRecorder,

                    // Callback to overwrite destination if it exists
                    OverwriteCallback = (source, destination) =>
                    {
                        return(OverwriteFile(source, destination, sourceAccount, destinationAccount, copyItem, blobRequestOptions, opContext));
                    }
                };

                CopyDirectoryOptions copyDirectoryOptions = new CopyDirectoryOptions
                {
                    IncludeSnapshots = true,
                    Recursive        = true
                };

                // Get the root source and destination directories for the two containers to be copied
                CloudBlobDirectory sourceDirectory = await GetDirectoryAsync(sourceAccount, copyItem.SourceContainer, blobRequestOptions);

                CloudBlobDirectory destinationDirectory = await GetDirectoryAsync(destinationAccount, copyItem.DestinationContainer, blobRequestOptions);

                // Copy the container
                await CopyDirectoryAsync(sourceDirectory, destinationDirectory, copyDirectoryOptions, transferContext, transferCheckpoint, cancellationTokenSource);


                log.WriteLine(progressRecorder.ToString());
                log.WriteLine("Job Complete: " + copyItem.JobName);
            }
            catch (Exception ex)
            {
                log.WriteLine("Backup Job error: " + copyItem.JobName + ", Error: " + ex.Message);
                log.WriteLine(progressRecorder.ToString());
            }
        }