fix(threading): protect AutoTranslate cache and bound framework waits
- Util/AutoTranslate.cs introduces a single EntriesLock object and serializes every read and write of the static Entries dictionary and ValidEntries hash set behind it. PreloadCache spawns a worker thread that fills both while the main thread reads them via the Matching / ReplaceWithPayload / StartsWithCommand entry points; without the lock the underlying collection access was undefined. AllEntries() splits into a thin lock wrapper plus a private BuildEntriesLocked() helper that runs under the lock - Ui/SettingsTabs/Privacy.cs bounds the .Wait() on the framework refresh after a manual retention sweep and after the privacy cleanup. A hung framework tick previously could deadlock the background worker thread. Five-second timeout, log on miss
This commit is contained in:
@@ -455,11 +455,18 @@ internal sealed class Privacy : ISettingsTab
|
||||
|
||||
if (deleted > 0)
|
||||
{
|
||||
Plugin.Framework.Run(() =>
|
||||
// Bound the wait so a hung framework tick can't deadlock
|
||||
// the background retention worker. Five seconds is well
|
||||
// beyond a normal frame; if we time out we log and let
|
||||
// the next FilterAllTabsAsync call recover the state.
|
||||
if (!Plugin.Framework.Run(() =>
|
||||
{
|
||||
Plugin.MessageManager.ClearAllTabs();
|
||||
Plugin.MessageManager.FilterAllTabsAsync();
|
||||
}).Wait(TimeSpan.FromSeconds(5)))
|
||||
{
|
||||
Plugin.MessageManager.ClearAllTabs();
|
||||
Plugin.MessageManager.FilterAllTabsAsync();
|
||||
}).Wait();
|
||||
Plugin.Log.Warning("Retention sweep: framework refresh timed out after 5s.");
|
||||
}
|
||||
}
|
||||
|
||||
WrapperUtil.AddNotification(string.Format(HellionStrings.Retention_Success, deleted), NotificationType.Success);
|
||||
@@ -615,11 +622,17 @@ internal sealed class Privacy : ISettingsTab
|
||||
var deleted = Plugin.MessageManager.Store.CleanupRetainOnly(allowed);
|
||||
Plugin.Log.Information($"Privacy cleanup: deleted {deleted} messages");
|
||||
|
||||
Plugin.Framework.Run(() =>
|
||||
// Bound the wait so a hung framework tick can't deadlock
|
||||
// the background cleanup worker. See the matching comment in
|
||||
// the retention path above for rationale.
|
||||
if (!Plugin.Framework.Run(() =>
|
||||
{
|
||||
Plugin.MessageManager.ClearAllTabs();
|
||||
Plugin.MessageManager.FilterAllTabsAsync();
|
||||
}).Wait(TimeSpan.FromSeconds(5)))
|
||||
{
|
||||
Plugin.MessageManager.ClearAllTabs();
|
||||
Plugin.MessageManager.FilterAllTabsAsync();
|
||||
}).Wait();
|
||||
Plugin.Log.Warning("Privacy cleanup: framework refresh timed out after 5s.");
|
||||
}
|
||||
|
||||
WrapperUtil.AddNotification(string.Format(HellionStrings.Cleanup_Success, deleted), NotificationType.Success);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user