mirror of
https://github.com/ppy/osu.git
synced 2025-01-26 20:13:20 +08:00
Fix multiple issues causing database reset to fail
This commit is contained in:
parent
68910745d8
commit
3a823d6c25
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Microsoft.EntityFrameworkCore.Storage;
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
@ -46,7 +47,10 @@ namespace osu.Game.Database
|
|||||||
public DatabaseWriteUsage GetForWrite(bool withTransaction = true)
|
public DatabaseWriteUsage GetForWrite(bool withTransaction = true)
|
||||||
{
|
{
|
||||||
Monitor.Enter(writeLock);
|
Monitor.Enter(writeLock);
|
||||||
|
OsuDbContext context;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
if (currentWriteTransaction == null && withTransaction)
|
if (currentWriteTransaction == null && withTransaction)
|
||||||
{
|
{
|
||||||
// this mitigates the fact that changes on tracked entities will not be rolled back with the transaction by ensuring write operations are always executed in isolated contexts.
|
// this mitigates the fact that changes on tracked entities will not be rolled back with the transaction by ensuring write operations are always executed in isolated contexts.
|
||||||
@ -54,12 +58,24 @@ namespace osu.Game.Database
|
|||||||
if (threadContexts.IsValueCreated)
|
if (threadContexts.IsValueCreated)
|
||||||
recycleThreadContexts();
|
recycleThreadContexts();
|
||||||
|
|
||||||
currentWriteTransaction = threadContexts.Value.Database.BeginTransaction();
|
context = threadContexts.Value;
|
||||||
|
currentWriteTransaction = context.Database.BeginTransaction();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context = threadContexts.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// retrieval of a context could trigger a fatal error.
|
||||||
|
Monitor.Exit(writeLock);
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
Interlocked.Increment(ref currentWriteUsages);
|
Interlocked.Increment(ref currentWriteUsages);
|
||||||
|
|
||||||
return new DatabaseWriteUsage(threadContexts.Value, usageCompleted) { IsTransactionLeader = currentWriteTransaction != null && currentWriteUsages == 1 };
|
return new DatabaseWriteUsage(context, usageCompleted) { IsTransactionLeader = currentWriteTransaction != null && currentWriteUsages == 1 };
|
||||||
}
|
}
|
||||||
|
|
||||||
private void usageCompleted(DatabaseWriteUsage usage)
|
private void usageCompleted(DatabaseWriteUsage usage)
|
||||||
@ -100,19 +116,18 @@ namespace osu.Game.Database
|
|||||||
|
|
||||||
private void recycleThreadContexts() => threadContexts = new ThreadLocal<OsuDbContext>(CreateContext);
|
private void recycleThreadContexts() => threadContexts = new ThreadLocal<OsuDbContext>(CreateContext);
|
||||||
|
|
||||||
protected virtual OsuDbContext CreateContext()
|
protected virtual OsuDbContext CreateContext() => new OsuDbContext(host.Storage.GetDatabaseConnectionString(database_name))
|
||||||
{
|
{
|
||||||
var ctx = new OsuDbContext(host.Storage.GetDatabaseConnectionString(database_name));
|
Database = { AutoTransactionsEnabled = false }
|
||||||
ctx.Database.AutoTransactionsEnabled = false;
|
};
|
||||||
|
|
||||||
return ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ResetDatabase()
|
public void ResetDatabase()
|
||||||
{
|
{
|
||||||
lock (writeLock)
|
lock (writeLock)
|
||||||
{
|
{
|
||||||
recycleThreadContexts();
|
recycleThreadContexts();
|
||||||
|
GC.Collect();
|
||||||
|
GC.WaitForPendingFinalizers();
|
||||||
host.Storage.DeleteDatabase(database_name);
|
host.Storage.DeleteDatabase(database_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,13 +58,22 @@ namespace osu.Game.Database
|
|||||||
this.connectionString = connectionString;
|
this.connectionString = connectionString;
|
||||||
|
|
||||||
var connection = Database.GetDbConnection();
|
var connection = Database.GetDbConnection();
|
||||||
|
try
|
||||||
|
{
|
||||||
connection.Open();
|
connection.Open();
|
||||||
|
|
||||||
using (var cmd = connection.CreateCommand())
|
using (var cmd = connection.CreateCommand())
|
||||||
{
|
{
|
||||||
cmd.CommandText = "PRAGMA journal_mode=WAL;";
|
cmd.CommandText = "PRAGMA journal_mode=WAL;";
|
||||||
cmd.ExecuteNonQuery();
|
cmd.ExecuteNonQuery();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
connection.Close();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
{
|
{
|
||||||
|
@ -211,15 +211,17 @@ namespace osu.Game
|
|||||||
using (var db = contextFactory.GetForWrite(false))
|
using (var db = contextFactory.GetForWrite(false))
|
||||||
db.Context.Migrate();
|
db.Context.Migrate();
|
||||||
}
|
}
|
||||||
catch (MigrationFailedException e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.Error(e.InnerException ?? e, "Migration failed! We'll be starting with a fresh database.", LoggingTarget.Database);
|
Logger.Error(e.InnerException ?? e, "Migration failed! We'll be starting with a fresh database.", LoggingTarget.Database);
|
||||||
|
|
||||||
// if we failed, let's delete the database and start fresh.
|
// if we failed, let's delete the database and start fresh.
|
||||||
// todo: we probably want a better (non-destructive) migrations/recovery process at a later point than this.
|
// todo: we probably want a better (non-destructive) migrations/recovery process at a later point than this.
|
||||||
contextFactory.ResetDatabase();
|
contextFactory.ResetDatabase();
|
||||||
|
|
||||||
Logger.Log("Database purged successfully.", LoggingTarget.Database, LogLevel.Important);
|
Logger.Log("Database purged successfully.", LoggingTarget.Database, LogLevel.Important);
|
||||||
|
|
||||||
|
// only run once more, then hard bail.
|
||||||
using (var db = contextFactory.GetForWrite(false))
|
using (var db = contextFactory.GetForWrite(false))
|
||||||
db.Context.Migrate();
|
db.Context.Migrate();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user