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:
parent
88295a49aa
commit
6e11162ab1
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user