mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 15:33:05 +08:00
Update terminology to realm "instance" rather than "context"
This matches the terminology used by realm themselves, which feels better.
This commit is contained in:
parent
6eb2c28e41
commit
f30894840c
@ -21,7 +21,7 @@ namespace osu.Game.Tests.Database
|
|||||||
{
|
{
|
||||||
RunTestWithRealm((realmAccess, storage) =>
|
RunTestWithRealm((realmAccess, storage) =>
|
||||||
{
|
{
|
||||||
var realm = realmAccess.Context;
|
var realm = realmAccess.Realm;
|
||||||
var files = new RealmFileStore(realmAccess, storage);
|
var files = new RealmFileStore(realmAccess, storage);
|
||||||
|
|
||||||
var testData = new MemoryStream(new byte[] { 0, 1, 2, 3 });
|
var testData = new MemoryStream(new byte[] { 0, 1, 2, 3 });
|
||||||
@ -38,7 +38,7 @@ namespace osu.Game.Tests.Database
|
|||||||
{
|
{
|
||||||
RunTestWithRealm((realmAccess, storage) =>
|
RunTestWithRealm((realmAccess, storage) =>
|
||||||
{
|
{
|
||||||
var realm = realmAccess.Context;
|
var realm = realmAccess.Realm;
|
||||||
var files = new RealmFileStore(realmAccess, storage);
|
var files = new RealmFileStore(realmAccess, storage);
|
||||||
|
|
||||||
var testData = new MemoryStream(new byte[] { 0, 1, 2, 3 });
|
var testData = new MemoryStream(new byte[] { 0, 1, 2, 3 });
|
||||||
@ -55,7 +55,7 @@ namespace osu.Game.Tests.Database
|
|||||||
{
|
{
|
||||||
RunTestWithRealm((realmAccess, storage) =>
|
RunTestWithRealm((realmAccess, storage) =>
|
||||||
{
|
{
|
||||||
var realm = realmAccess.Context;
|
var realm = realmAccess.Realm;
|
||||||
var files = new RealmFileStore(realmAccess, storage);
|
var files = new RealmFileStore(realmAccess, storage);
|
||||||
|
|
||||||
var file = realm.Write(() => files.Add(new MemoryStream(new byte[] { 0, 1, 2, 3 }), realm));
|
var file = realm.Write(() => files.Add(new MemoryStream(new byte[] { 0, 1, 2, 3 }), realm));
|
||||||
@ -94,7 +94,7 @@ namespace osu.Game.Tests.Database
|
|||||||
{
|
{
|
||||||
RunTestWithRealm((realmAccess, storage) =>
|
RunTestWithRealm((realmAccess, storage) =>
|
||||||
{
|
{
|
||||||
var realm = realmAccess.Context;
|
var realm = realmAccess.Realm;
|
||||||
var files = new RealmFileStore(realmAccess, storage);
|
var files = new RealmFileStore(realmAccess, storage);
|
||||||
|
|
||||||
var file = realm.Write(() => files.Add(new MemoryStream(new byte[] { 0, 1, 2, 3 }), realm));
|
var file = realm.Write(() => files.Add(new MemoryStream(new byte[] { 0, 1, 2, 3 }), realm));
|
||||||
|
@ -76,7 +76,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
.ChildrenOfType<KeyBindingPanel>().SingleOrDefault();
|
.ChildrenOfType<KeyBindingPanel>().SingleOrDefault();
|
||||||
|
|
||||||
private RealmKeyBinding firstOsuRulesetKeyBindings => Game.Dependencies
|
private RealmKeyBinding firstOsuRulesetKeyBindings => Game.Dependencies
|
||||||
.Get<RealmAccess>().Context
|
.Get<RealmAccess>().Realm
|
||||||
.All<RealmKeyBinding>()
|
.All<RealmKeyBinding>()
|
||||||
.AsEnumerable()
|
.AsEnumerable()
|
||||||
.First(k => k.RulesetName == "osu" && k.ActionInt == 0);
|
.First(k => k.RulesetName == "osu" && k.ActionInt == 0);
|
||||||
|
@ -59,9 +59,9 @@ namespace osu.Game.Database
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lock object which is held during <see cref="BlockAllOperations"/> sections, blocking context creation during blocking periods.
|
/// Lock object which is held during <see cref="BlockAllOperations"/> sections, blocking context creation during blocking periods.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly SemaphoreSlim contextCreationLock = new SemaphoreSlim(1);
|
private readonly SemaphoreSlim realmCreationLock = new SemaphoreSlim(1);
|
||||||
|
|
||||||
private readonly ThreadLocal<bool> currentThreadCanCreateContexts = new ThreadLocal<bool>();
|
private readonly ThreadLocal<bool> currentThreadCanCreateRealmInstances = new ThreadLocal<bool>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Holds a map of functions registered via <see cref="RegisterCustomSubscription"/> and <see cref="RegisterForNotifications{T}"/> and a coinciding action which when triggered,
|
/// Holds a map of functions registered via <see cref="RegisterCustomSubscription"/> and <see cref="RegisterForNotifications{T}"/> and a coinciding action which when triggered,
|
||||||
@ -81,35 +81,35 @@ namespace osu.Game.Database
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly Dictionary<Func<Realm, IDisposable?>, Action> notificationsResetMap = new Dictionary<Func<Realm, IDisposable?>, Action>();
|
private readonly Dictionary<Func<Realm, IDisposable?>, Action> notificationsResetMap = new Dictionary<Func<Realm, IDisposable?>, Action>();
|
||||||
|
|
||||||
private static readonly GlobalStatistic<int> contexts_created = GlobalStatistics.Get<int>(@"Realm", @"Contexts (Created)");
|
private static readonly GlobalStatistic<int> realm_instances_created = GlobalStatistics.Get<int>(@"Realm", @"Instances (Created)");
|
||||||
|
|
||||||
private readonly object contextLock = new object();
|
private readonly object realmLock = new object();
|
||||||
|
|
||||||
private Realm? context;
|
private Realm? updateRealm;
|
||||||
|
|
||||||
public Realm Context => ensureUpdateContext();
|
public Realm Realm => ensureUpdateRealm();
|
||||||
|
|
||||||
private Realm ensureUpdateContext()
|
private Realm ensureUpdateRealm()
|
||||||
{
|
{
|
||||||
if (!ThreadSafety.IsUpdateThread)
|
if (!ThreadSafety.IsUpdateThread)
|
||||||
throw new InvalidOperationException(@$"Use {nameof(createContext)} when performing realm operations from a non-update thread");
|
throw new InvalidOperationException(@$"Use {nameof(getRealmInstance)} when performing realm operations from a non-update thread");
|
||||||
|
|
||||||
lock (contextLock)
|
lock (realmLock)
|
||||||
{
|
{
|
||||||
if (context == null)
|
if (updateRealm == null)
|
||||||
{
|
{
|
||||||
context = createContext();
|
updateRealm = getRealmInstance();
|
||||||
Logger.Log(@$"Opened realm ""{context.Config.DatabasePath}"" at version {context.Config.SchemaVersion}");
|
|
||||||
|
Logger.Log(@$"Opened realm ""{updateRealm.Config.DatabasePath}"" at version {updateRealm.Config.SchemaVersion}");
|
||||||
|
|
||||||
// Resubscribe any subscriptions
|
// Resubscribe any subscriptions
|
||||||
foreach (var action in customSubscriptionsResetMap.Keys)
|
foreach (var action in customSubscriptionsResetMap.Keys)
|
||||||
registerSubscription(action);
|
registerSubscription(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug.Assert(context != null);
|
Debug.Assert(updateRealm != null);
|
||||||
|
|
||||||
// creating a context will ensure our schema is up-to-date and migrated.
|
return updateRealm;
|
||||||
return context;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +118,7 @@ namespace osu.Game.Database
|
|||||||
private static readonly ThreadLocal<bool> current_thread_subscriptions_allowed = new ThreadLocal<bool>();
|
private static readonly ThreadLocal<bool> current_thread_subscriptions_allowed = new ThreadLocal<bool>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Construct a new instance of a realm context factory.
|
/// Construct a new instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="storage">The game storage which will be used to create the realm backing file.</param>
|
/// <param name="storage">The game storage which will be used to create the realm backing file.</param>
|
||||||
/// <param name="filename">The filename to use for the realm backing file. A ".realm" extension will be added automatically if not specified.</param>
|
/// <param name="filename">The filename to use for the realm backing file. A ".realm" extension will be added automatically if not specified.</param>
|
||||||
@ -137,7 +137,7 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// This method triggers the first `CreateContext` call, which will implicitly run realm migrations and bring the schema up-to-date.
|
// This method triggers the first `getRealmInstance` call, which will implicitly run realm migrations and bring the schema up-to-date.
|
||||||
cleanupPendingDeletions();
|
cleanupPendingDeletions();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -153,7 +153,7 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
private void cleanupPendingDeletions()
|
private void cleanupPendingDeletions()
|
||||||
{
|
{
|
||||||
using (var realm = createContext())
|
using (var realm = getRealmInstance())
|
||||||
using (var transaction = realm.BeginWrite())
|
using (var transaction = realm.BeginWrite())
|
||||||
{
|
{
|
||||||
var pendingDeleteScores = realm.All<ScoreInfo>().Where(s => s.DeletePending);
|
var pendingDeleteScores = realm.All<ScoreInfo>().Where(s => s.DeletePending);
|
||||||
@ -201,34 +201,28 @@ namespace osu.Game.Database
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Run work on realm with a return value.
|
/// Run work on realm with a return value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
|
||||||
/// Handles correct context management automatically.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="action">The work to run.</param>
|
/// <param name="action">The work to run.</param>
|
||||||
/// <typeparam name="T">The return type.</typeparam>
|
/// <typeparam name="T">The return type.</typeparam>
|
||||||
public T Run<T>(Func<Realm, T> action)
|
public T Run<T>(Func<Realm, T> action)
|
||||||
{
|
{
|
||||||
if (ThreadSafety.IsUpdateThread)
|
if (ThreadSafety.IsUpdateThread)
|
||||||
return action(Context);
|
return action(Realm);
|
||||||
|
|
||||||
using (var realm = createContext())
|
using (var realm = getRealmInstance())
|
||||||
return action(realm);
|
return action(realm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Run work on realm.
|
/// Run work on realm.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
|
||||||
/// Handles correct context management automatically.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="action">The work to run.</param>
|
/// <param name="action">The work to run.</param>
|
||||||
public void Run(Action<Realm> action)
|
public void Run(Action<Realm> action)
|
||||||
{
|
{
|
||||||
if (ThreadSafety.IsUpdateThread)
|
if (ThreadSafety.IsUpdateThread)
|
||||||
action(Context);
|
action(Realm);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
using (var realm = createContext())
|
using (var realm = getRealmInstance())
|
||||||
action(realm);
|
action(realm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -236,17 +230,14 @@ namespace osu.Game.Database
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Write changes to realm.
|
/// Write changes to realm.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
|
||||||
/// Handles correct context management and transaction committing automatically.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="action">The work to run.</param>
|
/// <param name="action">The work to run.</param>
|
||||||
public void Write(Action<Realm> action)
|
public void Write(Action<Realm> action)
|
||||||
{
|
{
|
||||||
if (ThreadSafety.IsUpdateThread)
|
if (ThreadSafety.IsUpdateThread)
|
||||||
Context.Write(action);
|
Realm.Write(action);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
using (var realm = createContext())
|
using (var realm = getRealmInstance())
|
||||||
realm.Write(action);
|
realm.Write(action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -257,10 +248,10 @@ namespace osu.Game.Database
|
|||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This adds osu! specific thread and managed state safety checks on top of <see cref="IRealmCollection{T}.SubscribeForNotifications"/>.
|
/// This adds osu! specific thread and managed state safety checks on top of <see cref="IRealmCollection{T}.SubscribeForNotifications"/>.
|
||||||
///
|
///
|
||||||
/// In addition to the documented realm behaviour, we have the additional requirement of handling subscriptions over potential context loss.
|
/// In addition to the documented realm behaviour, we have the additional requirement of handling subscriptions over potential realm instance recycle.
|
||||||
/// When this happens, callback events will be automatically fired:
|
/// When this happens, callback events will be automatically fired:
|
||||||
/// - On context loss, a callback with an empty collection and <c>null</c> <see cref="ChangeSet"/> will be invoked.
|
/// - On recycle start, a callback with an empty collection and <c>null</c> <see cref="ChangeSet"/> will be invoked.
|
||||||
/// - On context revival, a standard initial realm callback will arrive, with <c>null</c> <see cref="ChangeSet"/> and an up-to-date collection.
|
/// - On recycle end, a standard initial realm callback will arrive, with <c>null</c> <see cref="ChangeSet"/> and an up-to-date collection.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="query">The <see cref="IQueryable{T}"/> to observe for changes.</param>
|
/// <param name="query">The <see cref="IQueryable{T}"/> to observe for changes.</param>
|
||||||
/// <typeparam name="T">Type of the elements in the list.</typeparam>
|
/// <typeparam name="T">Type of the elements in the list.</typeparam>
|
||||||
@ -276,7 +267,7 @@ namespace osu.Game.Database
|
|||||||
if (!ThreadSafety.IsUpdateThread)
|
if (!ThreadSafety.IsUpdateThread)
|
||||||
throw new InvalidOperationException(@$"{nameof(RegisterForNotifications)} must be called from the update thread.");
|
throw new InvalidOperationException(@$"{nameof(RegisterForNotifications)} must be called from the update thread.");
|
||||||
|
|
||||||
lock (contextLock)
|
lock (realmLock)
|
||||||
{
|
{
|
||||||
Func<Realm, IDisposable?> action = realm => query(realm).QueryAsyncWithNotifications(callback);
|
Func<Realm, IDisposable?> action = realm => query(realm).QueryAsyncWithNotifications(callback);
|
||||||
|
|
||||||
@ -287,7 +278,7 @@ namespace osu.Game.Database
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Run work on realm that will be run every time the update thread realm context gets recycled.
|
/// Run work on realm that will be run every time the update thread realm instance gets recycled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="action">The work to run. Return value should be an <see cref="IDisposable"/> from QueryAsyncWithNotifications, or an <see cref="InvokeOnDisposal"/> to clean up any bindings.</param>
|
/// <param name="action">The work to run. Return value should be an <see cref="IDisposable"/> from QueryAsyncWithNotifications, or an <see cref="InvokeOnDisposal"/> to clean up any bindings.</param>
|
||||||
/// <returns>An <see cref="IDisposable"/> which should be disposed to unsubscribe any inner subscription.</returns>
|
/// <returns>An <see cref="IDisposable"/> which should be disposed to unsubscribe any inner subscription.</returns>
|
||||||
@ -311,7 +302,7 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
void unsubscribe()
|
void unsubscribe()
|
||||||
{
|
{
|
||||||
lock (contextLock)
|
lock (realmLock)
|
||||||
{
|
{
|
||||||
if (customSubscriptionsResetMap.TryGetValue(action, out var unsubscriptionAction))
|
if (customSubscriptionsResetMap.TryGetValue(action, out var unsubscriptionAction))
|
||||||
{
|
{
|
||||||
@ -328,12 +319,12 @@ namespace osu.Game.Database
|
|||||||
{
|
{
|
||||||
Debug.Assert(ThreadSafety.IsUpdateThread);
|
Debug.Assert(ThreadSafety.IsUpdateThread);
|
||||||
|
|
||||||
lock (contextLock)
|
lock (realmLock)
|
||||||
{
|
{
|
||||||
// Retrieve context outside of flag update to ensure that the context is constructed,
|
// Retrieve realm instance outside of flag update to ensure that the instance is retrieved,
|
||||||
// as attempting to access it inside the subscription if it's not constructed would lead to
|
// as attempting to access it inside the subscription if it's not constructed would lead to
|
||||||
// cyclic invocations of the subscription callback.
|
// cyclic invocations of the subscription callback.
|
||||||
var realm = Context;
|
var realm = Realm;
|
||||||
|
|
||||||
Debug.Assert(!customSubscriptionsResetMap.TryGetValue(action, out var found) || found == null);
|
Debug.Assert(!customSubscriptionsResetMap.TryGetValue(action, out var found) || found == null);
|
||||||
|
|
||||||
@ -344,12 +335,12 @@ namespace osu.Game.Database
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unregister all subscriptions when the realm context is to be recycled.
|
/// Unregister all subscriptions when the realm instance is to be recycled.
|
||||||
/// Subscriptions will still remain and will be re-subscribed when the realm context returns.
|
/// Subscriptions will still remain and will be re-subscribed when the realm instance returns.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void unregisterAllSubscriptions()
|
private void unregisterAllSubscriptions()
|
||||||
{
|
{
|
||||||
lock (contextLock)
|
lock (realmLock)
|
||||||
{
|
{
|
||||||
foreach (var action in notificationsResetMap.Values)
|
foreach (var action in notificationsResetMap.Values)
|
||||||
action();
|
action();
|
||||||
@ -362,7 +353,7 @@ namespace osu.Game.Database
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Realm createContext()
|
private Realm getRealmInstance()
|
||||||
{
|
{
|
||||||
if (isDisposed)
|
if (isDisposed)
|
||||||
throw new ObjectDisposedException(nameof(RealmAccess));
|
throw new ObjectDisposedException(nameof(RealmAccess));
|
||||||
@ -371,20 +362,20 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!currentThreadCanCreateContexts.Value)
|
if (!currentThreadCanCreateRealmInstances.Value)
|
||||||
{
|
{
|
||||||
contextCreationLock.Wait();
|
realmCreationLock.Wait();
|
||||||
currentThreadCanCreateContexts.Value = true;
|
currentThreadCanCreateRealmInstances.Value = true;
|
||||||
tookSemaphoreLock = true;
|
tookSemaphoreLock = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// the semaphore is used to handle blocking of all context creation during certain periods.
|
// the semaphore is used to handle blocking of all realm retrieval during certain periods.
|
||||||
// once the semaphore has been taken by this code section, it is safe to create further contexts on the same thread.
|
// once the semaphore has been taken by this code section, it is safe to retrieve further realm instances on the same thread.
|
||||||
// this can happen if a realm subscription is active and triggers a callback which has user code that calls `CreateContext`.
|
// this can happen if a realm subscription is active and triggers a callback which has user code that calls `Run`.
|
||||||
}
|
}
|
||||||
|
|
||||||
contexts_created.Value++;
|
realm_instances_created.Value++;
|
||||||
|
|
||||||
return Realm.GetInstance(getConfiguration());
|
return Realm.GetInstance(getConfiguration());
|
||||||
}
|
}
|
||||||
@ -392,8 +383,8 @@ namespace osu.Game.Database
|
|||||||
{
|
{
|
||||||
if (tookSemaphoreLock)
|
if (tookSemaphoreLock)
|
||||||
{
|
{
|
||||||
contextCreationLock.Release();
|
realmCreationLock.Release();
|
||||||
currentThreadCanCreateContexts.Value = false;
|
currentThreadCanCreateRealmInstances.Value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -582,7 +573,7 @@ namespace osu.Game.Database
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Flush any active contexts and block any further writes.
|
/// Flush any active realm instances and block any further writes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This should be used in places we need to ensure no ongoing reads/writes are occurring with realm.
|
/// This should be used in places we need to ensure no ongoing reads/writes are occurring with realm.
|
||||||
@ -598,14 +589,14 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
contextCreationLock.Wait();
|
realmCreationLock.Wait();
|
||||||
|
|
||||||
lock (contextLock)
|
lock (realmLock)
|
||||||
{
|
{
|
||||||
if (context == null)
|
if (updateRealm == null)
|
||||||
{
|
{
|
||||||
// null context means the update thread has not yet retrieved its context.
|
// null realm means the update thread has not yet retrieved its instance.
|
||||||
// we don't need to worry about reviving the update context in this case, so don't bother with the SynchronizationContext.
|
// we don't need to worry about reviving the update instance in this case, so don't bother with the SynchronizationContext.
|
||||||
Debug.Assert(!ThreadSafety.IsUpdateThread);
|
Debug.Assert(!ThreadSafety.IsUpdateThread);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -620,8 +611,8 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
Logger.Log(@"Blocking realm operations.", LoggingTarget.Database);
|
Logger.Log(@"Blocking realm operations.", LoggingTarget.Database);
|
||||||
|
|
||||||
context?.Dispose();
|
updateRealm?.Dispose();
|
||||||
context = null;
|
updateRealm = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int sleep_length = 200;
|
const int sleep_length = 200;
|
||||||
@ -648,17 +639,17 @@ namespace osu.Game.Database
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
contextCreationLock.Release();
|
realmCreationLock.Release();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new InvokeOnDisposal<RealmAccess>(this, factory =>
|
return new InvokeOnDisposal<RealmAccess>(this, factory =>
|
||||||
{
|
{
|
||||||
factory.contextCreationLock.Release();
|
factory.realmCreationLock.Release();
|
||||||
Logger.Log(@"Restoring realm operations.", LoggingTarget.Database);
|
Logger.Log(@"Restoring realm operations.", LoggingTarget.Database);
|
||||||
|
|
||||||
// Post back to the update thread to revive any subscriptions.
|
// Post back to the update thread to revive any subscriptions.
|
||||||
syncContext?.Post(_ => ensureUpdateContext(), null);
|
syncContext?.Post(_ => ensureUpdateRealm(), null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -669,16 +660,16 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
lock (contextLock)
|
lock (realmLock)
|
||||||
{
|
{
|
||||||
context?.Dispose();
|
updateRealm?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isDisposed)
|
if (!isDisposed)
|
||||||
{
|
{
|
||||||
// intentionally block context creation indefinitely. this ensures that nothing can start consuming a new context after disposal.
|
// intentionally block context creation indefinitely. this ensures that nothing can start consuming a new context after disposal.
|
||||||
contextCreationLock.Wait();
|
realmCreationLock.Wait();
|
||||||
contextCreationLock.Dispose();
|
realmCreationLock.Dispose();
|
||||||
|
|
||||||
isDisposed = true;
|
isDisposed = true;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ 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 = Access.Context.Find<TModel>(item.ID);
|
var managed = Access.Realm.Find<TModel>(item.ID);
|
||||||
managed.Realm.Write(() => operation(managed));
|
managed.Realm.Write(() => operation(managed));
|
||||||
|
|
||||||
item.Files.Clear();
|
item.Files.Clear();
|
||||||
|
Loading…
Reference in New Issue
Block a user