Exemplo n.º 1
0
        /// <summary>
        ///     Check for the existence of hibernated sessions in the given filesystem root directory.
        /// </summary>
        public static bool HibernatedSessionsExists(this IAbsFileSystem fileSystem, AbsolutePath rootPath)
        {
            Contract.Requires(fileSystem != null);
            Contract.Requires(rootPath != null);

            return(fileSystem.DirectoryExists(rootPath) && fileSystem.FileExists(rootPath / FileName));
        }
Exemplo n.º 2
0
        /// <inheritdoc />
        protected override async Task <BoolResult> StartupCoreAsync(OperationContext context)
        {
            if (!FileSystem.DirectoryExists(Config.DataRootPath))
            {
                FileSystem.CreateDirectory(Config.DataRootPath);
            }

            await StartupStoresAsync(context).ThrowIfFailure();

            await LoadHibernatedSessionsAsync(context);

            InitializeAndStartGrpcServer(Config.GrpcPort, BindServices(), Config.RequestCallTokensPerCompletionQueue);

            _serviceReadinessChecker.Ready(context);

            _sessionExpirationCheckTimer = new IntervalTimer(
                () => CheckForExpiredSessionsAsync(context),
                MinTimeSpan(Config.UnusedSessionHeartbeatTimeout, TimeSpan.FromMinutes(CheckForExpiredSessionsPeriodMinutes)),
                message => Tracer.Debug(context, $"[{CheckForExpiredSessionsName}] message"));

            _logIncrementalStatsTimer = new IntervalTimer(
                () => LogIncrementalStatsAsync(context),
                Config.LogIncrementalStatsInterval);

            return(BoolResult.Success);
        }
        /// <summary>
        ///     Check if a valid content store configuration is present in a CAS root directory.
        /// </summary>
        /// <summary>
        ///     Deserialize a ContentStoreConfiguration from JSON in the standard filename in a CAS root directory.
        /// </summary>
        public static Result <ContentStoreConfiguration> ReadContentStoreConfiguration(this IAbsFileSystem fileSystem, AbsolutePath rootPath)
        {
            Contract.Requires(rootPath != null);

            AbsolutePath jsonPath = rootPath / FileName;
            ContentStoreConfiguration configuration;

            if (!fileSystem.DirectoryExists(rootPath))
            {
                return(new Result <ContentStoreConfiguration>($"Directory path=[{rootPath}] does not exist"));
            }

            if (!fileSystem.FileExists(jsonPath))
            {
                return(new Result <ContentStoreConfiguration>($"ContentStoreConfiguration not present at path=[{jsonPath}]"));
            }

            using (Stream stream = fileSystem.OpenReadOnly(jsonPath, FileShare.None))
            {
                configuration = stream.DeserializeFromJSON <ContentStoreConfiguration>();
            }

            if (!configuration.IsValid)
            {
                return(new Result <ContentStoreConfiguration>($"Invalid content store configuration at path=[{jsonPath}]"));
            }

            return(new Result <ContentStoreConfiguration>(configuration));
        }
