Fixed: Recreate log database if migration fails

Fixes: #1050
pull/3113/head
Mark McDowall 8 years ago committed by GitHub
parent 8255fb0b28
commit 857d661ff1

@ -9,6 +9,7 @@ namespace NzbDrone.Core.Datastore
{ {
string MainDbConnectionString { get; } string MainDbConnectionString { get; }
string LogDbConnectionString { get; } string LogDbConnectionString { get; }
string GetDatabasePath(string connectionString);
} }
public class ConnectionStringFactory : IConnectionStringFactory public class ConnectionStringFactory : IConnectionStringFactory
@ -22,6 +23,13 @@ namespace NzbDrone.Core.Datastore
public string MainDbConnectionString { get; private set; } public string MainDbConnectionString { get; private set; }
public string LogDbConnectionString { get; private set; } public string LogDbConnectionString { get; private set; }
public string GetDatabasePath(string connectionString)
{
var connectionBuilder = new SQLiteConnectionStringBuilder(connectionString);
return connectionBuilder.DataSource;
}
private static string GetConnectionString(string dbPath) private static string GetConnectionString(string dbPath)
{ {
var connectionBuilder = new SQLiteConnectionStringBuilder(); var connectionBuilder = new SQLiteConnectionStringBuilder();

@ -0,0 +1,24 @@
using System;
using NzbDrone.Common.Exceptions;
namespace NzbDrone.Core.Datastore
{
public class CorruptDatabaseException : NzbDroneException
{
public CorruptDatabaseException(string message, params object[] args) : base(message, args)
{
}
public CorruptDatabaseException(string message) : base(message)
{
}
public CorruptDatabaseException(string message, Exception innerException, params object[] args) : base(message, innerException, args)
{
}
public CorruptDatabaseException(string message, Exception innerException) : base(message, innerException)
{
}
}
}

@ -1,11 +1,14 @@
using System; using System;
using System.Data.SQLite; using System.Data.SQLite;
using System.IO;
using Marr.Data; using Marr.Data;
using Marr.Data.Reflection; using Marr.Data.Reflection;
using NLog;
using NzbDrone.Common.Composition; using NzbDrone.Common.Composition;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Instrumentation;
using NzbDrone.Core.Datastore.Migration.Framework; using NzbDrone.Core.Datastore.Migration.Framework;
using NzbDrone.Core.Instrumentation;
using NzbDrone.Core.Messaging.Events;
namespace NzbDrone.Core.Datastore namespace NzbDrone.Core.Datastore
@ -18,8 +21,10 @@ namespace NzbDrone.Core.Datastore
public class DbFactory : IDbFactory public class DbFactory : IDbFactory
{ {
private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(DbFactory));
private readonly IMigrationController _migrationController; private readonly IMigrationController _migrationController;
private readonly IConnectionStringFactory _connectionStringFactory; private readonly IConnectionStringFactory _connectionStringFactory;
private readonly IDiskProvider _diskProvider;
static DbFactory() static DbFactory()
{ {
@ -38,10 +43,13 @@ namespace NzbDrone.Core.Datastore
container.Register<ILogDatabase>(logDb); container.Register<ILogDatabase>(logDb);
} }
public DbFactory(IMigrationController migrationController, IConnectionStringFactory connectionStringFactory) public DbFactory(IMigrationController migrationController,
IConnectionStringFactory connectionStringFactory,
IDiskProvider diskProvider)
{ {
_migrationController = migrationController; _migrationController = migrationController;
_connectionStringFactory = connectionStringFactory; _connectionStringFactory = connectionStringFactory;
_diskProvider = diskProvider;
} }
public IDatabase Create(MigrationType migrationType = MigrationType.Main) public IDatabase Create(MigrationType migrationType = MigrationType.Main)
@ -72,7 +80,43 @@ namespace NzbDrone.Core.Datastore
} }
} }
_migrationController.Migrate(connectionString, migrationContext); try
{
_migrationController.Migrate(connectionString, migrationContext);
}
catch (SQLiteException ex)
{
var fileName = _connectionStringFactory.GetDatabasePath(connectionString);
if (migrationContext.MigrationType == MigrationType.Log)
{
Logger.Error(ex, "Logging database is corrupt, attempting to recreate it automatically");
try
{
_diskProvider.DeleteFile(fileName + "-shm");
_diskProvider.DeleteFile(fileName + "-wal");
_diskProvider.DeleteFile(fileName + "-journal");
_diskProvider.DeleteFile(fileName);
}
catch (Exception)
{
Logger.Error("Unable to recreate logging database automatically. It will need to be removed manually.");
}
_migrationController.Migrate(connectionString, migrationContext);
}
else
{
if (OsInfo.IsOsx)
{
throw new CorruptDatabaseException("Database file: {0} is corrupt, restore from backup if available. See: https://github.com/Sonarr/Sonarr/wiki/FAQ#i-use-sonarr-on-a-mac-and-it-suddenly-stopped-working-what-happened", ex, fileName);
}
throw new CorruptDatabaseException("Database file: {0} is corrupt, restore from backup if available. See: https://github.com/Sonarr/Sonarr/wiki/FAQ#i-am-getting-an-error-database-disk-image-is-malformed", ex, fileName);
}
}
var db = new Database(migrationContext.MigrationType.ToString(), () => var db = new Database(migrationContext.MigrationType.ToString(), () =>
{ {

@ -1,4 +1,4 @@
using System; using System.Data.SQLite;
using System.Diagnostics; using System.Diagnostics;
using System.Reflection; using System.Reflection;
using FluentMigrator.Runner; using FluentMigrator.Runner;
@ -37,17 +37,28 @@ namespace NzbDrone.Core.Datastore.Migration.Framework
var options = new MigrationOptions { PreviewOnly = false, Timeout = 60 }; var options = new MigrationOptions { PreviewOnly = false, Timeout = 60 };
var factory = new NzbDroneSqliteProcessorFactory(); var factory = new NzbDroneSqliteProcessorFactory();
var processor = factory.Create(connectionString, _announcer, options); var processor = factory.Create(connectionString, _announcer, options);
var runner = new MigrationRunner(assembly, runnerContext, processor);
if (migrationContext.DesiredVersion.HasValue) try
{ {
runner.MigrateUp(migrationContext.DesiredVersion.Value, true); var runner = new MigrationRunner(assembly, runnerContext, processor);
if (migrationContext.DesiredVersion.HasValue)
{
runner.MigrateUp(migrationContext.DesiredVersion.Value, true);
}
else
{
runner.MigrateUp(true);
}
} }
else catch (SQLiteException)
{ {
runner.MigrateUp(true); processor.Dispose();
SQLiteConnection.ClearAllPools();
throw;
} }
sw.Stop(); sw.Stop();
_announcer.ElapsedTime(sw.Elapsed); _announcer.ElapsedTime(sw.Elapsed);

@ -171,6 +171,7 @@
<Compile Include="Datastore\Converters\ProviderSettingConverter.cs" /> <Compile Include="Datastore\Converters\ProviderSettingConverter.cs" />
<Compile Include="Datastore\Converters\QualityIntConverter.cs" /> <Compile Include="Datastore\Converters\QualityIntConverter.cs" />
<Compile Include="Datastore\Converters\UtcConverter.cs" /> <Compile Include="Datastore\Converters\UtcConverter.cs" />
<Compile Include="Datastore\CorruptDatabaseException.cs" />
<Compile Include="Datastore\Database.cs" /> <Compile Include="Datastore\Database.cs" />
<Compile Include="Datastore\DbFactory.cs" /> <Compile Include="Datastore\DbFactory.cs" />
<Compile Include="Datastore\Events\ModelEvent.cs" /> <Compile Include="Datastore\Events\ModelEvent.cs" />

Loading…
Cancel
Save