From ad3a01dc06215e17458357189cac15b9c603d093 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 21 Jan 2022 22:40:18 +0900 Subject: [PATCH] Use a more reliable method of reviving the update thread realm after blocking --- osu.Game/Database/RealmContextFactory.cs | 44 +++++++++++-------- .../Sections/DebugSettings/MemorySettings.cs | 4 -- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/osu.Game/Database/RealmContextFactory.cs b/osu.Game/Database/RealmContextFactory.cs index d9c66ccc69..6fb9a2996b 100644 --- a/osu.Game/Database/RealmContextFactory.cs +++ b/osu.Game/Database/RealmContextFactory.cs @@ -69,30 +69,29 @@ namespace osu.Game.Database private Realm? context; - public Realm Context + public Realm Context => ensureUpdateContext(); + + private Realm ensureUpdateContext() { - get + if (!ThreadSafety.IsUpdateThread) + throw new InvalidOperationException(@$"Use {nameof(createContext)} when performing realm operations from a non-update thread"); + + lock (contextLock) { - if (!ThreadSafety.IsUpdateThread) - throw new InvalidOperationException(@$"Use {nameof(createContext)} when performing realm operations from a non-update thread"); - - lock (contextLock) + if (context == null) { - if (context == null) - { - context = createContext(); - Logger.Log(@$"Opened realm ""{context.Config.DatabasePath}"" at version {context.Config.SchemaVersion}"); + context = createContext(); + Logger.Log(@$"Opened realm ""{context.Config.DatabasePath}"" at version {context.Config.SchemaVersion}"); - // Resubscribe any subscriptions - foreach (var action in subscriptionActions.Keys) - registerSubscription(action); - } - - Debug.Assert(context != null); - - // creating a context will ensure our schema is up-to-date and migrated. - return context; + // Resubscribe any subscriptions + foreach (var action in subscriptionActions.Keys) + registerSubscription(action); } + + Debug.Assert(context != null); + + // creating a context will ensure our schema is up-to-date and migrated. + return context; } } @@ -506,6 +505,8 @@ namespace osu.Game.Database if (isDisposed) throw new ObjectDisposedException(nameof(RealmContextFactory)); + SynchronizationContext syncContext; + try { contextCreationLock.Wait(); @@ -515,6 +516,8 @@ namespace osu.Game.Database if (!ThreadSafety.IsUpdateThread && context != null) throw new InvalidOperationException(@$"{nameof(BlockAllOperations)} must be called from the update thread."); + syncContext = SynchronizationContext.Current; + Logger.Log(@"Blocking realm operations.", LoggingTarget.Database); context?.Dispose(); @@ -553,6 +556,9 @@ namespace osu.Game.Database { factory.contextCreationLock.Release(); Logger.Log(@"Restoring realm operations.", LoggingTarget.Database); + + // Post back to the update thread to revive any subscriptions. + syncContext?.Post(_ => ensureUpdateContext(), null); }); } diff --git a/osu.Game/Overlays/Settings/Sections/DebugSettings/MemorySettings.cs b/osu.Game/Overlays/Settings/Sections/DebugSettings/MemorySettings.cs index 84a54b208c..8d4fc5fc9f 100644 --- a/osu.Game/Overlays/Settings/Sections/DebugSettings/MemorySettings.cs +++ b/osu.Game/Overlays/Settings/Sections/DebugSettings/MemorySettings.cs @@ -33,10 +33,6 @@ namespace osu.Game.Overlays.Settings.Sections.DebugSettings using (realmFactory.BlockAllOperations()) { } - - // retrieve context to revive realm subscriptions. - // TODO: should we do this from OsuGame or RealmContextFactory or something? Answer: yes. - var _ = realmFactory.Context; } }, };