1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-28 08:02:55 +08:00

Merge pull request #1389 from peppy/db-migration-fixes

Fix a few issues with database upgrade
This commit is contained in:
Dean Herbert 2017-10-21 12:46:45 +09:00 committed by GitHub
commit a6f48f7f9f
3 changed files with 60 additions and 20 deletions

View File

@ -9,11 +9,19 @@ namespace osu.Game.Database
{
private readonly GameHost host;
private const string database_name = @"client";
public DatabaseContextFactory(GameHost host)
{
this.host = host;
}
public OsuDbContext GetContext() => new OsuDbContext(host.Storage.GetDatabaseConnectionString(@"client"));
public OsuDbContext GetContext() => new OsuDbContext(host.Storage.GetDatabaseConnectionString(database_name));
public void ResetDatabase()
{
// todo: we probably want to make sure there are no active contexts before performing this operation.
host.Storage.DeleteDatabase(database_name);
}
}
}

View File

@ -3,6 +3,7 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.Extensions.Logging;
using osu.Framework.Logging;
using osu.Game.Beatmaps;
@ -63,8 +64,12 @@ namespace osu.Game.Database
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseSqlite(connectionString);
optionsBuilder.UseLoggerFactory(logger.Value);
optionsBuilder
// this is required for the time being due to the way we are querying in places like BeatmapStore.
// if we ever move to having consumers file their own .Includes, or get eager loading support, this could be re-enabled.
.ConfigureWarnings(warnings => warnings.Ignore(CoreEventId.IncludeIgnoredWarning))
.UseSqlite(connectionString)
.UseLoggerFactory(logger.Value);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
@ -160,7 +165,15 @@ namespace osu.Game.Database
public void Migrate()
{
migrateFromSqliteNet();
Database.Migrate();
try
{
Database.Migrate();
}
catch (Exception e)
{
throw new MigrationFailedException(e);
}
}
private void migrateFromSqliteNet()
@ -179,6 +192,8 @@ namespace osu.Game.Database
try
{
Logger.Log("Performing migration from sqlite-net to EF...", LoggingTarget.Database, Framework.Logging.LogLevel.Important);
// we are good to perform messy migration of data!.
Database.ExecuteSqlCommand("ALTER TABLE BeatmapDifficulty RENAME TO BeatmapDifficulty_Old");
Database.ExecuteSqlCommand("ALTER TABLE BeatmapMetadata RENAME TO BeatmapMetadata_Old");
@ -219,13 +234,14 @@ namespace osu.Game.Database
Database.ExecuteSqlCommand("DROP TABLE RulesetInfo_Old");
Database.ExecuteSqlCommand(
"INSERT INTO BeatmapInfo SELECT ID, AudioLeadIn, BaseDifficultyID, BeatDivisor, BeatmapSetInfoID, Countdown, DistanceSpacing, GridSize, Hash, Hidden, LetterboxInBreaks, MD5Hash, NULLIF(BeatmapMetadataID, 0), OnlineBeatmapID, Path, RulesetID, SpecialStyle, StackLeniency, StarDifficulty, StoredBookmarks, TimelineZoom, Version, WidescreenStoryboard FROM BeatmapInfo_Old");
"INSERT INTO BeatmapInfo SELECT ID, AudioLeadIn, BaseDifficultyID, BeatDivisor, BeatmapSetInfoID, Countdown, DistanceSpacing, GridSize, Hash, IFNULL(Hidden, 0), LetterboxInBreaks, MD5Hash, NULLIF(BeatmapMetadataID, 0), OnlineBeatmapID, Path, RulesetID, SpecialStyle, StackLeniency, StarDifficulty, StoredBookmarks, TimelineZoom, Version, WidescreenStoryboard FROM BeatmapInfo_Old");
Database.ExecuteSqlCommand("DROP TABLE BeatmapInfo_Old");
Logger.Log("Migration complete!", LoggingTarget.Database, Framework.Logging.LogLevel.Important);
}
catch
catch (Exception e)
{
// if anything went wrong during migration just nuke the database.
throw new MigrationFailedException();
throw new MigrationFailedException(e);
}
}
catch (MigrationFailedException e)
@ -241,5 +257,9 @@ namespace osu.Game.Database
public class MigrationFailedException : Exception
{
public MigrationFailedException(Exception exception)
: base("sqlite-net migration failed", exception)
{
}
}
}

View File

@ -17,6 +17,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Cursor;
using osu.Game.Online.API;
using osu.Framework.Graphics.Performance;
using osu.Framework.Logging;
using osu.Game.Database;
using osu.Game.Input;
using osu.Game.Input.Bindings;
@ -90,18 +91,7 @@ namespace osu.Game
dependencies.Cache(this);
dependencies.Cache(LocalConfig);
try
{
using (var context = contextFactory.GetContext())
context.Migrate();
}
catch (MigrationFailedException)
{
using (var context = contextFactory.GetContext())
context.Database.EnsureDeleted();
using (var context = contextFactory.GetContext())
context.Migrate();
}
runMigrations();
dependencies.Cache(API = new APIAccess
{
@ -173,6 +163,28 @@ namespace osu.Game
FileStore.Cleanup();
}
private void runMigrations()
{
try
{
using (var context = contextFactory.GetContext())
context.Migrate();
}
catch (MigrationFailedException e)
{
Logger.Log((e.InnerException ?? e).ToString(), LoggingTarget.Database, LogLevel.Error);
Logger.Log("Migration failed! We'll be starting with a fresh database.", LoggingTarget.Database, LogLevel.Error);
// 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.
contextFactory.ResetDatabase();
Logger.Log("Database purged successfully.", LoggingTarget.Database, LogLevel.Important);
using (var context = contextFactory.GetContext())
context.Migrate();
}
}
private WorkingBeatmap lastBeatmap;
public void APIStateChanged(APIAccess api, APIState state)