2017-11-26 04:31:41 +00:00
using System ;
2022-01-26 00:08:27 +00:00
using System.Data.Common ;
2013-03-26 05:51:56 +00:00
using System.Data.SQLite ;
2016-07-20 01:57:36 +00:00
using NLog ;
2022-01-26 00:08:27 +00:00
using Npgsql ;
2016-07-20 01:57:36 +00:00
using NzbDrone.Common.Disk ;
using NzbDrone.Common.EnvironmentInfo ;
2019-04-14 12:09:22 +00:00
using NzbDrone.Common.Exceptions ;
2016-07-20 01:57:36 +00:00
using NzbDrone.Common.Instrumentation ;
2013-03-25 06:13:53 +00:00
using NzbDrone.Core.Datastore.Migration.Framework ;
2013-03-25 03:51:32 +00:00
2013-03-24 00:08:23 +00:00
namespace NzbDrone.Core.Datastore
{
public interface IDbFactory
{
2016-02-13 21:23:37 +00:00
IDatabase Create ( MigrationType migrationType = MigrationType . Main ) ;
IDatabase Create ( MigrationContext migrationContext ) ;
2013-03-24 00:08:23 +00:00
}
public class DbFactory : IDbFactory
{
2016-07-20 01:57:36 +00:00
private static readonly Logger Logger = NzbDroneLogger . GetLogger ( typeof ( DbFactory ) ) ;
2013-03-25 06:13:53 +00:00
private readonly IMigrationController _migrationController ;
2013-07-05 03:56:27 +00:00
private readonly IConnectionStringFactory _connectionStringFactory ;
2016-07-20 01:57:36 +00:00
private readonly IDiskProvider _diskProvider ;
2018-01-14 22:11:37 +00:00
private readonly IRestoreDatabase _restoreDatabaseService ;
2013-03-24 00:08:23 +00:00
2013-03-30 22:14:33 +00:00
static DbFactory ( )
2013-03-24 00:08:23 +00:00
{
2018-04-22 13:35:37 +00:00
InitializeEnvironment ( ) ;
2013-03-25 06:13:53 +00:00
TableMapping . Map ( ) ;
2013-03-30 22:14:33 +00:00
}
2018-04-22 13:35:37 +00:00
private static void InitializeEnvironment ( )
{
// Speed up sqlite3 initialization since we don't use the config file and can't rely on preloading.
Environment . SetEnvironmentVariable ( "No_Expand" , "true" ) ;
Environment . SetEnvironmentVariable ( "No_SQLiteXmlConfigFile" , "true" ) ;
Environment . SetEnvironmentVariable ( "No_PreLoadSQLite" , "true" ) ;
2022-06-04 20:19:50 +00:00
Environment . SetEnvironmentVariable ( "No_SQLiteFunctions" , "true" ) ;
2018-04-22 13:35:37 +00:00
}
2016-07-20 01:57:36 +00:00
public DbFactory ( IMigrationController migrationController ,
IConnectionStringFactory connectionStringFactory ,
2018-01-14 22:11:37 +00:00
IDiskProvider diskProvider ,
IRestoreDatabase restoreDatabaseService )
2013-03-30 22:14:33 +00:00
{
2013-03-25 06:13:53 +00:00
_migrationController = migrationController ;
2013-07-05 03:56:27 +00:00
_connectionStringFactory = connectionStringFactory ;
2016-07-20 01:57:36 +00:00
_diskProvider = diskProvider ;
2018-01-14 22:11:37 +00:00
_restoreDatabaseService = restoreDatabaseService ;
2013-03-25 06:13:53 +00:00
}
2013-03-24 04:56:59 +00:00
2016-02-13 21:23:37 +00:00
public IDatabase Create ( MigrationType migrationType = MigrationType . Main )
{
return Create ( new MigrationContext ( migrationType ) ) ;
}
public IDatabase Create ( MigrationContext migrationContext )
2013-03-25 06:13:53 +00:00
{
2013-07-05 03:56:27 +00:00
string connectionString ;
2020-01-03 12:49:24 +00:00
2016-02-13 21:23:37 +00:00
switch ( migrationContext . MigrationType )
2013-06-28 01:03:04 +00:00
{
case MigrationType . Main :
{
2013-07-05 03:56:27 +00:00
connectionString = _connectionStringFactory . MainDbConnectionString ;
2018-01-14 22:11:37 +00:00
CreateMain ( connectionString , migrationContext ) ;
2013-06-28 01:03:04 +00:00
break ;
}
2020-01-03 12:49:24 +00:00
2013-06-28 01:03:04 +00:00
case MigrationType . Log :
{
2013-07-05 03:56:27 +00:00
connectionString = _connectionStringFactory . LogDbConnectionString ;
2018-01-14 22:11:37 +00:00
CreateLog ( connectionString , migrationContext ) ;
2013-06-28 01:03:04 +00:00
break ;
}
2020-01-03 12:49:24 +00:00
2013-06-28 01:03:04 +00:00
default :
{
throw new ArgumentException ( "Invalid MigrationType" ) ;
}
}
2018-01-14 22:11:37 +00:00
var db = new Database ( migrationContext . MigrationType . ToString ( ) , ( ) = >
{
2022-01-26 00:08:27 +00:00
DbConnection conn ;
if ( connectionString . Contains ( ".db" ) )
{
conn = SQLiteFactory . Instance . CreateConnection ( ) ;
conn . ConnectionString = connectionString ;
}
else
{
conn = new NpgsqlConnection ( connectionString ) ;
}
2018-01-14 22:11:37 +00:00
2022-01-26 00:08:27 +00:00
conn . Open ( ) ;
2020-08-18 20:11:44 +00:00
return conn ;
2018-01-14 22:11:37 +00:00
} ) ;
return db ;
}
private void CreateMain ( string connectionString , MigrationContext migrationContext )
{
2016-07-20 01:57:36 +00:00
try
{
2018-01-14 22:11:37 +00:00
_restoreDatabaseService . Restore ( ) ;
2016-07-20 01:57:36 +00:00
_migrationController . Migrate ( connectionString , migrationContext ) ;
}
2018-01-14 22:11:37 +00:00
catch ( SQLiteException e )
2016-07-20 01:57:36 +00:00
{
var fileName = _connectionStringFactory . GetDatabasePath ( connectionString ) ;
2018-01-14 22:11:37 +00:00
if ( OsInfo . IsOsx )
2016-07-20 01:57:36 +00:00
{
2021-08-04 22:47:40 +00:00
throw new CorruptDatabaseException ( "Database file: {0} is corrupt, restore from backup if available. See: https://wiki.servarr.com/lidarr/faq#i-use-lidarr-on-a-mac-and-it-suddenly-stopped-working-what-happened" , e , fileName ) ;
2016-07-20 01:57:36 +00:00
}
2021-08-04 22:47:40 +00:00
throw new CorruptDatabaseException ( "Database file: {0} is corrupt, restore from backup if available. See: https://wiki.servarr.com/lidarr/faq#i-am-getting-an-error-database-disk-image-is-malformed" , e , fileName ) ;
2018-01-14 22:11:37 +00:00
}
2019-04-14 12:09:22 +00:00
catch ( Exception e )
{
throw new LidarrStartupException ( e , "Error creating main database" ) ;
}
2018-01-14 22:11:37 +00:00
}
2016-07-20 01:57:36 +00:00
2018-01-14 22:11:37 +00:00
private void CreateLog ( string connectionString , MigrationContext migrationContext )
{
try
{
_migrationController . Migrate ( connectionString , migrationContext ) ;
2016-07-20 01:57:36 +00:00
}
2018-01-14 22:11:37 +00:00
catch ( SQLiteException e )
{
var fileName = _connectionStringFactory . GetDatabasePath ( connectionString ) ;
2013-05-11 20:06:57 +00:00
2018-01-14 22:11:37 +00:00
Logger . Error ( e , "Logging database is corrupt, attempting to recreate it automatically" ) ;
2013-11-28 07:52:22 +00:00
2018-01-14 22:11:37 +00:00
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." ) ;
}
2013-11-28 07:11:05 +00:00
2018-01-14 22:11:37 +00:00
_migrationController . Migrate ( connectionString , migrationContext ) ;
2017-11-26 04:31:41 +00:00
}
2019-04-14 12:09:22 +00:00
catch ( Exception e )
{
throw new LidarrStartupException ( e , "Error creating log database" ) ;
}
2013-03-25 03:51:32 +00:00
}
2013-03-24 00:08:23 +00:00
}
}