Merge pull request #15812 from peppy/realm-live-unmanaged-fetch-fix

Avoid attempting to fetch a non-managed `RealmLive` instance from the realm backing
This commit is contained in:
Dan Balasescu 2021-11-26 15:37:58 +09:00 committed by GitHub
commit 5e53f51c99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 41 additions and 4 deletions

View File

@ -29,6 +29,23 @@ namespace osu.Game.Tests.Database
}); });
} }
[Test]
public void TestAccessNonManaged()
{
var beatmap = new RealmBeatmap(CreateRuleset(), new RealmBeatmapDifficulty(), new RealmBeatmapMetadata());
var liveBeatmap = beatmap.ToLive();
Assert.IsFalse(beatmap.Hidden);
Assert.IsFalse(liveBeatmap.Value.Hidden);
Assert.IsFalse(liveBeatmap.PerformRead(l => l.Hidden));
Assert.Throws<InvalidOperationException>(() => liveBeatmap.PerformWrite(l => l.Hidden = true));
Assert.IsFalse(beatmap.Hidden);
Assert.IsFalse(liveBeatmap.Value.Hidden);
Assert.IsFalse(liveBeatmap.PerformRead(l => l.Hidden));
}
[Test] [Test]
public void TestValueAccessWithOpenContext() public void TestValueAccessWithOpenContext()
{ {

View File

@ -11,6 +11,7 @@ namespace osu.Game.Database
{ {
public EntityFrameworkLive(T item) public EntityFrameworkLive(T item)
{ {
IsManaged = true; // no way to really know.
Value = item; Value = item;
} }
@ -31,6 +32,8 @@ namespace osu.Game.Database
perform(Value); perform(Value);
} }
public bool IsManaged { get; }
public T Value { get; } public T Value { get; }
public bool Equals(ILive<T>? other) => ID == other?.ID; public bool Equals(ILive<T>? other) => ID == other?.ID;

View File

@ -32,6 +32,11 @@ namespace osu.Game.Database
/// <param name="perform">The action to perform.</param> /// <param name="perform">The action to perform.</param>
void PerformWrite(Action<T> perform); void PerformWrite(Action<T> perform);
/// <summary>
/// Whether this instance is tracking data which is managed by the database backing.
/// </summary>
bool IsManaged { get; }
/// <summary> /// <summary>
/// Resolve the value of this instance on the current thread's context. /// Resolve the value of this instance on the current thread's context.
/// </summary> /// </summary>

View File

@ -17,6 +17,8 @@ namespace osu.Game.Database
{ {
public Guid ID { get; } public Guid ID { get; }
public bool IsManaged { get; }
private readonly SynchronizationContext? fetchedContext; private readonly SynchronizationContext? fetchedContext;
private readonly int fetchedThreadId; private readonly int fetchedThreadId;
@ -33,8 +35,13 @@ namespace osu.Game.Database
{ {
this.data = data; this.data = data;
fetchedContext = SynchronizationContext.Current; if (data.IsManaged)
fetchedThreadId = Thread.CurrentThread.ManagedThreadId; {
IsManaged = true;
fetchedContext = SynchronizationContext.Current;
fetchedThreadId = Thread.CurrentThread.ManagedThreadId;
}
ID = data.ID; ID = data.ID;
} }
@ -75,13 +82,18 @@ namespace osu.Game.Database
/// Perform a write operation on this live object. /// Perform a write operation on this live object.
/// </summary> /// </summary>
/// <param name="perform">The action to perform.</param> /// <param name="perform">The action to perform.</param>
public void PerformWrite(Action<T> perform) => public void PerformWrite(Action<T> perform)
{
if (!IsManaged)
throw new InvalidOperationException("Can't perform writes on a non-managed underlying value");
PerformRead(t => PerformRead(t =>
{ {
var transaction = t.Realm.BeginWrite(); var transaction = t.Realm.BeginWrite();
perform(t); perform(t);
transaction.Commit(); transaction.Commit();
}); });
}
public T Value public T Value
{ {
@ -102,7 +114,7 @@ namespace osu.Game.Database
} }
} }
private bool originalDataValid => isCorrectThread && data.IsValid; private bool originalDataValid => !IsManaged || (isCorrectThread && data.IsValid);
// this matches realm's internal thread validation (see https://github.com/realm/realm-dotnet/blob/903b4d0b304f887e37e2d905384fb572a6496e70/Realm/Realm/Native/SynchronizationContextScheduler.cs#L72) // this matches realm's internal thread validation (see https://github.com/realm/realm-dotnet/blob/903b4d0b304f887e37e2d905384fb572a6496e70/Realm/Realm/Native/SynchronizationContextScheduler.cs#L72)
private bool isCorrectThread private bool isCorrectThread