From 85f2089f0e3d7ffa3b1626d497dcd2e954a00991 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 13 Sep 2026 16:44:11 +0200 Subject: [PATCH] Delete CultCache wrappers and unused members Removes FlushBackingStore, both PrepareForReloadOrShutdown overloads, PullBackingStoreRecordsAsync, TryGet, TryGetByName, TryGetByIndex, Resolve, the cache and store Logger, and LastSuccessfulFlushAtUtc on the cache and stores. GetStoredDocuments folds into GetAll. The soft flag goes from FlushAllBackingStores, ExecuteTransactionAsync, CommitBatch and PushAll. It stays on FlushAsync(bool) because CultCacheStudioWindow reflects on that signature until Cut 6. CultMesh.FlushAsync and CultNetLocal.FlushAsync keep their parameter and stop forwarding it. The store's EntryAdded/EntryUpdated/EntryDeleted subjects become protected internal Loaded/Unloaded callbacks set by the cache at attach. AddStoredDocumentInternal is synchronous, so the GetAwaiter().GetResult() bridges on the store subscriptions and the global materializer are gone. Tests: drop the LastSuccessfulFlushAtUtc asserts; OpenAsync and GetAll tests read through Get/GetAll; the persisted-global test proves the durable global loads without staging a default instead of going through selective hydration; the lease-before-observers test observes through CultCache.Watch; the PullSelected selective-hydration test is deleted. Co-Authored-By: Claude Opus 5 --- .../DirectoryMessagePackBackingStore.cs | 25 +- src/GameCult.Caching/CultCache.cs | 247 +++--------------- src/GameCult.Mesh/CultMesh.cs | 2 +- src/GameCult.Networking/CultNetLocal.cs | 2 +- .../BackingStoreTests.cs | 95 +------ 5 files changed, 55 insertions(+), 316 deletions(-) diff --git a/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs b/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs index 6af00795..1fdf07c8 100644 --- a/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs +++ b/src/GameCult.Caching.MessagePack/DirectoryMessagePackBackingStore.cs @@ -201,10 +201,7 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore } Entries[pair.Key] = pair.Value; - if (existing == null) - EntryAdded.OnNext(pair.Value); - else - EntryUpdated.OnNext(pair.Value); + Loaded?.Invoke(pair.Value); } foreach (var removedKey in _hydratedKeys.Where(key => !loaded.ContainsKey(key)).ToArray()) @@ -213,7 +210,7 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore continue; if (Entries.TryRemove(removedKey, out var removed)) - EntryDeleted.OnNext(removed); + Unloaded?.Invoke(removed); _hydratedKeys.Remove(removedKey); } @@ -307,8 +304,7 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore /// public override void CommitBatch( IReadOnlyCollection upserts, - IReadOnlyCollection deletes, - bool soft) + IReadOnlyCollection deletes) { lock (_mutationGate) { @@ -331,7 +327,7 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore _deletedKeys.TryRemove(entry.Key.Value, out _); } IsDirty = true; - PushAllCore(soft); + PushAllCore(); } catch { @@ -351,13 +347,13 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore } /// - public override void PushAll(bool soft = false) + public override void PushAll() { lock (_mutationGate) - PushAllCore(soft); + PushAllCore(); } - private void PushAllCore(bool soft) + private void PushAllCore() { if (!IsDirty && !_needsIndexUpgrade) { @@ -652,10 +648,7 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore continue; Entries[pair.Key] = pair.Value; - if (existing == null) - EntryAdded.OnNext(pair.Value); - else - EntryUpdated.OnNext(pair.Value); + Loaded?.Invoke(pair.Value); } foreach (var missingKey in selectedKeys.Where(key => !loaded.ContainsKey(key)).ToArray()) @@ -663,7 +656,7 @@ public sealed class DirectoryMessagePackBackingStore : CacheBackingStore if (_dirtyKeys.ContainsKey(missingKey) || _deletedKeys.ContainsKey(missingKey)) continue; if (Entries.TryRemove(missingKey, out var removed)) - EntryDeleted.OnNext(removed); + Unloaded?.Invoke(removed); _hydratedKeys.Remove(missingKey); } diff --git a/src/GameCult.Caching/CultCache.cs b/src/GameCult.Caching/CultCache.cs index a722d965..7f1af80e 100644 --- a/src/GameCult.Caching/CultCache.cs +++ b/src/GameCult.Caching/CultCache.cs @@ -9,7 +9,6 @@ using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; -using GameCult.Logging; using R3; namespace GameCult.Caching @@ -1281,7 +1280,6 @@ namespace GameCult.Caching private readonly SemaphoreSlim _transactionGate = new(1, 1); private readonly AsyncLocal _ambientTransaction = new(); private readonly object _stateGate = new(); - private ILogger _logger = new NullLogger(); private bool _hasUnflushedMutations; /// @@ -1314,25 +1312,11 @@ namespace GameCult.Caching InitializeGlobals(); } - /// - /// Gets or sets the cache logger. - /// - public ILogger Logger - { - get => _logger; - set => _logger = value ?? new NullLogger(); - } - /// /// Gets whether the cache currently holds unflushed mutations in any attached backing store or only in memory. /// public bool IsDirty => _hasUnflushedMutations || _backingStores.Any(store => store.IsDirty); - /// - /// Gets the UTC timestamp of the last successful flush across all attached backing stores. - /// - public DateTimeOffset? LastSuccessfulFlushAtUtc { get; private set; } - /// /// Gets or sets whether disposing the cache should flush attached dirty backing stores first. /// @@ -1405,10 +1389,8 @@ namespace GameCult.Caching { if (store == null) throw new ArgumentNullException(nameof(store)); store.AttachRegistry(_registry); - store.Logger = Logger; - store.EntryAdded.Subscribe(entry => AddStoredDocumentInternal(entry, store, raiseUpdate: true).GetAwaiter().GetResult()); - store.EntryUpdated.Subscribe(entry => AddStoredDocumentInternal(entry, store, raiseUpdate: true).GetAwaiter().GetResult()); - store.EntryDeleted.Subscribe(entry => RemoveStoredDocumentInternal(entry, store, raiseUpdate: true)); + store.Loaded = entry => AddStoredDocumentInternal(entry, store, raiseUpdate: true); + store.Unloaded = entry => RemoveStoredDocumentInternal(entry, store, raiseUpdate: true); foreach (var entry in _entries.Values.OrderBy(entry => entry.Key.Value, StringComparer.Ordinal)) { @@ -1441,35 +1423,10 @@ namespace GameCult.Caching } } - /// - /// Pulls persisted records selected by durable metadata from every attached backing store. - /// Stores without indexed selection support preserve correctness by performing a full pull. - /// - public async Task PullBackingStoreRecordsAsync(Func selector) - { - if (selector == null) throw new ArgumentNullException(nameof(selector)); - if (_ambientTransaction.Value != null) - throw new InvalidOperationException( - "CultCache hydration cannot run inside a mutation transaction; hydrate before opening the commit scope."); - - await _transactionGate.WaitAsync().ConfigureAwait(false); - try - { - foreach (var store in _backingStores) - store.PullSelected(selector); - - _hasUnflushedMutations = _backingStores.Any(store => store.IsDirty); - } - finally - { - _transactionGate.Release(); - } - } - /// /// Flushes all attached backing stores. /// - public void FlushAllBackingStores(bool soft = false) + public void FlushAllBackingStores() { if (_ambientTransaction.Value != null) throw new InvalidOperationException("A CultCache transaction owns durable commit; do not flush inside its stage callback."); @@ -1478,11 +1435,10 @@ namespace GameCult.Caching try { foreach (var store in _backingStores) - FlushBackingStoreCore(store, soft); - - RecomputeDirtyState(); - if (!IsDirty) - LastSuccessfulFlushAtUtc = DateTimeOffset.UtcNow; + { + store.PushAll(); + RecomputeDirtyState(); + } } finally { @@ -1490,64 +1446,10 @@ namespace GameCult.Caching } } - /// - /// Flushes all attached backing stores. - /// + // soft is dead. CultCacheStudioWindow reflects on FlushAsync(bool) until Cut 6 rewrites it. public Task FlushAsync(bool soft = false) { - FlushAllBackingStores(soft); - return Task.CompletedTask; - } - - /// - /// Flushes one attached backing store. - /// - public void FlushBackingStore(CacheBackingStore store, bool soft = false) - { - if (store == null) throw new ArgumentNullException(nameof(store)); - if (!_backingStores.Contains(store)) - { - throw new InvalidOperationException("Backing store is not attached to this cache."); - } - - if (_ambientTransaction.Value != null) - throw new InvalidOperationException("A CultCache transaction owns durable commit; do not flush inside its stage callback."); - - _transactionGate.Wait(); - try - { - FlushBackingStoreCore(store, soft); - } - finally - { - _transactionGate.Release(); - } - } - - private void FlushBackingStoreCore(CacheBackingStore store, bool soft) - { - store.PushAll(soft); - RecomputeDirtyState(); - if (!store.IsDirty) - { - LastSuccessfulFlushAtUtc = DateTimeOffset.UtcNow; - } - } - - /// - /// Flushes attached backing stores at a lifecycle boundary such as shutdown or assembly reload. - /// - public void PrepareForReloadOrShutdown(bool soft = false) - { - FlushAllBackingStores(soft); - } - - /// - /// Flushes attached backing stores at a lifecycle boundary such as shutdown or assembly reload. - /// - public Task PrepareForReloadOrShutdownAsync(bool soft = false) - { - PrepareForReloadOrShutdown(soft); + FlushAllBackingStores(); return Task.CompletedTask; } @@ -1556,7 +1458,7 @@ namespace GameCult.Caching /// async flow. The durable backing store is committed before the live cache and its /// observers advance; an exception discards the entire staged batch. /// - public async Task ExecuteTransactionAsync(Func stageAsync, bool soft = false) + public async Task ExecuteTransactionAsync(Func stageAsync) { if (stageAsync == null) throw new ArgumentNullException(nameof(stageAsync)); if (_ambientTransaction.Value != null) @@ -1573,7 +1475,7 @@ namespace GameCult.Caching { await stageAsync().ConfigureAwait(false); transaction.Seal(); - changes = CommitTransaction(transaction, soft); + changes = CommitTransaction(transaction); } finally { @@ -1587,14 +1489,14 @@ namespace GameCult.Caching } /// Runs a value-producing buffered cache mutation. - public async Task ExecuteTransactionAsync(Func> stageAsync, bool soft = false) + public async Task ExecuteTransactionAsync(Func> stageAsync) { if (stageAsync == null) throw new ArgumentNullException(nameof(stageAsync)); T result = default!; await ExecuteTransactionAsync(async () => { result = await stageAsync().ConfigureAwait(false); - }, soft).ConfigureAwait(false); + }).ConfigureAwait(false); return result; } @@ -1614,10 +1516,8 @@ namespace GameCult.Caching await _transactionGate.WaitAsync().ConfigureAwait(false); try { - var stored = await AddStoredDocumentInternal( - CreateStoredDocument(typeof(T), document, handle?.Key), - source: null, - raiseUpdate: false).ConfigureAwait(false); + var stored = CreateStoredDocument(typeof(T), document, handle?.Key); + AddStoredDocumentInternal(stored, source: null, raiseUpdate: false); return new CultRecordHandle(stored.Key); } finally @@ -1658,10 +1558,8 @@ namespace GameCult.Caching await _transactionGate.WaitAsync().ConfigureAwait(false); try { - var stored = await AddStoredDocumentInternal( - CreateStoredDocument(documentType, document, key), - source: null, - raiseUpdate: false).ConfigureAwait(false); + var stored = CreateStoredDocument(documentType, document, key); + AddStoredDocumentInternal(stored, source: null, raiseUpdate: false); return stored.Key; } finally @@ -1705,33 +1603,17 @@ namespace GameCult.Caching return Get(key) as T; } - /// - /// Tries to get a typed document by record key. - /// - public bool TryGet(CultRecordKey key, out T? document) where T : class - { - document = Get(key); - return document != null; - } - /// /// Gets all cached documents assignable to the requested type. /// public IEnumerable GetAll() where T : class - { - return GetStoredDocuments().Select(entry => (T)entry.Document); - } - - /// - /// Gets typed cached records with their stable CultCache identities without scanning unrelated documents. - /// - public IEnumerable GetStoredDocuments() where T : class { lock (_stateGate) { var type = typeof(T); return VisibleStoredDocuments() .Where(entry => type.IsAssignableFrom(entry.Descriptor.DocumentType)) + .Select(entry => (T)entry.Document) .ToArray(); } } @@ -1761,15 +1643,6 @@ namespace GameCult.Caching return null; } - /// - /// Tries to get a typed document by its CultName value. - /// - public bool TryGetByName(string name, out T? document) where T : class - { - document = GetByName(name); - return document != null; - } - /// /// Gets a typed document by an indexed value. /// @@ -1784,23 +1657,6 @@ namespace GameCult.Caching return null; } - /// - /// Tries to get a typed document by an indexed value. - /// - public bool TryGetByIndex(string alias, string value, out T? document) where T : class - { - document = GetByIndex(alias, value); - return document != null; - } - - /// - /// Resolves a typed document reference against this cache. - /// - public T? Resolve(CultRecordRef reference) where T : class - { - return Get(reference.Key); - } - /// /// Removes a document by typed handle. /// @@ -1898,8 +1754,7 @@ namespace GameCult.Caching } private IReadOnlyList<(CultStoredDocument Stored, object? Previous, bool Removed)> CommitTransaction( - CultCacheTransaction transaction, - bool soft) + CultCacheTransaction transaction) { var mutations = transaction.SnapshotForCommit() .OrderBy(pair => pair.Key, StringComparer.Ordinal) @@ -1932,7 +1787,7 @@ namespace GameCult.Caching .ToArray(); foreach (var store in _backingStores) - store.CommitBatch(upserts, deleted, soft); + store.CommitBatch(upserts, deleted); var changes = new List<(CultStoredDocument Stored, object? Previous, bool Removed)>(); lock (_stateGate) @@ -1964,8 +1819,6 @@ namespace GameCult.Caching changes.Add((stored, existing?.Document, false)); } _hasUnflushedMutations = _backingStores.Any(store => store.IsDirty); - if (!IsDirty) - LastSuccessfulFlushAtUtc = DateTimeOffset.UtcNow; } return changes; @@ -2051,7 +1904,7 @@ namespace GameCult.Caching document); } - private async Task AddStoredDocumentInternal( + private void AddStoredDocumentInternal( CultStoredDocument stored, CacheBackingStore? source, bool raiseUpdate) @@ -2086,9 +1939,6 @@ namespace GameCult.Caching { OnUpdate?.Invoke(existing?.Document, stored.Document); } - - await Task.CompletedTask; - return stored; } private void RemoveStoredDocumentInternal( @@ -2154,7 +2004,7 @@ namespace GameCult.Caching descriptor, instance), source: null, - raiseUpdate: false).GetAwaiter().GetResult(); + raiseUpdate: false); } } @@ -2301,7 +2151,6 @@ namespace GameCult.Caching public abstract class CacheBackingStore : IDisposable { private CultDocumentRegistry? _registry; - private ILogger _logger = new NullLogger(); private bool _isDirty; private CultSchemaMigrationReport[] _lastSchemaMigrationReports = Array.Empty(); @@ -2317,15 +2166,6 @@ namespace GameCult.Caching protected ConcurrentDictionary Entries { get; } = new(StringComparer.Ordinal); - /// - /// Gets or sets the backing store logger. - /// - public ILogger Logger - { - get => _logger; - set => _logger = value ?? new NullLogger(); - } - /// /// Gets whether the backing store holds staged mutations not yet durably flushed. /// @@ -2335,11 +2175,6 @@ namespace GameCult.Caching protected set => _isDirty = value; } - /// - /// Gets the UTC timestamp of the last successful durable flush. - /// - public DateTimeOffset? LastSuccessfulFlushAtUtc { get; protected set; } - /// /// Gets or sets whether disposing the backing store should flush staged mutations first. /// @@ -2350,18 +2185,9 @@ namespace GameCult.Caching /// public IReadOnlyList LastSchemaMigrationReports => _lastSchemaMigrationReports; - /// - /// Publishes documents added by the backing store. - /// - public Subject EntryAdded { get; } = new(); - /// - /// Publishes documents updated by the backing store. - /// - public Subject EntryUpdated { get; } = new(); - /// - /// Publishes documents deleted by the backing store. - /// - public Subject EntryDeleted { get; } = new(); + // Set by the cache at attach; a store calls them for records it loads or drops. + protected internal Action? Loaded; + protected internal Action? Unloaded; internal void AttachRegistry(CultDocumentRegistry registry) { @@ -2401,8 +2227,7 @@ namespace GameCult.Caching /// public virtual void CommitBatch( IReadOnlyCollection upserts, - IReadOnlyCollection deletes, - bool soft) + IReadOnlyCollection deletes) { var previousEntries = Entries.ToDictionary(pair => pair.Key, pair => pair.Value, StringComparer.Ordinal); var wasDirty = IsDirty; @@ -2412,7 +2237,7 @@ namespace GameCult.Caching Delete(entry); foreach (var entry in upserts) Push(entry); - PushAll(soft); + PushAll(); } catch { @@ -2426,9 +2251,9 @@ namespace GameCult.Caching /// /// Persists all current backing store entries. /// - public abstract void PushAll(bool soft = false); + public abstract void PushAll(); /// - /// Releases backing store event subjects. + /// Flushes staged mutations first when FlushOnDispose is set. /// public virtual void Dispose() { @@ -2436,10 +2261,6 @@ namespace GameCult.Caching { PushAll(); } - - EntryAdded.Dispose(); - EntryUpdated.Dispose(); - EntryDeleted.Dispose(); } /// @@ -2487,7 +2308,6 @@ namespace GameCult.Caching protected void MarkFlushSucceeded() { IsDirty = false; - LastSuccessfulFlushAtUtc = DateTimeOffset.UtcNow; } } @@ -2571,16 +2391,13 @@ namespace GameCult.Caching continue; } Entries[stored.Key.Value] = stored; - if (existing == null) - EntryAdded.OnNext(stored); - else - EntryUpdated.OnNext(stored); + Loaded?.Invoke(stored); } foreach (var removedKey in Entries.Keys.Where(key => !persistedKeys.Contains(key)).ToArray()) { if (Entries.TryRemove(removedKey, out var removed)) - EntryDeleted.OnNext(removed); + Unloaded?.Invoke(removed); } SetLastSchemaMigrationReports(reports); @@ -2608,7 +2425,7 @@ namespace GameCult.Caching /// /// Writes the staged snapshot to disk. /// - public override void PushAll(bool soft = false) + public override void PushAll() { var snapshot = new CultPersistedStoreSnapshot { diff --git a/src/GameCult.Mesh/CultMesh.cs b/src/GameCult.Mesh/CultMesh.cs index 6dd47f8c..08868ade 100644 --- a/src/GameCult.Mesh/CultMesh.cs +++ b/src/GameCult.Mesh/CultMesh.cs @@ -432,7 +432,7 @@ namespace GameCult.Mesh /// public Task FlushAsync(bool soft = false) { - return _host.FlushAsync(soft); + return _host.FlushAsync(); } /// diff --git a/src/GameCult.Networking/CultNetLocal.cs b/src/GameCult.Networking/CultNetLocal.cs index e884cd8d..87942ce8 100644 --- a/src/GameCult.Networking/CultNetLocal.cs +++ b/src/GameCult.Networking/CultNetLocal.cs @@ -100,7 +100,7 @@ namespace GameCult.Networking /// public Task FlushAsync(bool soft = false) { - return Cache.FlushAsync(soft); + return Cache.FlushAsync(); } /// diff --git a/tests/GameCult.Caching.Tests/BackingStoreTests.cs b/tests/GameCult.Caching.Tests/BackingStoreTests.cs index 6624b9f2..483007cb 100644 --- a/tests/GameCult.Caching.Tests/BackingStoreTests.cs +++ b/tests/GameCult.Caching.Tests/BackingStoreTests.cs @@ -178,14 +178,11 @@ namespace GameCult.Caching.Tests Assert.That(cache.IsDirty, Is.True); Assert.That(store.IsDirty, Is.True); - Assert.That(cache.LastSuccessfulFlushAtUtc, Is.Null); cache.FlushAllBackingStores(); Assert.That(cache.IsDirty, Is.False); Assert.That(store.IsDirty, Is.False); - Assert.That(cache.LastSuccessfulFlushAtUtc, Is.Not.Null); - Assert.That(store.LastSuccessfulFlushAtUtc, Is.Not.Null); } finally { @@ -213,8 +210,7 @@ namespace GameCult.Caching.Tests cache.Dispose(); var reopened = await CultCacheMessagePack.OpenAsync(filePath); - Assert.That(reopened.TryGet(handle.Key, out NamedTestEntry? loaded), Is.True); - Assert.That(loaded!.Value, Is.EqualTo("magic")); + Assert.That(reopened.Get(handle.Key)?.Value, Is.EqualTo("magic")); } finally { @@ -310,21 +306,11 @@ namespace GameCult.Caching.Tests using var reopened = await CultCacheMessagePack.OpenAsync( filePath, - new CultCacheOpenOptions - { - Registry = registry, - UseDirectoryStore = true, - DirectoryStoreHydrationFilter = _ => false - }); + new CultCacheOpenOptions { Registry = registry, UseDirectoryStore = true }); - Assert.That(reopened.GetGlobal(), Is.Null, - "the hydration filter owns whether the durable global becomes hot"); - Assert.That(reopened.IsDirty, Is.False, - "a cold durable global must not stage its schema default as a write"); - - var globalKey = "global:" + registry.GetRequired().SchemaId; - await reopened.PullBackingStoreRecordsAsync(metadata => metadata.Key == globalKey); Assert.That(reopened.GetGlobal()?.Value, Is.EqualTo("durable authority")); + Assert.That(reopened.IsDirty, Is.False, + "a hydrated durable global must not stage its schema default as a write"); } finally { @@ -444,63 +430,6 @@ namespace GameCult.Caching.Tests } } - [Test] - public async Task DirectoryMessagePackBackingStore_PullSelected_HydratesMatchingColdPagesOnly() - { - var filePath = Path.Combine(Path.GetTempPath(), $"cultlib-tests-{Guid.NewGuid():N}.cc"); - var recordsPath = DirectoryMessagePackBackingStore.DefaultRecordDirectoryPath(filePath); - - try - { - CultRecordHandle hot; - CultRecordHandle requested; - CultRecordHandle unrelated; - using (var seed = await CultCacheMessagePack.OpenAsync( - filePath, - new CultCacheOpenOptions { UseDirectoryStore = true })) - { - hot = await seed.UpsertAsync(new NamedTestEntry { Name = "hot", Value = "already-loaded" }); - requested = await seed.UpsertAsync(new NamedTestEntry { Name = "requested", Value = "load-later" }); - unrelated = await seed.UpsertAsync(new NamedTestEntry - { - Name = "unrelated", - Value = new string('u', 1024 * 1024) - }); - await seed.FlushAsync(); - } - - string PageFor(CultRecordHandle handle) => - Directory.GetFiles(recordsPath, "*.msgpack").Single(path => string.Equals( - CultDocumentMessagePackSerialization.DeserializePersistedRecord(File.ReadAllBytes(path)).Key, - handle.Key.Value, - StringComparison.Ordinal)); - - using var selected = await CultCacheMessagePack.OpenAsync( - filePath, - new CultCacheOpenOptions - { - UseDirectoryStore = true, - DirectoryStoreHydrationFilter = metadata => metadata.Key == hot.Key.Value - }); - Assert.That(selected.Get(requested.Key), Is.Null); - - using (new FileStream(PageFor(unrelated), FileMode.Open, FileAccess.Read, FileShare.None)) - { - await selected.PullBackingStoreRecordsAsync(metadata => metadata.Key == requested.Key.Value); - Assert.That(selected.Get(requested.Key)?.Value, Is.EqualTo("load-later")); - Assert.That(selected.Get(hot.Key)?.Value, Is.EqualTo("already-loaded")); - Assert.That(selected.Get(unrelated.Key), Is.Null); - } - } - finally - { - if (File.Exists(filePath)) - File.Delete(filePath); - if (Directory.Exists(recordsPath)) - Directory.Delete(recordsPath, recursive: true); - } - } - [Test] public async Task DirectoryMessagePackBackingStore_Loads_Record_When_Manifest_Misses_Catalog_Entry() { @@ -876,7 +805,7 @@ namespace GameCult.Caching.Tests var readerCache = new CultCache(); readerCache.AddBackingStore(readerStore); var observerRan = false; - using var subscription = readerStore.EntryAdded.Subscribe(_ => + using var subscription = readerCache.Watch().Subscribe(_ => { if (observerRan) return; @@ -1059,7 +988,7 @@ namespace GameCult.Caching.Tests } [Test] - public async Task CultCache_TypedStoredDocumentIndex_Tracks_Upsert_Replacement_And_Removal() + public async Task CultCache_GetAll_Tracks_Upsert_Replacement_And_Removal() { var cache = new CultCache(); var key = new CultRecordKey("typed-index:named"); @@ -1073,20 +1002,20 @@ namespace GameCult.Caching.Tests Name = "unrelated" }, new CultRecordKey("typed-index:unrelated")); - var initial = cache.GetStoredDocuments().Single(); - Assert.That(initial.Key, Is.EqualTo(key)); - Assert.That(((NamedTestEntry)initial.Document).Value, Is.EqualTo("first")); + var initial = cache.GetAll().Single(); + Assert.That(cache.TryGetHandle(initial)?.Key, Is.EqualTo(key)); + Assert.That(initial.Value, Is.EqualTo("first")); await cache.UpsertAsync(typeof(NamedTestEntry), new NamedTestEntry { Name = "indexed", Value = "second" }, key); - var replaced = cache.GetStoredDocuments().Single(); - Assert.That(((NamedTestEntry)replaced.Document).Value, Is.EqualTo("second")); + var replaced = cache.GetAll().Single(); + Assert.That(replaced.Value, Is.EqualTo("second")); Assert.That(cache.Remove(key), Is.True); - Assert.That(cache.GetStoredDocuments(), Is.Empty); + Assert.That(cache.GetAll(), Is.Empty); } [Test]