Exemplo n.º 4
0
        /// <inheritdoc />
        protected override async Task <BoolResult> StartupCoreAsync(OperationContext context)
        {
            // Splitting initialization into two pieces:
            // Normal startup procedure and post-initialization step that notifies all
            // the special stores that the initialization has finished.
            // This is a workaround to make sure hibernated sessions are fully restored
            // before FileSystemContentStore can evict the content.
            var result = await tryStartupCoreAsync();

            foreach (var store in StoresByName.Values)
            {
                if (store is IContentStore contentStore)
                {
                    contentStore.PostInitializationCompleted(context, result);
                }
            }

            return(result);

            async Task <BoolResult> tryStartupCoreAsync()
            {
                try
                {
                    if (!FileSystem.DirectoryExists(Config.DataRootPath))
                    {
                        FileSystem.CreateDirectory(Config.DataRootPath);
                    }

                    await StartupStoresAsync(context).ThrowIfFailure();

                    await LoadHibernatedSessionsAsync(context);

                    InitializeAndStartGrpcServer(Config.GrpcPort, BindServices(), Config.RequestCallTokensPerCompletionQueue, Config.GrpcThreadPoolSize ?? DefaultGrpcThreadPoolSize);

                    _serviceReadinessChecker.Ready(context);

                    _sessionExpirationCheckTimer = new IntervalTimer(
                        () => CheckForExpiredSessionsAsync(context),
                        MinTimeSpan(Config.UnusedSessionHeartbeatTimeout, TimeSpan.FromMinutes(CheckForExpiredSessionsPeriodMinutes)),
                        message => Tracer.Debug(context, $"[{CheckForExpiredSessionsName}] message"));

                    _logIncrementalStatsTimer = new IntervalTimer(
                        () => LogIncrementalStatsAsync(context),
                        Config.LogIncrementalStatsInterval);

                    _logMachineStatsTimer = new IntervalTimer(
                        () => LogMachinePerformanceStatistics(context),
                        Config.LogMachineStatsInterval);

                    return(BoolResult.Success);
                }
                catch (Exception e)
                {
                    return(new BoolResult(e));
                }
            }
        }
Exemplo n.º 5
0
        /// <summary>
        ///     Delete the hibernated sessions file in the given filesystem root directory.
        /// </summary>
        public static Task DeleteHibernatedSessions(this IAbsFileSystem fileSystem, AbsolutePath rootPath, string fileName)
        {
            Contract.Requires(rootPath != null);

            return(Task.Run(() =>
            {
                var jsonPath = rootPath / fileName;
                if (fileSystem.DirectoryExists(rootPath) && fileSystem.FileExists(jsonPath))
                {
                    fileSystem.DeleteFile(jsonPath);
                }
            }));
        }
Exemplo n.º 6
0
 /// <inheritdoc />
 public void Dispose()
 {
     try
     {
         if (_fileSystem.DirectoryExists(Path))
         {
             _fileSystem.DeleteDirectory(Path, DeleteOptions.All);
         }
     }
     catch (Exception exception)
     {
         Debug.WriteLine("Unable to cleanup due to exception: {0}", exception);
     }
 }
Exemplo n.º 7
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}]"));
Exemplo n.º 8
0
        protected override async Task <BoolResult> StartupCoreAsync(OperationContext context)
        {
            await _store.StartupAsync(context).ThrowIfFailure();

            if (_fileSystem.DirectoryExists(_rootPath / "temp"))
            {
                _fileSystem.DeleteDirectory(_rootPath / "temp", DeleteOptions.All);
            }

            await _copier.StartupAsync(context).ThrowIfFailure();

            CreateSessionResult <IContentSession> sessionResult = _store.CreateSession(context, SessionName, ImplicitPin.None).ThrowIfFailure();

            _session = sessionResult.Session !;

            return(await _session.StartupAsync(context));
        }
        /// <summary>
        ///     Initializes a new instance of the <see cref="MemoryContentDirectory" /> class.
        /// </summary>
        public MemoryContentDirectory(IAbsFileSystem fileSystem, AbsolutePath directoryPath, IContentDirectoryHost host = null)
        {
            Contract.Requires(fileSystem != null);
            Contract.Requires(directoryPath != null);

            _fileSystem     = fileSystem;
            _filePath       = directoryPath / BinaryFileName;
            _backupFilePath = directoryPath / BinaryBackupFileName;
            _host           = host;

            if (!_fileSystem.DirectoryExists(directoryPath))
            {
                throw new ArgumentException("must be path to a directory", nameof(directoryPath));
            }

            FilePath = _filePath;
        }
        /// <summary>
        ///     Serialize a ContentStoreConfiguration to JSON in the standard filename in a CAS root directory.
        /// </summary>
        public static void Write(this ContentStoreConfiguration configuration, IAbsFileSystem fileSystem, AbsolutePath rootPath)
        {
            Contract.Requires(rootPath != null);
            Contract.Requires(configuration != null);
            Contract.Requires(configuration.IsValid);

            AbsolutePath jsonPath = rootPath / FileName;

            if (!fileSystem.DirectoryExists(rootPath))
            {
                throw new CacheException($"Directory path=[{rootPath}] does not exist");
            }

            using (var stream = fileSystem.Open(jsonPath, FileAccess.Write, FileMode.Create, FileShare.None))
            {
                configuration.SerializeToJSON(stream);
            }
        }
