1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-27 11:12:59 +08:00

Merge branch 'master' into mod-overlay/rename-new

This commit is contained in:
Dean Herbert 2022-05-11 10:15:59 +09:00 committed by GitHub
commit 53259251af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 68 additions and 8 deletions

View File

@ -136,6 +136,37 @@ namespace osu.Game.Tests.Database
}); });
} }
[Test]
public void TestAddFileToAsyncImportedBeatmap()
{
RunTestWithRealm((realm, storage) =>
{
BeatmapSetInfo? detachedSet = null;
using (var importer = new BeatmapModelManager(realm, storage))
using (new RealmRulesetStore(realm, storage))
{
Task.Run(async () =>
{
Live<BeatmapSetInfo>? beatmapSet;
using (var reader = new ZipArchiveReader(TestResources.GetTestBeatmapStream()))
// ReSharper disable once AccessToDisposedClosure
beatmapSet = await importer.Import(reader);
Assert.NotNull(beatmapSet);
Debug.Assert(beatmapSet != null);
// Intentionally detach on async thread as to not trigger a refresh on the main thread.
beatmapSet.PerformRead(s => detachedSet = s.Detach());
}).WaitSafely();
Debug.Assert(detachedSet != null);
importer.AddFile(detachedSet, new MemoryStream(), "test");
}
});
}
[Test] [Test]
public void TestImportBeatmapThenCleanup() public void TestImportBeatmapThenCleanup()
{ {

View File

@ -344,6 +344,26 @@ namespace osu.Game.Database
} }
} }
/// <summary>
/// Write changes to realm.
/// </summary>
/// <param name="action">The work to run.</param>
public T Write<T>(Func<Realm, T> action)
{
if (ThreadSafety.IsUpdateThread)
{
total_writes_update.Value++;
return Realm.Write(action);
}
else
{
total_writes_async.Value++;
using (var realm = getRealmInstance())
return realm.Write(action);
}
}
/// <summary> /// <summary>
/// Write changes to realm. /// Write changes to realm.
/// </summary> /// </summary>

View File

@ -45,11 +45,16 @@ namespace osu.Game.Stores
// This method should be removed as soon as all the surrounding pieces support non-detached operations. // This method should be removed as soon as all the surrounding pieces support non-detached operations.
if (!item.IsManaged) if (!item.IsManaged)
{ {
var managed = Realm.Realm.Find<TModel>(item.ID); // Importantly, begin the realm write *before* re-fetching, else the update realm may not be in a consistent state
managed.Realm.Write(() => operation(managed)); // (ie. if an async import finished very recently).
Realm.Realm.Write(realm =>
{
var managed = realm.Find<TModel>(item.ID);
operation(managed);
item.Files.Clear(); item.Files.Clear();
item.Files.AddRange(managed.Files.Detach()); item.Files.AddRange(managed.Files.Detach());
});
} }
else else
operation(item); operation(item);
@ -165,7 +170,9 @@ namespace osu.Game.Stores
public bool Delete(TModel item) public bool Delete(TModel item)
{ {
return Realm.Run(realm => // 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).
return Realm.Write(realm =>
{ {
if (!item.IsManaged) if (!item.IsManaged)
item = realm.Find<TModel>(item.ID); item = realm.Find<TModel>(item.ID);
@ -173,14 +180,16 @@ namespace osu.Game.Stores
if (item?.DeletePending != false) if (item?.DeletePending != false)
return false; return false;
realm.Write(r => item.DeletePending = true); item.DeletePending = true;
return true; return true;
}); });
} }
public void Undelete(TModel item) public void Undelete(TModel item)
{ {
Realm.Run(realm => // 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.Write(realm =>
{ {
if (!item.IsManaged) if (!item.IsManaged)
item = realm.Find<TModel>(item.ID); item = realm.Find<TModel>(item.ID);
@ -188,7 +197,7 @@ namespace osu.Game.Stores
if (item?.DeletePending != true) if (item?.DeletePending != true)
return; return;
realm.Write(r => item.DeletePending = false); item.DeletePending = false;
}); });
} }