DatabaseWriteUsage

This commit is contained in:
Dean Herbert
2018-02-12 17:55:11 +09:00
parent cc948d688f
commit edc3638175
14 changed files with 385 additions and 354 deletions

View File

@ -1,10 +1,8 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.EntityFrameworkCore;
using osu.Framework.Platform;
@ -17,9 +15,7 @@ namespace osu.Game.Database
/// <summary>
/// Create a new <see cref="OsuDbContext"/> instance (separate from the shared context via <see cref="GetContext"/> for performing isolated operations.
/// </summary>
protected readonly Func<OsuDbContext> CreateContext;
private readonly ThreadLocal<OsuDbContext> queryContext;
protected readonly DatabaseContextFactory ContextFactory;
/// <summary>
/// Refresh an instance potentially from a different thread with a local context-tracked instance.
@ -29,33 +25,27 @@ namespace osu.Game.Database
/// <typeparam name="T">A valid EF-stored type.</typeparam>
protected virtual void Refresh<T>(ref T obj, IEnumerable<T> lookupSource = null) where T : class, IHasPrimaryKey
{
var context = GetContext();
if (context.Entry(obj).State != EntityState.Detached) return;
var id = obj.ID;
var foundObject = lookupSource?.SingleOrDefault(t => t.ID == id) ?? context.Find<T>(id);
if (foundObject != null)
using (var usage = ContextFactory.GetForWrite())
{
obj = foundObject;
context.Entry(obj).Reload();
var context = usage.Context;
if (context.Entry(obj).State != EntityState.Detached) return;
var id = obj.ID;
var foundObject = lookupSource?.SingleOrDefault(t => t.ID == id) ?? context.Find<T>(id);
if (foundObject != null)
{
obj = foundObject;
context.Entry(obj).Reload();
}
else
context.Add(obj);
}
else
context.Add(obj);
}
/// <summary>
/// Retrieve a shared context for performing lookups (or write operations on the update thread, for now).
/// </summary>
protected OsuDbContext GetContext() => queryContext.Value;
protected DatabaseBackedStore(Func<OsuDbContext> createContext, Storage storage = null)
protected DatabaseBackedStore(DatabaseContextFactory contextFactory, Storage storage = null)
{
CreateContext = createContext;
// todo: while this seems to work quite well, we need to consider that contexts could enter a state where they are never cleaned up.
queryContext = new ThreadLocal<OsuDbContext>(CreateContext);
ContextFactory = contextFactory;
Storage = storage;
}