perf(messagemanager): switch pending queue to linked list, quiet privacy log
PendingSync läuft jetzt als LinkedList (O(1) Last statt O(n) Linq-Last im ContentIdResolverHook); Privacy-Filter-Drop-Log auf Verbose runter, sodass der Default-xllog-Stream nicht mehr pro Nachricht spammt.
This commit is contained in:
@@ -34,7 +34,10 @@ internal class MessageManager : IAsyncDisposable
|
|||||||
// After that, the message is enqueued in the PendingAsync queue, which will
|
// After that, the message is enqueued in the PendingAsync queue, which will
|
||||||
// be consumed in a separate thread and perform more processing (emotes,
|
// be consumed in a separate thread and perform more processing (emotes,
|
||||||
// URLs) as well as inserting the message into the database.
|
// URLs) as well as inserting the message into the database.
|
||||||
private Queue<PendingMessage> PendingSync { get; } = [];
|
// LinkedList instead of Queue: ContentIdResolver hits PendingSync.Last
|
||||||
|
// every hook call. Queue<T>.Last() is the LINQ extension and walks the
|
||||||
|
// whole queue (O(n)); LinkedList<T>.Last is an O(1) node reference.
|
||||||
|
private LinkedList<PendingMessage> PendingSync { get; } = [];
|
||||||
private ConcurrentQueue<PendingMessage> PendingAsync { get; } = [];
|
private ConcurrentQueue<PendingMessage> PendingAsync { get; } = [];
|
||||||
private readonly Thread PendingMessageThread;
|
private readonly Thread PendingMessageThread;
|
||||||
private readonly CancellationTokenSource PendingThreadCancellationToken = new();
|
private readonly CancellationTokenSource PendingThreadCancellationToken = new();
|
||||||
@@ -117,8 +120,11 @@ internal class MessageManager : IAsyncDisposable
|
|||||||
LastContentId = contentId;
|
LastContentId = contentId;
|
||||||
|
|
||||||
// Drain the PendingSync queue into the PendingAsync queue.
|
// Drain the PendingSync queue into the PendingAsync queue.
|
||||||
while (PendingSync.TryDequeue(out var pending))
|
while (PendingSync.First is { } first)
|
||||||
PendingAsync.Enqueue(pending);
|
{
|
||||||
|
PendingSync.RemoveFirst();
|
||||||
|
PendingAsync.Enqueue(first.Value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessPendingMessages(CancellationToken token)
|
private void ProcessPendingMessages(CancellationToken token)
|
||||||
@@ -223,7 +229,7 @@ internal class MessageManager : IAsyncDisposable
|
|||||||
// We delay messages to be handed off to the async processing thread
|
// We delay messages to be handed off to the async processing thread
|
||||||
// in the next tick, otherwise we can't get the content ID from the hook
|
// in the next tick, otherwise we can't get the content ID from the hook
|
||||||
// below.
|
// below.
|
||||||
PendingSync.Enqueue(pendingMessage);
|
PendingSync.AddLast(pendingMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This hook is called immediately after receiving a message with the
|
// This hook is called immediately after receiving a message with the
|
||||||
@@ -235,11 +241,11 @@ internal class MessageManager : IAsyncDisposable
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
ContentIdResolverHook?.Original(agent, contentId, accountId, messageIndex, worldId, chatType);
|
ContentIdResolverHook?.Original(agent, contentId, accountId, messageIndex, worldId, chatType);
|
||||||
if (PendingSync.Count == 0)
|
if (PendingSync.Last is not { } last)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
PendingSync.Last().ContentId = contentId;
|
last.Value.ContentId = contentId;
|
||||||
PendingSync.Last().AccountId = accountId;
|
last.Value.AccountId = accountId;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -452,7 +452,10 @@ internal class MessageStore : IDisposable
|
|||||||
// covers any future write paths e.g. webinterface backfill).
|
// covers any future write paths e.g. webinterface backfill).
|
||||||
if (!Plugin.Config.IsAllowedForStorage(message.Code.Type))
|
if (!Plugin.Config.IsAllowedForStorage(message.Code.Type))
|
||||||
{
|
{
|
||||||
Plugin.Log.Debug($"Privacy filter dropped message: ChatType={message.Code.Type}");
|
// Verbose-only: this fires for every dropped message, which is
|
||||||
|
// the common case for users with a tight privacy whitelist. Keep
|
||||||
|
// it for diagnostics but stay out of the default xllog stream.
|
||||||
|
Plugin.Log.Verbose($"Privacy filter dropped message: ChatType={message.Code.Type}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user