diff --git a/Directory.Packages.props b/Directory.Packages.props index d8cf98790e..c3fc950111 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -13,7 +13,7 @@ - + all diff --git a/src/Marten/Events/QuickEventAppender.cs b/src/Marten/Events/QuickEventAppender.cs index 1ae83d5c05..baabef6d3c 100644 --- a/src/Marten/Events/QuickEventAppender.cs +++ b/src/Marten/Events/QuickEventAppender.cs @@ -31,12 +31,15 @@ private static void registerOperationsForStreams(EventGraph eventGraph, Document } } + // The quick-append path never reads from this queue (PrepareEvents calls + // applyQuickMetadata, not applyRichMetadata, and only the rich variant + // dequeues from it). Hoist a single throwaway instance out of the + // per-stream loop so we don't allocate one per stream on every save. + var sequences = new Queue(); + foreach (var stream in session.WorkTracker.Streams.Where(x => x.Events.Any())) { stream.TenantId ??= session.TenantId; - - // Not really using it, just need a stand in - var sequences = new Queue(); if (stream.ActionType == StreamActionType.Start) { stream.PrepareEvents(0, eventGraph, sequences, session); diff --git a/src/Marten/Internal/Sessions/DocumentSessionBase.SaveChanges.cs b/src/Marten/Internal/Sessions/DocumentSessionBase.SaveChanges.cs index 37637aff0a..32a0299cb3 100644 --- a/src/Marten/Internal/Sessions/DocumentSessionBase.SaveChanges.cs +++ b/src/Marten/Internal/Sessions/DocumentSessionBase.SaveChanges.cs @@ -96,7 +96,20 @@ async ValueTask IStorageOperations.GetOrStartMessageSink() private IEnumerable operationDocumentTypes() { - return _workTracker.Operations().Select(x => x.DocumentType).Where(x => x != null).Distinct(); + // Single-pass HashSet so we don't enumerate Operations() twice (once for + // Select, once for the Distinct hash) and don't allocate intermediate + // LINQ enumerator chains on every SaveChanges. + var types = new HashSet(); + foreach (var op in _workTracker.Operations()) + { + var documentType = op.DocumentType; + if (documentType != null) + { + types.Add(documentType); + } + } + + return types; } internal record PagesExecution(IReadOnlyList Pages, IConnectionLifetime Connection,