1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 05:32:54 +08:00

Add helper method for safer realm Find<T>

This commit is contained in:
Dean Herbert 2023-08-16 15:36:31 +09:00
parent 88295a49aa
commit 6e11162ab1
3 changed files with 37 additions and 41 deletions

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using osu.Framework.Platform;
@ -47,13 +48,16 @@ namespace osu.Game.Database
// This method should be removed as soon as all the surrounding pieces support non-detached operations.
if (!item.IsManaged)
{
// We use RealmLive here as it handled re-retrieval and refreshing of realm if required.
new RealmLive<TModel>(item.ID, Realm).PerformWrite(i =>
// Importantly, begin the realm write *before* re-fetching, else the update realm may not be in a consistent state
// (ie. if an async import finished very recently).
Realm.Realm.Write(realm =>
{
operation(i);
var managed = realm.FindWithRefresh<TModel>(item.ID);
Debug.Assert(managed != null);
operation(managed);
item.Files.Clear();
item.Files.AddRange(i.Files.Detach());
item.Files.AddRange(managed.Files.Detach());
});
}
else

View File

@ -8,6 +8,31 @@ namespace osu.Game.Database
{
public static class RealmExtensions
{
/// <summary>
/// Performs a <see cref="Realm.Find{T}(System.Nullable{long})"/>.
/// If a match was not found, a <see cref="Realm.Refresh"/> is performed before trying a second time.
/// This ensures that an instance is found even if the realm requested against was not in a consistent state.
/// </summary>
/// <param name="realm"></param>
/// <param name="id"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T? FindWithRefresh<T>(this Realm realm, Guid id) where T : IRealmObject
{
var found = realm.Find<T>(id);
if (found == null)
{
// It may be that we access this from the update thread before a refresh has taken place.
// To ensure that behaviour matches what we'd expect (the object *is* available), force
// a refresh to bring in any off-thread changes immediately.
realm.Refresh();
found = realm.Find<T>(id);
}
return found;
}
/// <summary>
/// Perform a write operation against the provided realm instance.
/// </summary>

View File

@ -41,24 +41,6 @@ namespace osu.Game.Database
dataIsFromUpdateThread = ThreadSafety.IsUpdateThread;
}
/// <summary>
/// Construct a new instance of live realm data from an ID.
/// </summary>
/// <param name="id">The ID of an already-persisting realm instance.</param>
/// <param name="realm">The realm factory the data was sourced from. May be null for an unmanaged object.</param>
public RealmLive(Guid id, RealmAccess realm)
: base(id)
{
data = retrieveFromID(realm.Realm);
if (data.IsNull())
throw new ArgumentException("Realm instance for provided ID could not be found.", nameof(id));
this.realm = realm;
dataIsFromUpdateThread = ThreadSafety.IsUpdateThread;
}
/// <summary>
/// Perform a read operation on this live object.
/// </summary>
@ -80,7 +62,7 @@ namespace osu.Game.Database
return;
}
perform(retrieveFromID(r));
perform(r.FindWithRefresh<T>(ID)!);
RealmLiveStatistics.USAGE_ASYNC.Value++;
});
}
@ -102,7 +84,7 @@ namespace osu.Game.Database
return realm.Run(r =>
{
var returnData = perform(retrieveFromID(r));
var returnData = perform(r.FindWithRefresh<T>(ID)!);
RealmLiveStatistics.USAGE_ASYNC.Value++;
if (returnData is RealmObjectBase realmObject && realmObject.IsManaged)
@ -159,25 +141,10 @@ namespace osu.Game.Database
}
dataIsFromUpdateThread = true;
data = retrieveFromID(realm.Realm);
data = realm.Realm.FindWithRefresh<T>(ID)!;
RealmLiveStatistics.USAGE_UPDATE_REFETCH.Value++;
}
private T retrieveFromID(Realm realm)
{
var found = realm.Find<T>(ID);
if (found == null)
{
// It may be that we access this from the update thread before a refresh has taken place.
// To ensure that behaviour matches what we'd expect (the object *is* available), force
// a refresh to bring in any off-thread changes immediately.
realm.Refresh();
found = realm.Find<T>(ID)!;
}
return found;
}
}
internal static class RealmLiveStatistics