You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Readarr/src/NzbDrone.Core/Datastore/DbFactory.cs

156 lines
5.6 KiB

using System;
using System.Data.SQLite;
using Marr.Data;
using Marr.Data.Reflection;
using NLog;
using NzbDrone.Common.Composition;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Instrumentation;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore
{
public interface IDbFactory
{
IDatabase Create(MigrationType migrationType = MigrationType.Main);
IDatabase Create(MigrationContext migrationContext);
}
public class DbFactory : IDbFactory
{
private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(DbFactory));
private readonly IMigrationController _migrationController;
private readonly IConnectionStringFactory _connectionStringFactory;
private readonly IDiskProvider _diskProvider;
private readonly IRestoreDatabase _restoreDatabaseService;
static DbFactory()
{
MapRepository.Instance.ReflectionStrategy = new SimpleReflectionStrategy();
TableMapping.Map();
}
public static void RegisterDatabase(IContainer container)
{
var mainDb = new MainDatabase(container.Resolve<IDbFactory>().Create());
container.Register<IMainDatabase>(mainDb);
var logDb = new LogDatabase(container.Resolve<IDbFactory>().Create(MigrationType.Log));
container.Register<ILogDatabase>(logDb);
}
public DbFactory(IMigrationController migrationController,
IConnectionStringFactory connectionStringFactory,
IDiskProvider diskProvider,
IRestoreDatabase restoreDatabaseService)
{
_migrationController = migrationController;
_connectionStringFactory = connectionStringFactory;
_diskProvider = diskProvider;
_restoreDatabaseService = restoreDatabaseService;
}
public IDatabase Create(MigrationType migrationType = MigrationType.Main)
{
return Create(new MigrationContext(migrationType));
}
public IDatabase Create(MigrationContext migrationContext)
{
string connectionString;
switch (migrationContext.MigrationType)
{
case MigrationType.Main:
{
connectionString = _connectionStringFactory.MainDbConnectionString;
CreateMain(connectionString, migrationContext);
break;
}
case MigrationType.Log:
{
connectionString = _connectionStringFactory.LogDbConnectionString;
CreateLog(connectionString, migrationContext);
break;
}
default:
{
throw new ArgumentException("Invalid MigrationType");
}
}
var db = new Database(migrationContext.MigrationType.ToString(), () =>
{
var dataMapper = new DataMapper(SQLiteFactory.Instance, connectionString)
{
SqlMode = SqlModes.Text,
};
return dataMapper;
});
if (db.Migration > 100) //Quick DB Migration Check. This should get rid of users on old DB format
{
throw new CorruptDatabaseException("Invalid DB, Please Delete and Restart Lidarr");
}
return db;
}
private void CreateMain(string connectionString, MigrationContext migrationContext)
{
try
{
_restoreDatabaseService.Restore();
_migrationController.Migrate(connectionString, migrationContext);
}
catch (SQLiteException e)
{
var fileName = _connectionStringFactory.GetDatabasePath(connectionString);
if (OsInfo.IsOsx)
{
throw new CorruptDatabaseException("Database file: {0} is corrupt, restore from backup if available. See: https://github.com/Lidarr/Lidarr/wiki/FAQ#i-use-lidarr-on-a-mac-and-it-suddenly-stopped-working-what-happened", e, fileName);
}
throw new CorruptDatabaseException("Database file: {0} is corrupt, restore from backup if available. See: https://github.com/Lidarr/Lidarr/wiki/FAQ#i-am-getting-an-error-database-disk-image-is-malformed", e, fileName);
}
}
private void CreateLog(string connectionString, MigrationContext migrationContext)
{
try
{
_migrationController.Migrate(connectionString, migrationContext);
}
catch (SQLiteException e)
{
var fileName = _connectionStringFactory.GetDatabasePath(connectionString);
Logger.Error(e, "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);
}
}
}
}