diff --git a/src/GameCult.Networking/CultNetDatabase.cs b/src/GameCult.Networking/CultNetDatabase.cs index 1cb1a1e0..bedf91c6 100644 --- a/src/GameCult.Networking/CultNetDatabase.cs +++ b/src/GameCult.Networking/CultNetDatabase.cs @@ -1180,10 +1180,22 @@ namespace GameCult.Networking } _disposed = true; + // The journal first: disposing it waits for a journal in flight, so nothing is stashed after this line. What a + // writer has logged and not yet published is then published here, so a change the log holds is never dropped. _cacheJournal.Dispose(); _cacheChanges.Dispose(); + Publication[] unpublished; lock (_logGate) + { + unpublished = _stash.OrderBy(entry => entry.Key).Select(entry => entry.Value).ToArray(); _stash.Clear(); + } + + foreach (var publication in unpublished) + { + Publish(publication); + } + _changes.Dispose(); } @@ -1288,6 +1300,10 @@ namespace GameCult.Networking } } + Publish(publication); + } + + private void Publish(Publication publication) => PublishUntyped( publication.DocumentType, publication.Kind, @@ -1296,7 +1312,6 @@ namespace GameCult.Networking publication.Shard, publication.Document, publication.PreviousDocument); - } private void RecordReplicatedEntry( CultNetShardDescriptor shard, diff --git a/tests/GameCult.Networking.Tests/CultNetJournalTests.cs b/tests/GameCult.Networking.Tests/CultNetJournalTests.cs index 7ba70dc8..d6f9d6d6 100644 --- a/tests/GameCult.Networking.Tests/CultNetJournalTests.cs +++ b/tests/GameCult.Networking.Tests/CultNetJournalTests.cs @@ -1022,8 +1022,8 @@ namespace GameCult.Networking.Tests Assert.That(logger.Errors, Is.Empty); } - // The journal is disposed before the observer: an admission the journal logs while the database is being disposed is - // still published, never logged and then dropped. + // A change the log holds is published, however Dispose interleaves with the write: Dispose waits for a journal in + // flight (disposing the journal first) and publishes whatever the writer had logged and not yet published. [Test] public async Task ADatabaseDisposedWhileAWriteIsInItsLogAppendStillPublishesWhatItLogged() {