@ -4,7 +4,6 @@
using System ;
using System.Collections.Generic ;
using System.Threading ;
using Jellyfin.Extensions ;
using Microsoft.Extensions.Logging ;
using SQLitePCL.pretty ;
@ -27,9 +26,19 @@ namespace Emby.Server.Implementations.Data
/// <summary>
/// Gets or sets the path to the DB file.
/// </summary>
/// <value>Path to the DB file.</value>
protected string DbFilePath { get ; set ; }
/// <summary>
/// Gets or sets the number of write connections to create.
/// </summary>
/// <value>Path to the DB file.</value>
protected int WriteConnectionsCount { get ; set ; } = 1 ;
/// <summary>
/// Gets or sets the number of read connections to create.
/// </summary>
protected int ReadConnectionsCount { get ; set ; } = 1 ;
/// <summary>
/// Gets the logger.
/// </summary>
@ -63,7 +72,7 @@ namespace Emby.Server.Implementations.Data
/// <summary>
/// Gets the locking mode. <see href="https://www.sqlite.org/pragma.html#pragma_locking_mode" />.
/// </summary>
protected virtual string LockingMode = > " EXCLUSIVE ";
protected virtual string LockingMode = > " NORMAL ";
/// <summary>
/// Gets the journal mode. <see href="https://www.sqlite.org/pragma.html#pragma_journal_mode" />.
@ -88,7 +97,7 @@ namespace Emby.Server.Implementations.Data
/// </summary>
/// <value>The temp store mode.</value>
/// <see cref="TempStoreMode"/>
protected virtual TempStoreMode TempStore = > TempStoreMode . Default ;
protected virtual TempStoreMode TempStore = > TempStoreMode . Memory ;
/// <summary>
/// Gets the synchronous mode.
@ -101,63 +110,115 @@ namespace Emby.Server.Implementations.Data
/// Gets or sets the write lock.
/// </summary>
/// <value>The write lock.</value>
protected SemaphoreSlim WriteLock { get ; set ; } = new SemaphoreSlim ( 1 , 1 ) ;
protected ConnectionPool WriteConnections { get ; set ; }
/// <summary>
/// Gets or sets the write connection.
/// </summary>
/// <value>The write connection.</value>
protected SQLiteDatabaseConnection WriteConnection { get ; set ; }
protected ConnectionPool ReadConnections { get ; set ; }
public virtual void Initialize ( )
{
WriteConnections = new ConnectionPool ( WriteConnectionsCount , CreateWriteConnection ) ;
ReadConnections = new ConnectionPool ( ReadConnectionsCount , CreateReadConnection ) ;
}
protected ManagedConnection GetConnection ( bool readOnly = false )
{
WriteLock . Wait ( ) ;
if ( WriteConnection is not null )
if ( readOnly )
{
return new ManagedConnection ( WriteConnection , WriteLock ) ;
return ReadConnections . GetConnection ( ) ;
}
WriteConnection = SQLite3 . Open (
return WriteConnections . GetConnection ( ) ;
}
protected SQLiteDatabaseConnection CreateWriteConnection ( )
{
var writeConnection = SQLite3 . Open (
DbFilePath ,
DefaultConnectionFlags | ConnectionFlags . Create | ConnectionFlags . ReadWrite ,
null ) ;
if ( CacheSize . HasValue )
{
W riteConnection. Execute ( "PRAGMA cache_size=" + CacheSize . Value ) ;
w riteConnection. Execute ( "PRAGMA cache_size=" + CacheSize . Value ) ;
}
if ( ! string . IsNullOrWhiteSpace ( LockingMode ) )
{
W riteConnection. Execute ( "PRAGMA locking_mode=" + LockingMode ) ;
w riteConnection. Execute ( "PRAGMA locking_mode=" + LockingMode ) ;
}
if ( ! string . IsNullOrWhiteSpace ( JournalMode ) )
{
W riteConnection. Execute ( "PRAGMA journal_mode=" + JournalMode ) ;
w riteConnection. Execute ( "PRAGMA journal_mode=" + JournalMode ) ;
}
if ( JournalSizeLimit . HasValue )
{
W riteConnection. Execute ( "PRAGMA journal_size_limit=" + JournalSizeLimit . Value ) ;
w riteConnection. Execute ( "PRAGMA journal_size_limit=" + JournalSizeLimit . Value ) ;
}
if ( Synchronous . HasValue )
{
W riteConnection. Execute ( "PRAGMA synchronous=" + ( int ) Synchronous . Value ) ;
w riteConnection. Execute ( "PRAGMA synchronous=" + ( int ) Synchronous . Value ) ;
}
if ( PageSize . HasValue )
{
W riteConnection. Execute ( "PRAGMA page_size=" + PageSize . Value ) ;
w riteConnection. Execute ( "PRAGMA page_size=" + PageSize . Value ) ;
}
W riteConnection. Execute ( "PRAGMA temp_store=" + ( int ) TempStore ) ;
w riteConnection. Execute ( "PRAGMA temp_store=" + ( int ) TempStore ) ;
// Configuration and pragmas can affect VACUUM so it needs to be last.
W riteConnection. Execute ( "VACUUM" ) ;
w riteConnection. Execute ( "VACUUM" ) ;
return new ManagedConnection ( WriteConnection , WriteLock ) ;
return writeConnection ;
}
protected SQLiteDatabaseConnection CreateReadConnection ( )
{
var writeConnection = SQLite3 . Open (
DbFilePath ,
DefaultConnectionFlags | ConnectionFlags . ReadOnly ,
null ) ;
if ( CacheSize . HasValue )
{
writeConnection . Execute ( "PRAGMA cache_size=" + CacheSize . Value ) ;
}
if ( ! string . IsNullOrWhiteSpace ( LockingMode ) )
{
writeConnection . Execute ( "PRAGMA locking_mode=" + LockingMode ) ;
}
if ( ! string . IsNullOrWhiteSpace ( JournalMode ) )
{
writeConnection . Execute ( "PRAGMA journal_mode=" + JournalMode ) ;
}
if ( JournalSizeLimit . HasValue )
{
writeConnection . Execute ( "PRAGMA journal_size_limit=" + JournalSizeLimit . Value ) ;
}
if ( Synchronous . HasValue )
{
writeConnection . Execute ( "PRAGMA synchronous=" + ( int ) Synchronous . Value ) ;
}
if ( PageSize . HasValue )
{
writeConnection . Execute ( "PRAGMA page_size=" + PageSize . Value ) ;
}
writeConnection . Execute ( "PRAGMA temp_store=" + ( int ) TempStore ) ;
return writeConnection ;
}
public IStatement PrepareStatement ( ManagedConnection connection , string sql )
@ -240,22 +301,10 @@ namespace Emby.Server.Implementations.Data
if ( dispose )
{
WriteLock . Wait ( ) ;
try
{
WriteConnection ? . Dispose ( ) ;
}
finally
{
WriteLock . Release ( ) ;
}
WriteLock . Dispose ( ) ;
WriteConnections . Dispose ( ) ;
ReadConnections . Dispose ( ) ;
}
WriteConnection = null ;
WriteLock = null ;
_disposed = true ;
}
}