1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 18:27:26 +08:00

Merge branch 'realm-stable-subscriptions' into music-controller-less-population

This commit is contained in:
Dean Herbert 2022-01-22 14:37:39 +09:00
commit 287d70d728
5 changed files with 50 additions and 36 deletions

View File

@ -29,8 +29,10 @@ namespace osu.Game.Benchmarks
realmFactory = new RealmContextFactory(storage, "client");
using (var context = realmFactory.CreateContext())
context.Write(c => c.Add(TestResources.CreateTestBeatmapSetInfo(rulesets: new[] { new OsuRuleset().RulesetInfo })));
realmFactory.Run(realm =>
{
realm.Write(c => c.Add(TestResources.CreateTestBeatmapSetInfo(rulesets: new[] { new OsuRuleset().RulesetInfo })));
});
updateThread = new UpdateThread(() => { }, null);
updateThread.Start();
@ -39,15 +41,15 @@ namespace osu.Game.Benchmarks
[Benchmark]
public void BenchmarkDirectPropertyRead()
{
using (var context = realmFactory.CreateContext())
realmFactory.Run(realm =>
{
var beatmapSet = context.All<BeatmapSetInfo>().First();
var beatmapSet = realm.All<BeatmapSetInfo>().First();
for (int i = 0; i < ReadsPerFetch; i++)
{
string _ = beatmapSet.Beatmaps.First().Hash;
}
}
});
}
[Benchmark]
@ -78,15 +80,15 @@ namespace osu.Game.Benchmarks
[Benchmark]
public void BenchmarkRealmLivePropertyRead()
{
using (var context = realmFactory.CreateContext())
realmFactory.Run(realm =>
{
var beatmapSet = context.All<BeatmapSetInfo>().First().ToLive(realmFactory);
var beatmapSet = realm.All<BeatmapSetInfo>().First().ToLive(realmFactory);
for (int i = 0; i < ReadsPerFetch; i++)
{
string _ = beatmapSet.PerformRead(b => b.Beatmaps.First().Hash);
}
}
});
}
[Benchmark]
@ -117,15 +119,15 @@ namespace osu.Game.Benchmarks
[Benchmark]
public void BenchmarkDetachedPropertyRead()
{
using (var context = realmFactory.CreateContext())
realmFactory.Run(realm =>
{
var beatmapSet = context.All<BeatmapSetInfo>().First().Detach();
var beatmapSet = realm.All<BeatmapSetInfo>().First().Detach();
for (int i = 0; i < ReadsPerFetch; i++)
{
string _ = beatmapSet.Beatmaps.First().Hash;
}
}
});
}
[GlobalCleanup]

View File

@ -47,6 +47,11 @@ namespace osu.Game.Tests.Database
liveBeatmap = beatmap.ToLive(realmFactory);
});
using (realmFactory.BlockAllOperations())
{
// recycle realm before migrating
}
using (var migratedStorage = new TemporaryNativeStorage("realm-test-migration-target"))
{
migratedStorage.DeleteDirectory(string.Empty);

View File

@ -69,28 +69,29 @@ namespace osu.Game.Database
private Realm? context;
public Realm Context
public Realm Context => ensureUpdateContext();
private Realm ensureUpdateContext()
{
get
if (!ThreadSafety.IsUpdateThread)
throw new InvalidOperationException(@$"Use {nameof(createContext)} when performing realm operations from a non-update thread");
lock (contextLock)
{
if (!ThreadSafety.IsUpdateThread)
throw new InvalidOperationException(@$"Use {nameof(createContext)} when performing realm operations from a non-update thread");
lock (contextLock)
if (context == null)
{
if (context == null)
{
context = createContext();
Logger.Log(@$"Opened realm ""{context.Config.DatabasePath}"" at version {context.Config.SchemaVersion}");
context = createContext();
Logger.Log(@$"Opened realm ""{context.Config.DatabasePath}"" at version {context.Config.SchemaVersion}");
// Resubscribe any subscriptions
foreach (var action in subscriptionActions.Keys)
registerSubscription(action);
}
// creating a context will ensure our schema is up-to-date and migrated.
return context;
// Resubscribe any subscriptions
foreach (var action in subscriptionActions.Keys)
registerSubscription(action);
}
Debug.Assert(context != null);
// creating a context will ensure our schema is up-to-date and migrated.
return context;
}
}
@ -261,10 +262,13 @@ namespace osu.Game.Database
{
Debug.Assert(ThreadSafety.IsUpdateThread);
// Get context outside of flag update to ensure beyond doubt this can't be cyclic.
var realm = Context;
lock (contextLock)
{
current_thread_subscriptions_allowed.Value = true;
subscriptionActions[action] = action(Context);
subscriptionActions[action] = action(realm);
current_thread_subscriptions_allowed.Value = false;
}
}
@ -501,6 +505,8 @@ namespace osu.Game.Database
if (isDisposed)
throw new ObjectDisposedException(nameof(RealmContextFactory));
SynchronizationContext syncContext;
try
{
contextCreationLock.Wait();
@ -510,6 +516,8 @@ namespace osu.Game.Database
if (!ThreadSafety.IsUpdateThread && context != null)
throw new InvalidOperationException(@$"{nameof(BlockAllOperations)} must be called from the update thread.");
syncContext = SynchronizationContext.Current;
Logger.Log(@"Blocking realm operations.", LoggingTarget.Database);
context?.Dispose();
@ -548,6 +556,9 @@ namespace osu.Game.Database
{
factory.contextCreationLock.Release();
Logger.Log(@"Restoring realm operations.", LoggingTarget.Database);
// Post back to the update thread to revive any subscriptions.
syncContext?.Post(_ => ensureUpdateContext(), null);
});
}

View File

@ -33,10 +33,6 @@ namespace osu.Game.Overlays.Settings.Sections.DebugSettings
using (realmFactory.BlockAllOperations())
{
}
// retrieve context to revive realm subscriptions.
// TODO: should we do this from OsuGame or RealmContextFactory or something? Answer: yes.
var _ = realmFactory.Context;
}
},
};

View File

@ -34,9 +34,9 @@ namespace osu.Game.Overlays.Settings.Sections.Input
{
string rulesetName = Ruleset?.ShortName;
List<RealmKeyBinding> bindings = null;
realmFactory.Run(realm => bindings = realm.All<RealmKeyBinding>().Where(b => b.RulesetName == rulesetName && b.Variant == variant).Detach());
var bindings = realmFactory.Run(realm => realm.All<RealmKeyBinding>()
.Where(b => b.RulesetName == rulesetName && b.Variant == variant)
.Detach());
foreach (var defaultGroup in Defaults.GroupBy(d => d.Action))
{