1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-14 19:03:22 +08:00

Merge pull request #17023 from peppy/realm-async-write

Add `RealmAccess.WriteAsync` method and more statistics of realm reads/writes
This commit is contained in:
Dean Herbert 2022-03-02 12:31:16 +09:00 committed by GitHub
commit 09a74cdfc6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 65 additions and 3 deletions

View File

@ -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<BeatmapSetInfo>(), 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<BeatmapSetInfo> sender, ChangeSet? changes, Exception error) => lastChanges = changes;
}
[Test]
public void TestSubscriptionWithContextLoss()
{

View File

@ -8,20 +8,21 @@ using System.IO;
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;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Framework.Statistics;
using osu.Game.Configuration;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Input.Bindings;
using osu.Game.Models;
using osu.Game.Skinning;
using osu.Game.Stores;
using osu.Game.Rulesets;
using osu.Game.Scoring;
using osu.Game.Skinning;
using osu.Game.Stores;
using Realms;
using Realms.Exceptions;
@ -85,6 +86,14 @@ namespace osu.Game.Database
private static readonly GlobalStatistic<int> total_subscriptions = GlobalStatistics.Get<int>(@"Realm", @"Subscriptions");
private static readonly GlobalStatistic<int> total_reads_update = GlobalStatistics.Get<int>(@"Realm", @"Reads (Update)");
private static readonly GlobalStatistic<int> total_reads_async = GlobalStatistics.Get<int>(@"Realm", @"Reads (Async)");
private static readonly GlobalStatistic<int> total_writes_update = GlobalStatistics.Get<int>(@"Realm", @"Writes (Update)");
private static readonly GlobalStatistic<int> total_writes_async = GlobalStatistics.Get<int>(@"Realm", @"Writes (Async)");
private readonly object realmLock = new object();
private Realm? updateRealm;
@ -213,8 +222,12 @@ namespace osu.Game.Database
public T Run<T>(Func<Realm, T> action)
{
if (ThreadSafety.IsUpdateThread)
{
total_reads_update.Value++;
return action(Realm);
}
total_reads_async.Value++;
using (var realm = getRealmInstance())
return action(realm);
}
@ -226,9 +239,13 @@ namespace osu.Game.Database
public void Run(Action<Realm> action)
{
if (ThreadSafety.IsUpdateThread)
{
total_reads_update.Value++;
action(Realm);
}
else
{
total_reads_async.Value++;
using (var realm = getRealmInstance())
action(realm);
}
@ -241,14 +258,30 @@ namespace osu.Game.Database
public void Write(Action<Realm> action)
{
if (ThreadSafety.IsUpdateThread)
{
total_writes_update.Value++;
Realm.Write(action);
}
else
{
total_writes_async.Value++;
using (var realm = getRealmInstance())
realm.Write(action);
}
}
/// <summary>
/// Write changes to realm asynchronously, guaranteeing order of execution.
/// </summary>
/// <param name="action">The work to run.</param>
public async Task WriteAsync(Action<Realm> action)
{
total_writes_async.Value++;
using (var realm = getRealmInstance())
await realm.WriteAsync(action);
}
/// <summary>
/// Subscribe to a realm collection and begin watching for asynchronous changes.
/// </summary>