1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-22 08:07:24 +08:00

Fix thread safety of realm Refresh operation

Due to the lack of locking, there was a chance the the update thread
`context` was retrieved just before the `flushContexts` call, followed
by `.Refresh()` being run while the blocking behaviour was invoked.

This can be seen in test failures such as
https://ci.appveyor.com/project/peppy/osu/builds/39859786/tests.

As an aside, I tried multiple different methods to avoid `lock()` on the
update thread but they felt flaky. The overhead of lock when there's no
contention is reportedly around 30-50ns, so likely not of concern. We
can address it at a later point if it becomes one.
This commit is contained in:
Dean Herbert 2021-07-04 16:24:39 +09:00
parent 49090a0d1b
commit 567e9f33a9

View File

@ -38,6 +38,8 @@ namespace osu.Game.Database
private static readonly GlobalStatistic<int> pending_writes = GlobalStatistics.Get<int>("Realm", "Pending writes");
private static readonly GlobalStatistic<int> active_usages = GlobalStatistics.Get<int>("Realm", "Active usages");
private readonly object updateContextLock = new object();
private Realm context;
public Realm Context
@ -107,8 +109,11 @@ namespace osu.Game.Database
{
base.Update();
if (context?.Refresh() == true)
refreshes.Value++;
lock (updateContextLock)
{
if (context?.Refresh() == true)
refreshes.Value++;
}
}
private Realm createContext()
@ -156,7 +161,9 @@ namespace osu.Game.Database
Logger.Log(@"Flushing realm contexts...", LoggingTarget.Database);
var previousContext = context;
context = null;
lock (updateContextLock)
context = null;
// wait for all threaded usages to finish
while (active_usages.Value > 0)