Beispiel #1
0
        public async Task <Result <AbsolutePath> > BackupAsync(OperationContext context, AbsolutePath instancePath, string?name = null)
        {
            int          numCopiedFiles = 0;
            AbsolutePath?backupPath     = null;

            return(await context.PerformOperationAsync(_tracer, async() =>
            {
                var backupTime = _clock.UtcNow.ToString("yyyyMMdd_HHmmss", CultureInfo.InvariantCulture);
                var backupName = backupTime;
                if (!string.IsNullOrEmpty(name))
                {
                    backupName += $"-{name}";
                }
                backupPath = _backupPath / backupName;

                // Unlikely, but it is possible for GC to start running and think that it should purge this directory,
                // this avoids the scenario.
                using var _ = await _locks.AcquireAsync(backupPath);

                if (_fileSystem.DirectoryExists(backupPath))
                {
                    _fileSystem.DeleteDirectory(backupPath, DeleteOptions.All);
                }
                _fileSystem.CreateDirectory(backupPath);

                // See: https://github.com/facebook/rocksdb/wiki/rocksdb-basics#database-debug-logs
                _fileSystem.EnumerateFiles(instancePath, "*LOG*", false,
                                           fileInfo =>
                {
                    var fileName = fileInfo.FullPath.FileName;
                    var targetFilePath = backupPath / fileName;

                    // Do not use Async here: since EnumerateFiles takes an Action, making this async means we'll
                    // need to make the action async as well, which is equivalent to an async void function. That
                    // leads to race conditions.
#pragma warning disable AsyncFixer02 // Long running or blocking operations under an async method
                    _fileSystem.CopyFile(fileInfo.FullPath, targetFilePath, replaceExisting: true);
#pragma warning restore AsyncFixer02 // Long running or blocking operations under an async method

                    ++numCopiedFiles;
                });

                if (numCopiedFiles == 0)
                {
                    _fileSystem.DeleteDirectory(backupPath, DeleteOptions.All);
                }

                return new Result <AbsolutePath>(backupPath);
            }, extraEndMessage : _ => $"From=[{instancePath}] To=[{backupPath?.ToString() ?? "Unknown"}] NumCopiedFiles=[{numCopiedFiles}]"));