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

Tidy up write usage class

This commit is contained in:
Dean Herbert 2021-01-13 18:24:19 +09:00
parent 5fa3a22f28
commit 8442b34e84
3 changed files with 22 additions and 116 deletions

View File

@ -22,6 +22,6 @@ namespace osu.Game.Database
/// This method may block if a write is already active on a different thread.
/// </summary>
/// <returns>A usage containing a usable context.</returns>
RealmWriteUsage GetForWrite();
RealmContextFactory.RealmWriteUsage GetForWrite();
}
}

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System.Threading;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Logging;
using osu.Framework.Platform;
@ -13,6 +14,7 @@ namespace osu.Game.Database
public class RealmContextFactory : Component, IRealmFactory
{
private readonly Storage storage;
private const string database_name = @"client";
private const int schema_version = 5;
@ -22,20 +24,11 @@ namespace osu.Game.Database
/// </summary>
private readonly object writeLock = new object();
private ThreadLocal<bool> refreshCompleted = new ThreadLocal<bool>();
private bool rollbackRequired;
private int currentWriteUsages;
private Transaction currentWriteTransaction;
private static readonly GlobalStatistic<int> reads = GlobalStatistics.Get<int>("Realm", "Get (Read)");
private static readonly GlobalStatistic<int> writes = GlobalStatistics.Get<int>("Realm", "Get (Write)");
private static readonly GlobalStatistic<int> refreshes = GlobalStatistics.Get<int>("Realm", "Refreshes");
private static readonly GlobalStatistic<int> commits = GlobalStatistics.Get<int>("Realm", "Commits");
private static readonly GlobalStatistic<int> rollbacks = GlobalStatistics.Get<int>("Realm", "Rollbacks");
private static readonly GlobalStatistic<int> contexts_open = GlobalStatistics.Get<int>("Realm", "Contexts (Open)");
private static readonly GlobalStatistic<int> refreshes = GlobalStatistics.Get<int>("Realm", "Dirty Refreshes");
private static readonly GlobalStatistic<int> contexts_created = GlobalStatistics.Get<int>("Realm", "Contexts (Created)");
private Realm context;
@ -72,24 +65,8 @@ namespace osu.Game.Database
writes.Value++;
Monitor.Enter(writeLock);
Realm realm;
try
{
realm = createContext();
currentWriteTransaction ??= realm.BeginWrite();
}
catch
{
// retrieval of a context could trigger a fatal error.
Monitor.Exit(writeLock);
throw;
}
Interlocked.Increment(ref currentWriteUsages);
return new RealmWriteUsage(realm, usageCompleted) { IsTransactionLeader = currentWriteTransaction != null && currentWriteUsages == 1 };
return new RealmWriteUsage(this);
}
protected override void Update()
@ -111,41 +88,25 @@ namespace osu.Game.Database
});
}
private void usageCompleted(RealmWriteUsage usage)
{
int usages = Interlocked.Decrement(ref currentWriteUsages);
try
{
rollbackRequired |= usage.RollbackRequired;
if (usages == 0)
{
if (rollbackRequired)
{
rollbacks.Value++;
currentWriteTransaction?.Rollback();
}
else
{
commits.Value++;
currentWriteTransaction?.Commit();
}
currentWriteTransaction = null;
rollbackRequired = false;
refreshCompleted = new ThreadLocal<bool>();
}
}
finally
{
Monitor.Exit(writeLock);
}
}
private void onMigration(Migration migration, ulong lastSchemaVersion)
{
}
public class RealmWriteUsage : InvokeOnDisposal<RealmContextFactory>
{
public readonly Realm Context;
public RealmWriteUsage(RealmContextFactory factory)
: base(factory, usageCompleted)
{
Context = factory.createContext();
Context.BeginWrite();
}
private static void usageCompleted(RealmContextFactory factory)
{
Monitor.Exit(factory.writeLock);
}
}
}
}

View File

@ -1,55 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using Realms;
namespace osu.Game.Database
{
public class RealmWriteUsage : IDisposable
{
public readonly Realm Context;
private readonly Action<RealmWriteUsage> usageCompleted;
public bool RollbackRequired { get; private set; }
public RealmWriteUsage(Realm context, Action<RealmWriteUsage> onCompleted)
{
Context = context;
usageCompleted = onCompleted;
}
/// <summary>
/// Whether this write usage will commit a transaction on completion.
/// If false, there is a parent usage responsible for transaction commit.
/// </summary>
public bool IsTransactionLeader;
private bool isDisposed;
protected void Dispose(bool disposing)
{
if (isDisposed) return;
isDisposed = true;
usageCompleted?.Invoke(this);
}
public void Rollback(Exception error = null)
{
RollbackRequired = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~RealmWriteUsage()
{
Dispose(false);
}
}
}