diff --git a/osu.Game.Tests/Database/RealmSubscriptionRegistrationTests.cs b/osu.Game.Tests/Database/RealmSubscriptionRegistrationTests.cs index d62ce3b585..02d617d0e0 100644 --- a/osu.Game.Tests/Database/RealmSubscriptionRegistrationTests.cs +++ b/osu.Game.Tests/Database/RealmSubscriptionRegistrationTests.cs @@ -4,8 +4,10 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Extensions; using osu.Game.Beatmaps; using osu.Game.Rulesets; using osu.Game.Tests.Resources; @@ -18,6 +20,33 @@ namespace osu.Game.Tests.Database [TestFixture] public class RealmSubscriptionRegistrationTests : RealmTest { + [Test] + public void TestSubscriptionWithAsyncWrite() + { + ChangeSet? lastChanges = null; + + RunTestWithRealm((realm, _) => + { + var registration = realm.RegisterForNotifications(r => r.All(), onChanged); + + realm.Run(r => r.Refresh()); + + // Without forcing the write onto its own thread, realm will internally run the operation synchronously, which can cause a deadlock with `WaitSafely`. + Task.Run(async () => + { + await realm.WriteAsync(r => r.Add(TestResources.CreateTestBeatmapSetInfo())); + }).WaitSafely(); + + realm.Run(r => r.Refresh()); + + Assert.That(lastChanges?.InsertedIndices, Has.One.Items); + + registration.Dispose(); + }); + + void onChanged(IRealmCollection sender, ChangeSet? changes, Exception error) => lastChanges = changes; + } + [Test] public void TestSubscriptionWithContextLoss() { diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index f63e858b6f..bf2b48ea52 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Reflection; using System.Threading; +using System.Threading.Tasks; using osu.Framework.Allocation; using osu.Framework.Development; using osu.Framework.Input.Bindings; @@ -270,6 +271,17 @@ public void Write(Action action) } } + /// + /// Write changes to realm asynchronously, guaranteeing order of execution. + /// + /// The work to run. + public async Task WriteAsync(Action action) + { + total_writes_async.Value++; + using (var realm = getRealmInstance()) + await realm.WriteAsync(action); + } + /// /// Subscribe to a realm collection and begin watching for asynchronous changes. ///