Exemplo n.º 11
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,
                                           async fileInfo =>
                {
                    var fileName = fileInfo.FullPath.FileName;
                    var targetFilePath = backupPath / fileName;

                    await _fileSystem.CopyFileAsync(fileInfo.FullPath, targetFilePath, replaceExisting: true);

                    ++numCopiedFiles;
                });

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

                return new Result <AbsolutePath>(backupPath);
            }, extraEndMessage : _ => $"From=[{instancePath}] To=[{backupPath?.ToString() ?? "Unknown"}] NumCopiedFiles=[{numCopiedFiles}]"));
Exemplo n.º 12
0
        public void CanBackupSingleFile()
        {
            WithLogManager(TimeSpan.FromDays(7),
                           async(context, manager) =>
            {
                var instanceFolder = await GenerateRocksDbInstanceFolderAsync(numSstFiles: 0, numLogFiles: 1);
                var backupFolder   = (await manager.BackupAsync(context, instanceFolder)).ShouldBeSuccess().Value;
                Assert.True(_fileSystem.DirectoryExists(backupFolder));

                var files = _fileSystem.EnumerateFiles(backupFolder, EnumerateOptions.None).ToList();
                Assert.Equal(files.Count, 1);
                Assert.Equal(files[0].FullPath.FileName, "LOG");
            });
        }
Exemplo n.º 13
0
        protected override async Task <BoolResult> StartupCoreAsync(OperationContext context)
        {
            // Splitting initialization into two pieces:
            // Normal startup procedure and post-initialization step that notifies all
            // the special stores that the initialization has finished.
            // This is a workaround to make sure hibernated sessions are fully restored
            // before FileSystemContentStore can evict the content.
            var result = await tryStartupCoreAsync();

            if (!result)
            {
                // We should not be running post initialization operation if the startup operation failed.
                return(result);
            }

            foreach (var store in StoresByName.Values)
            {
                if (store is IContentStore contentStore)
                {
                    contentStore.PostInitializationCompleted(context, result);
                }
            }

            return(result);

            async Task <BoolResult> tryStartupCoreAsync()
            {
                try
                {
                    if (!FileSystem.DirectoryExists(Config.DataRootPath))
                    {
                        FileSystem.CreateDirectory(Config.DataRootPath);
                    }

                    await StartupStoresAsync(context).ThrowIfFailure();

                    foreach (var endpoint in GrpcEndpoints)
                    {
                        await endpoint.StartupAsync(context).ThrowIfFailure();
                    }

                    await LoadHibernatedSessionsAsync(context);

                    if (!Config.DisableGrpcServer)
                    {
                        InitializeAndStartGrpcServer(context, Config);
                    }

                    _serviceReadinessChecker.Ready(context);

                    _sessionExpirationCheckTimer = new IntervalTimer(
                        () => CheckForExpiredSessionsAsync(context),
                        MinTimeSpan(Config.UnusedSessionHeartbeatTimeout, TimeSpan.FromMinutes(CheckForExpiredSessionsPeriodMinutes)),
                        logAction: message => Tracer.Debug(context, $"{CheckForExpiredSessionsName}: {message}"));

                    _logIncrementalStatsTimer = new IntervalTimer(
                        () => LogIncrementalStatsAsync(context, logAtShutdown: false),
                        Config.LogIncrementalStatsInterval);

                    _logMachineStatsTimer = new IntervalTimer(
                        () => LogMachinePerformanceStatistics(context),
                        Config.LogMachineStatsInterval);

                    return(BoolResult.Success);
                }
                catch (Exception e)
                {
                    return(new BoolResult(e));
                }
            }
        }