public async Task Roundtrip() { using (var directory = new DisposableDirectory(FileSystem)) { const Capabilities capabilities = Capabilities.Heartbeat; var pins = ContentHashes.Select(x => x.Serialize()).ToList(); var expirationTicks = DateTime.UtcNow.Ticks; var sessionInfo = new HibernatedSessionInfo(1, SessionName, ImplicitPin.None, CacheName, pins, expirationTicks, capabilities); var sessions1 = new HibernatedSessions(new List <HibernatedSessionInfo> { sessionInfo }); await sessions1.WriteAsync(FileSystem, directory.Path); FileSystem.HibernatedSessionsExists(directory.Path).Should().BeTrue(); var fileSize = FileSystem.GetFileSize(directory.Path / HibernatedSessionsExtensions.FileName); fileSize.Should().BeGreaterThan(0); var sessions2 = await FileSystem.ReadHibernatedSessionsAsync(directory.Path); sessions2.Sessions.Count.Should().Be(1); sessions2.Sessions[0].Pins.Count.Should().Be(ContentHashCount); sessions2.Sessions[0].ExpirationUtcTicks.Should().Be(expirationTicks); sessions2.Sessions[0].Capabilities.Should().Be(capabilities); await FileSystem.DeleteHibernatedSessions(directory.Path); } }
public async Task RoundtripSessionsWithSameName() { const int count = 3; using (var directory = new DisposableDirectory(FileSystem)) { var sessionInfoList = new List <HibernatedSessionInfo>(); foreach (var i in Enumerable.Range(0, count)) { List <string> pins = ContentHashes.Select(x => x.Serialize()).ToList(); sessionInfoList.Add(new HibernatedSessionInfo(i, SessionName, ImplicitPin.None, CacheName, pins, DateTime.UtcNow.Ticks, Capabilities.None)); } var sessions1 = new HibernatedSessions(sessionInfoList); await sessions1.WriteAsync(FileSystem, directory.Path); FileSystem.HibernatedSessionsExists(directory.Path).Should().BeTrue(); var sessions2 = await FileSystem.ReadHibernatedSessionsAsync(directory.Path); sessions2.Sessions.Count.Should().Be(count); sessions2.Sessions.All(s => s.Pins.Count == ContentHashCount).Should().BeTrue(); sessions2.Sessions.All(s => s.Session == SessionName).Should().BeTrue(); sessions2.Sessions.All(s => s.Cache == CacheName).Should().BeTrue(); await FileSystem.DeleteHibernatedSessions(directory.Path); } }
public async Task Roundtrip() { var fileName = $"{Guid.NewGuid()}.json"; using (var directory = new DisposableDirectory(FileSystem)) { var sessionId = 42; var serializedConfig = "Foo"; var pat = Guid.NewGuid().ToString(); var numOperations = 3; var operations = Enumerable.Range(0, numOperations) .Select(_ => generateRandomOperation()) .ToList(); var sessionInfo = new HibernatedCacheSessionInfo(sessionId, serializedConfig, pat, operations); var sessions1 = new HibernatedSessions <HibernatedCacheSessionInfo>(new List <HibernatedCacheSessionInfo> { sessionInfo }); await sessions1.WriteAsync(FileSystem, directory.Path, fileName); FileSystem.HibernatedSessionsExists(directory.Path, fileName).Should().BeTrue(); var fileSize = FileSystem.GetFileSize(directory.Path / fileName); fileSize.Should().BeGreaterThan(0); var sessions2 = await FileSystem.ReadHibernatedSessionsAsync <HibernatedCacheSessionInfo>(directory.Path, fileName); sessions2.Sessions.Count.Should().Be(1); sessions2.Sessions[0].Id.Should().Be(sessionId); sessions2.Sessions[0].SerializedSessionConfiguration.Should().Be(serializedConfig); sessions2.Sessions[0].Pat.Should().Be(pat); sessions2.Sessions[0].PendingPublishingOperations.Should().BeEquivalentTo(operations); await FileSystem.DeleteHibernatedSessions(directory.Path, fileName); PublishingOperation generateRandomOperation() { var amountOfHashes = 3; var hashes = Enumerable.Range(0, amountOfHashes).Select(_ => ContentHash.Random()).ToArray(); var contentHashList = new ContentHashList(hashes); var determinism = CacheDeterminism.ViaCache(CacheDeterminism.NewCacheGuid(), DateTime.UtcNow.AddMilliseconds(ThreadSafeRandom.Generator.Next())); var contentHashListWithDeterminism = new ContentHashListWithDeterminism(contentHashList, determinism); var fingerprint = new Fingerprint(ContentHash.Random().ToByteArray()); var selector = new Selector(ContentHash.Random()); var strongFingerprint = new StrongFingerprint(fingerprint, selector); return(new PublishingOperation { ContentHashListWithDeterminism = contentHashListWithDeterminism, StrongFingerprint = strongFingerprint }); } } }
protected override async Task HibernateSessionsAsync( Context context, IDictionary <int, ISessionHandle <ICacheSession, LocalCacheServerSessionData> > sessionHandles) { var sessionInfoList = new List <HibernatedCacheSessionInfo>(sessionHandles.Count); foreach (var keyValuePair in sessionHandles) { var id = keyValuePair.Key; var handle = keyValuePair.Value; if (handle.Session is IHibernateCacheSession hibernateSession) { IList <PublishingOperation>?pending = null; string?serializedConfig = null; if (handle.SessionData.PublishingConfig is not null) { pending = hibernateSession.GetPendingPublishingOperations(); serializedConfig = DynamicJson.Serialize(handle.SessionData.PublishingConfig); } var info = new HibernatedCacheSessionInfo( id, serializedConfig, handle.SessionData.Pat, pending); sessionInfoList.Add(info); } } var hibernatedSessions = new HibernatedSessions <HibernatedCacheSessionInfo>(sessionInfoList); try { await hibernatedSessions.WriteProtectedAsync(FileSystem, Config.DataRootPath, HibernatedSessionsFileName); } catch (Exception e) when(e is NotSupportedException) { Tracer.Debug(context, e, "Failed to protect hibernated sessions because it is not supported by the current OS. " + $"Attempting to hibernate while unprotected."); hibernatedSessions.Write(FileSystem, Config.DataRootPath, HibernatedSessionsFileName); } var contentHandles = new Dictionary <int, ISessionHandle <IContentSession, LocalContentServerSessionData> >(sessionHandles.Count); foreach (var keyValuePair in sessionHandles) { contentHandles[keyValuePair.Key] = keyValuePair.Value; } await LocalContentServer.HibernateSessionsAsync(context, contentHandles, Config, Tracer, FileSystem); }
public async Task HibernationDataNotLoadedIfStoreStartupFails() { const string scenario = nameof(HibernationDataNotLoadedIfStoreStartupFails); var fileName = $"{Guid.NewGuid()}.json"; var context = new Context(Logger); using (var directory = new DisposableDirectory(FileSystem)) { var rootPath = directory.Path; var contentHash = ContentHash.Random(); var pins = new List <string> { contentHash.Serialize() }; var hibernatedSessionInfo = new HibernatedContentSessionInfo(SessionId, SessionName, ImplicitPin.None, CacheName, pins, 0, Capabilities.None); var hibernatedSessions = new HibernatedSessions <HibernatedContentSessionInfo>(new List <HibernatedContentSessionInfo> { hibernatedSessionInfo }); hibernatedSessions.Write(FileSystem, rootPath, fileName); var namedCacheRoots = new Dictionary <string, AbsolutePath> { { CacheName, rootPath } }; var grpcPort = PortExtensions.GetNextAvailablePort(); var grpcPortFileName = Guid.NewGuid().ToString(); var configuration = new ServiceConfiguration(namedCacheRoots, rootPath, MaxConnections, GracefulShutdownSeconds, grpcPort, grpcPortFileName); Func <AbsolutePath, IContentStore> contentStoreFactory = (path) => new TestFailingContentStore(); var localContentServerConfiguration = new LocalServerConfiguration(configuration) { UnusedSessionHeartbeatTimeout = TimeSpan.FromSeconds(TimeoutSecs), UnusedSessionTimeout = TimeSpan.FromSeconds(TimeoutSecs * 4), RequestCallTokensPerCompletionQueue = 10, }; using (var server = new LocalContentServer(FileSystem, Logger, scenario, contentStoreFactory, localContentServerConfiguration)) { var r = await server.StartupAsync(context); r.ShouldBeError(TestFailingContentStore.FailureMessage); FileSystem.HibernatedSessionsExists(rootPath, fileName).Should().BeTrue("The hibernation data should not have been read/deleted"); } } }
public async Task Roundtrip(bool useProtected) { var fileName = $"{Guid.NewGuid()}.json"; using (var directory = new DisposableDirectory(FileSystem)) { const Capabilities capabilities = Capabilities.Heartbeat; var pins = ContentHashes.Select(x => x.Serialize()).ToList(); var expirationTicks = DateTime.UtcNow.Ticks; var sessionInfo = new HibernatedContentSessionInfo(1, SessionName, ImplicitPin.None, CacheName, pins, expirationTicks, capabilities); var sessions1 = new HibernatedSessions <HibernatedContentSessionInfo>(new List <HibernatedContentSessionInfo> { sessionInfo }); if (useProtected) { await sessions1.WriteProtectedAsync(FileSystem, directory.Path, fileName); } else { sessions1.Write(FileSystem, directory.Path, fileName); } FileSystem.HibernatedSessionsExists(directory.Path, fileName).Should().BeTrue(); var fileSize = FileSystem.GetFileSize(directory.Path / fileName); fileSize.Should().BeGreaterThan(0); var sessions2 = useProtected ? await FileSystem.ReadProtectedHibernatedSessionsAsync <HibernatedContentSessionInfo>(directory.Path, fileName) : await FileSystem.ReadHibernatedSessionsAsync <HibernatedContentSessionInfo>(directory.Path, fileName); sessions2.Sessions.Count.Should().Be(1); sessions2.Sessions[0].Pins.Count.Should().Be(ContentHashCount); sessions2.Sessions[0].ExpirationUtcTicks.Should().Be(expirationTicks); sessions2.Sessions[0].Capabilities.Should().Be(capabilities); await FileSystem.DeleteHibernatedSessions(directory.Path, fileName); } }
[Trait("Category", "QTestSkip")] // Skipped public async Task RestoredSessionReleasedAfterInactivity() { const string scenario = nameof(RestoredSessionReleasedAfterInactivity); var context = new Context(Logger); using (var directory = new DisposableDirectory(FileSystem)) { var rootPath = directory.Path; var contentHash = ContentHash.Random(); var pins = new List <string> { contentHash.Serialize() }; var hibernatedSessionInfo = new HibernatedSessionInfo(SessionId, SessionName, ImplicitPin.None, CacheName, pins, DateTime.UtcNow.Ticks, Capabilities.None); var hibernatedSessions = new HibernatedSessions(new List <HibernatedSessionInfo> { hibernatedSessionInfo }); await hibernatedSessions.WriteAsync(FileSystem, rootPath); var namedCacheRoots = new Dictionary <string, AbsolutePath> { { CacheName, rootPath } }; var grpcPort = PortExtensions.GetNextAvailablePort(); var grpcPortFileName = Guid.NewGuid().ToString(); var configuration = new ServiceConfiguration(namedCacheRoots, rootPath, MaxConnections, GracefulShutdownSeconds, grpcPort, grpcPortFileName); var storeConfig = ContentStoreConfiguration.CreateWithMaxSizeQuotaMB(1); Func <AbsolutePath, IContentStore> contentStoreFactory = (path) => new FileSystemContentStore( FileSystem, SystemClock.Instance, directory.Path, new ConfigurationModel(storeConfig)); var localContentServerConfiguration = new LocalServerConfiguration(configuration) { UnusedSessionHeartbeatTimeout = TimeSpan.FromSeconds(TimeoutSecs), RequestCallTokensPerCompletionQueue = 10, }; using (var server = new LocalContentServer(FileSystem, Logger, scenario, contentStoreFactory, localContentServerConfiguration)) { var r1 = await server.StartupAsync(context); r1.ShouldBeSuccess(); var beforeIds = server.GetSessionIds(); beforeIds.Should().Contain(SessionId); // Wait one period to ensure that it times out, another to ensure that the checker finds it, and another to give it time to release it. await Task.Delay(TimeSpan.FromSeconds(TimeoutSecs * 3)); var afterIds = server.GetSessionIds(); afterIds.Count.Should().Be(0); var r2 = await server.ShutdownAsync(context); r2.ShouldBeSuccess(); } } }