From b136f1408481661df7666652e75625e877873299 Mon Sep 17 00:00:00 2001 From: ferferga Date: Mon, 10 Jun 2019 11:31:38 +0200 Subject: Vacuum databases at startup --- Emby.Server.Implementations/Data/BaseSqliteRepository.cs | 1 + 1 file changed, 1 insertion(+) (limited to 'Emby.Server.Implementations/Data/BaseSqliteRepository.cs') diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index fba81306b..821c4b448 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -203,6 +203,7 @@ namespace Emby.Server.Implementations.Data { var queries = new List { + "VACUUM", "PRAGMA journal_mode=WAL", "PRAGMA page_size=4096", "PRAGMA synchronous=Normal" -- cgit v1.2.3 From cec22ad10daf7abef2f27f846e4022d5a35faccf Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 20 Feb 2019 14:26:49 +0100 Subject: Simplify db code --- .../Activity/ActivityRepository.cs | 5 +- .../Data/BaseSqliteRepository.cs | 239 ++----- .../Data/ManagedConnection.cs | 79 --- .../Data/SqliteDisplayPreferencesRepository.cs | 70 +- .../Data/SqliteExtensions.cs | 2 +- .../Data/SqliteItemRepository.cs | 733 ++++++++++----------- .../Data/SqliteUserDataRepository.cs | 76 +-- .../Data/SqliteUserRepository.cs | 96 ++- .../Security/AuthenticationRepository.cs | 216 +++--- 9 files changed, 589 insertions(+), 927 deletions(-) delete mode 100644 Emby.Server.Implementations/Data/ManagedConnection.cs (limited to 'Emby.Server.Implementations/Data/BaseSqliteRepository.cs') diff --git a/Emby.Server.Implementations/Activity/ActivityRepository.cs b/Emby.Server.Implementations/Activity/ActivityRepository.cs index aeed8b6f1..495d96977 100644 --- a/Emby.Server.Implementations/Activity/ActivityRepository.cs +++ b/Emby.Server.Implementations/Activity/ActivityRepository.cs @@ -57,7 +57,7 @@ namespace Emby.Server.Implementations.Activity } } - private void TryMigrate(ManagedConnection connection) + private void TryMigrate(SQLiteDatabaseConnection connection) { try { @@ -85,7 +85,6 @@ namespace Emby.Server.Implementations.Activity throw new ArgumentNullException(nameof(entry)); } - using (WriteLock.Write()) using (var connection = CreateConnection()) { connection.RunInTransaction(db => @@ -124,7 +123,6 @@ namespace Emby.Server.Implementations.Activity throw new ArgumentNullException(nameof(entry)); } - using (WriteLock.Write()) using (var connection = CreateConnection()) { connection.RunInTransaction(db => @@ -159,7 +157,6 @@ namespace Emby.Server.Implementations.Activity public QueryResult GetActivityLogEntries(DateTime? minDate, bool? hasUserId, int? startIndex, int? limit) { - using (WriteLock.Read()) using (var connection = CreateConnection(true)) { var commandText = BaseActivitySelectText; diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index fba81306b..29edddb3a 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading; +using System.Threading.Tasks; using Microsoft.Extensions.Logging; using SQLitePCL; using SQLitePCL.pretty; @@ -12,15 +13,12 @@ namespace Emby.Server.Implementations.Data public abstract class BaseSqliteRepository : IDisposable { protected string DbFilePath { get; set; } - protected ReaderWriterLockSlim WriteLock; protected ILogger Logger { get; private set; } protected BaseSqliteRepository(ILogger logger) { Logger = logger; - - WriteLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); } protected TransactionMode TransactionMode => TransactionMode.Deferred; @@ -31,130 +29,96 @@ namespace Emby.Server.Implementations.Data static BaseSqliteRepository() { - SQLite3.EnableSharedCache = false; - - int rc = raw.sqlite3_config(raw.SQLITE_CONFIG_MEMSTATUS, 0); - //CheckOk(rc); - - rc = raw.sqlite3_config(raw.SQLITE_CONFIG_MULTITHREAD, 1); - //rc = raw.sqlite3_config(raw.SQLITE_CONFIG_SINGLETHREAD, 1); - //rc = raw.sqlite3_config(raw.SQLITE_CONFIG_SERIALIZED, 1); - //CheckOk(rc); - - rc = raw.sqlite3_enable_shared_cache(1); - ThreadSafeMode = raw.sqlite3_threadsafe(); } private static bool _versionLogged; private string _defaultWal; - protected ManagedConnection _connection; - - protected virtual bool EnableSingleConnection => true; - protected ManagedConnection CreateConnection(bool isReadOnly = false) + protected SQLiteDatabaseConnection CreateConnection(bool isReadOnly = false) { - if (_connection != null) + if (!_versionLogged) { - return _connection; + _versionLogged = true; + Logger.LogInformation("Sqlite version: " + SQLite3.Version); + Logger.LogInformation("Sqlite compiler options: " + string.Join(",", SQLite3.CompilerOptions)); } - lock (WriteLock) + ConnectionFlags connectionFlags; + + if (isReadOnly) { - if (!_versionLogged) - { - _versionLogged = true; - Logger.LogInformation("Sqlite version: " + SQLite3.Version); - Logger.LogInformation("Sqlite compiler options: " + string.Join(",", SQLite3.CompilerOptions.ToArray())); - } + //Logger.LogInformation("Opening read connection"); + //connectionFlags = ConnectionFlags.Create; + connectionFlags = ConnectionFlags.ReadOnly; + } + else + { + //Logger.LogInformation("Opening write connection"); + connectionFlags = ConnectionFlags.Create; + connectionFlags |= ConnectionFlags.ReadWrite; + } + + connectionFlags |= ConnectionFlags.SharedCached; + connectionFlags |= ConnectionFlags.FullMutex; - ConnectionFlags connectionFlags; + var db = SQLite3.Open(DbFilePath, connectionFlags, null); - if (isReadOnly) + try + { + if (string.IsNullOrWhiteSpace(_defaultWal)) { - //Logger.LogInformation("Opening read connection"); - //connectionFlags = ConnectionFlags.ReadOnly; - connectionFlags = ConnectionFlags.Create; - connectionFlags |= ConnectionFlags.ReadWrite; + _defaultWal = db.Query("PRAGMA journal_mode").SelectScalarString().First(); + + Logger.LogInformation("Default journal_mode for {0} is {1}", DbFilePath, _defaultWal); } - else + + var queries = new List + { + //"PRAGMA cache size=-10000" + //"PRAGMA read_uncommitted = true", + //"PRAGMA synchronous=Normal" + }; + + if (CacheSize.HasValue) { - //Logger.LogInformation("Opening write connection"); - connectionFlags = ConnectionFlags.Create; - connectionFlags |= ConnectionFlags.ReadWrite; + queries.Add("PRAGMA cache_size=" + CacheSize.Value.ToString(CultureInfo.InvariantCulture)); } - if (EnableSingleConnection) + if (EnableTempStoreMemory) { - connectionFlags |= ConnectionFlags.PrivateCache; + queries.Add("PRAGMA temp_store = memory"); } else { - connectionFlags |= ConnectionFlags.SharedCached; + queries.Add("PRAGMA temp_store = file"); } - connectionFlags |= ConnectionFlags.NoMutex; - - var db = SQLite3.Open(DbFilePath, connectionFlags, null); - - try + foreach (var query in queries) { - if (string.IsNullOrWhiteSpace(_defaultWal)) - { - _defaultWal = db.Query("PRAGMA journal_mode").SelectScalarString().First(); - - Logger.LogInformation("Default journal_mode for {0} is {1}", DbFilePath, _defaultWal); - } - - var queries = new List - { - //"PRAGMA cache size=-10000" - //"PRAGMA read_uncommitted = true", - "PRAGMA synchronous=Normal" - }; - - if (CacheSize.HasValue) - { - queries.Add("PRAGMA cache_size=" + CacheSize.Value.ToString(CultureInfo.InvariantCulture)); - } - - if (EnableTempStoreMemory) - { - queries.Add("PRAGMA temp_store = memory"); - } - else - { - queries.Add("PRAGMA temp_store = file"); - } - - foreach (var query in queries) - { - db.Execute(query); - } + db.Execute(query); } - catch + } + catch + { + using (db) { - using (db) - { - } - - throw; } - _connection = new ManagedConnection(db, false); - - return _connection; + throw; } + + return db; } - public IStatement PrepareStatement(ManagedConnection connection, string sql) + public IStatement PrepareStatement(SQLiteDatabaseConnection connection, string sql) { return connection.PrepareStatement(sql); } - public IStatement PrepareStatementSafe(ManagedConnection connection, string sql) + public IStatement PrepareStatementSafe(SQLiteDatabaseConnection connection, string sql) { return connection.PrepareStatement(sql); } @@ -179,7 +143,7 @@ namespace Emby.Server.Implementations.Data return sql.Select(connection.PrepareStatement).ToList(); } - protected bool TableExists(ManagedConnection connection, string name) + protected bool TableExists(SQLiteDatabaseConnection connection, string name) { return connection.RunInTransaction(db => { @@ -199,7 +163,7 @@ namespace Emby.Server.Implementations.Data }, ReadTransactionMode); } - protected void RunDefaultInitialization(ManagedConnection db) + protected void RunDefaultInitialization(SQLiteDatabaseConnection db) { var queries = new List { @@ -243,7 +207,7 @@ namespace Emby.Server.Implementations.Data public void Dispose() { - _disposed = true; + Dispose(true); } @@ -255,42 +219,13 @@ namespace Emby.Server.Implementations.Data /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool dispose) { - if (dispose) - { - DisposeConnection(); - } - } - - private void DisposeConnection() - { - try - { - lock (_disposeLock) - { - using (WriteLock.Write()) - { - if (_connection != null) - { - using (_connection) - { - _connection.Close(); - } - _connection = null; - } - - CloseConnection(); - } - } - } - catch (Exception ex) + if (_disposed) { - Logger.LogError(ex, "Error disposing database"); + return; } - } - protected virtual void CloseConnection() - { + _disposed = true; } protected List GetColumnNames(IDatabaseConnection connection, string table) @@ -320,60 +255,4 @@ namespace Emby.Server.Implementations.Data connection.Execute("alter table " + table + " add column " + columnName + " " + type + " NULL"); } } - - public static class ReaderWriterLockSlimExtensions - { - private sealed class ReadLockToken : IDisposable - { - private ReaderWriterLockSlim _sync; - public ReadLockToken(ReaderWriterLockSlim sync) - { - _sync = sync; - sync.EnterReadLock(); - } - public void Dispose() - { - if (_sync != null) - { - _sync.ExitReadLock(); - _sync = null; - } - } - } - private sealed class WriteLockToken : IDisposable - { - private ReaderWriterLockSlim _sync; - public WriteLockToken(ReaderWriterLockSlim sync) - { - _sync = sync; - sync.EnterWriteLock(); - } - public void Dispose() - { - if (_sync != null) - { - _sync.ExitWriteLock(); - _sync = null; - } - } - } - - public static IDisposable Read(this ReaderWriterLockSlim obj) - { - //if (BaseSqliteRepository.ThreadSafeMode > 0) - //{ - // return new DummyToken(); - //} - return new WriteLockToken(obj); - } - - public static IDisposable Write(this ReaderWriterLockSlim obj) - { - //if (BaseSqliteRepository.ThreadSafeMode > 0) - //{ - // return new DummyToken(); - //} - return new WriteLockToken(obj); - } - } } diff --git a/Emby.Server.Implementations/Data/ManagedConnection.cs b/Emby.Server.Implementations/Data/ManagedConnection.cs deleted file mode 100644 index b8f1e581a..000000000 --- a/Emby.Server.Implementations/Data/ManagedConnection.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System; -using System.Collections.Generic; -using SQLitePCL.pretty; - -namespace Emby.Server.Implementations.Data -{ - public class ManagedConnection : IDisposable - { - private SQLiteDatabaseConnection db; - private readonly bool _closeOnDispose; - - public ManagedConnection(SQLiteDatabaseConnection db, bool closeOnDispose) - { - this.db = db; - _closeOnDispose = closeOnDispose; - } - - public IStatement PrepareStatement(string sql) - { - return db.PrepareStatement(sql); - } - - public IEnumerable PrepareAll(string sql) - { - return db.PrepareAll(sql); - } - - public void ExecuteAll(string sql) - { - db.ExecuteAll(sql); - } - - public void Execute(string sql, params object[] values) - { - db.Execute(sql, values); - } - - public void RunQueries(string[] sql) - { - db.RunQueries(sql); - } - - public void RunInTransaction(Action action, TransactionMode mode) - { - db.RunInTransaction(action, mode); - } - - public T RunInTransaction(Func action, TransactionMode mode) - { - return db.RunInTransaction(action, mode); - } - - public IEnumerable> Query(string sql) - { - return db.Query(sql); - } - - public IEnumerable> Query(string sql, params object[] values) - { - return db.Query(sql, values); - } - - public void Close() - { - using (db) - { - - } - } - - public void Dispose() - { - if (_closeOnDispose) - { - Close(); - } - } - } -} diff --git a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs index 47552806d..86a7c1551 100644 --- a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs @@ -98,15 +98,12 @@ namespace Emby.Server.Implementations.Data cancellationToken.ThrowIfCancellationRequested(); - using (WriteLock.Write()) + using (var connection = CreateConnection()) { - using (var connection = CreateConnection()) + connection.RunInTransaction(db => { - connection.RunInTransaction(db => - { - SaveDisplayPreferences(displayPreferences, userId, client, db); - }, TransactionMode); - } + SaveDisplayPreferences(displayPreferences, userId, client, db); + }, TransactionMode); } } @@ -142,18 +139,15 @@ namespace Emby.Server.Implementations.Data cancellationToken.ThrowIfCancellationRequested(); - using (WriteLock.Write()) + using (var connection = CreateConnection()) { - using (var connection = CreateConnection()) + connection.RunInTransaction(db => { - connection.RunInTransaction(db => + foreach (var displayPreference in displayPreferences) { - foreach (var displayPreference in displayPreferences) - { - SaveDisplayPreferences(displayPreference, userId, displayPreference.Client, db); - } - }, TransactionMode); - } + SaveDisplayPreferences(displayPreference, userId, displayPreference.Client, db); + } + }, TransactionMode); } } @@ -174,27 +168,24 @@ namespace Emby.Server.Implementations.Data var guidId = displayPreferencesId.GetMD5(); - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var connection = CreateConnection(true)) + using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where id = @id and userId=@userId and client=@client")) { - using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where id = @id and userId=@userId and client=@client")) - { - statement.TryBind("@id", guidId.ToGuidBlob()); - statement.TryBind("@userId", userId.ToGuidBlob()); - statement.TryBind("@client", client); - - foreach (var row in statement.ExecuteQuery()) - { - return Get(row); - } - } + statement.TryBind("@id", guidId.ToGuidBlob()); + statement.TryBind("@userId", userId.ToGuidBlob()); + statement.TryBind("@client", client); - return new DisplayPreferences + foreach (var row in statement.ExecuteQuery()) { - Id = guidId.ToString("N") - }; + return Get(row); + } } + + return new DisplayPreferences + { + Id = guidId.ToString("N") + }; } } @@ -208,18 +199,15 @@ namespace Emby.Server.Implementations.Data { var list = new List(); - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var connection = CreateConnection(true)) + using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where userId=@userId")) { - using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where userId=@userId")) - { - statement.TryBind("@userId", userId.ToGuidBlob()); + statement.TryBind("@userId", userId.ToGuidBlob()); - foreach (var row in statement.ExecuteQuery()) - { - list.Add(Get(row)); - } + foreach (var row in statement.ExecuteQuery()) + { + list.Add(Get(row)); } } } diff --git a/Emby.Server.Implementations/Data/SqliteExtensions.cs b/Emby.Server.Implementations/Data/SqliteExtensions.cs index a486cb1a0..c0f27b25a 100644 --- a/Emby.Server.Implementations/Data/SqliteExtensions.cs +++ b/Emby.Server.Implementations/Data/SqliteExtensions.cs @@ -141,7 +141,7 @@ namespace Emby.Server.Implementations.Data } } - public static void Attach(ManagedConnection db, string path, string alias) + public static void Attach(SQLiteDatabaseConnection db, string path, string alias) { var commandText = string.Format("attach @path as {0};", alias); diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 8841a9a50..baa5b713a 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -319,7 +319,7 @@ namespace Emby.Server.Implementations.Data connection.RunQueries(postQueries); } - userDataRepo.Initialize(WriteLock, _connection, userManager); + userDataRepo.Initialize(userManager); } private static readonly string[] _retriveItemColumns = @@ -551,21 +551,18 @@ namespace Emby.Server.Implementations.Data CheckDisposed(); - using (WriteLock.Write()) + using (var connection = CreateConnection()) { - using (var connection = CreateConnection()) + connection.RunInTransaction(db => { - connection.RunInTransaction(db => + using (var saveImagesStatement = PrepareStatement(db, "Update TypedBaseItems set Images=@Images where guid=@Id")) { - using (var saveImagesStatement = PrepareStatement(db, "Update TypedBaseItems set Images=@Images where guid=@Id")) - { - saveImagesStatement.TryBind("@Id", item.Id.ToGuidBlob()); - saveImagesStatement.TryBind("@Images", SerializeImages(item)); + saveImagesStatement.TryBind("@Id", item.Id.ToGuidBlob()); + saveImagesStatement.TryBind("@Images", SerializeImages(item)); - saveImagesStatement.MoveNext(); - } - }, TransactionMode); - } + saveImagesStatement.MoveNext(); + } + }, TransactionMode); } } @@ -605,16 +602,12 @@ namespace Emby.Server.Implementations.Data tuples.Add((item, ancestorIds, topParent, userdataKey, inheritedTags)); } - using (WriteLock.Write()) + using (var connection = CreateConnection()) { - using (var connection = CreateConnection()) + connection.RunInTransaction(db => { - connection.RunInTransaction(db => - { - SaveItemsInTranscation(db, tuples); - - }, TransactionMode); - } + SaveItemsInTranscation(db, tuples); + }, TransactionMode); } } @@ -1193,23 +1186,20 @@ namespace Emby.Server.Implementations.Data CheckDisposed(); - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var connection = CreateConnection(true)) + using (var statement = PrepareStatementSafe(connection, "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems where guid = @guid")) { - using (var statement = PrepareStatementSafe(connection, "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems where guid = @guid")) - { - statement.TryBind("@guid", id); + statement.TryBind("@guid", id); - foreach (var row in statement.ExecuteQuery()) - { - return GetItem(row, new InternalItemsQuery()); - } + foreach (var row in statement.ExecuteQuery()) + { + return GetItem(row, new InternalItemsQuery()); } - - return null; } } + + return null; } private bool TypeRequiresDeserialization(Type type) @@ -1909,24 +1899,21 @@ namespace Emby.Server.Implementations.Data { CheckDisposed(); - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var connection = CreateConnection(true)) + var list = new List(); + + using (var statement = PrepareStatementSafe(connection, "select StartPositionTicks,Name,ImagePath,ImageDateModified from " + ChaptersTableName + " where ItemId = @ItemId order by ChapterIndex asc")) { - var list = new List(); + statement.TryBind("@ItemId", item.Id); - using (var statement = PrepareStatementSafe(connection, "select StartPositionTicks,Name,ImagePath,ImageDateModified from " + ChaptersTableName + " where ItemId = @ItemId order by ChapterIndex asc")) + foreach (var row in statement.ExecuteQuery()) { - statement.TryBind("@ItemId", item.Id); - - foreach (var row in statement.ExecuteQuery()) - { - list.Add(GetChapter(row, item)); - } + list.Add(GetChapter(row, item)); } - - return list; } + + return list; } } @@ -1941,22 +1928,20 @@ namespace Emby.Server.Implementations.Data { CheckDisposed(); - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var connection = CreateConnection(true)) + using (var statement = PrepareStatementSafe(connection, "select StartPositionTicks,Name,ImagePath,ImageDateModified from " + ChaptersTableName + " where ItemId = @ItemId and ChapterIndex=@ChapterIndex")) { - using (var statement = PrepareStatementSafe(connection, "select StartPositionTicks,Name,ImagePath,ImageDateModified from " + ChaptersTableName + " where ItemId = @ItemId and ChapterIndex=@ChapterIndex")) - { - statement.TryBind("@ItemId", item.Id); - statement.TryBind("@ChapterIndex", index); + statement.TryBind("@ItemId", item.Id); + statement.TryBind("@ChapterIndex", index); - foreach (var row in statement.ExecuteQuery()) - { - return GetChapter(row, item); - } + foreach (var row in statement.ExecuteQuery()) + { + return GetChapter(row, item); } } } + return null; } @@ -2012,21 +1997,18 @@ namespace Emby.Server.Implementations.Data throw new ArgumentNullException(nameof(chapters)); } - using (WriteLock.Write()) + using (var connection = CreateConnection()) { - using (var connection = CreateConnection()) + connection.RunInTransaction(db => { - connection.RunInTransaction(db => - { - var idBlob = id.ToGuidBlob(); + var idBlob = id.ToGuidBlob(); // First delete chapters db.Execute("delete from " + ChaptersTableName + " where ItemId=@ItemId", idBlob); - InsertChapters(idBlob, chapters, db); + InsertChapters(idBlob, chapters, db); - }, TransactionMode); - } + }, TransactionMode); } } @@ -2551,29 +2533,25 @@ namespace Emby.Server.Implementations.Data commandText += " where " + string.Join(" AND ", whereClauses); } - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var connection = CreateConnection(true)) + using (var statement = PrepareStatementSafe(connection, commandText)) { - using (var statement = PrepareStatementSafe(connection, commandText)) + if (EnableJoinUserData(query)) { - if (EnableJoinUserData(query)) - { - statement.TryBind("@UserId", query.User.InternalId); - } + statement.TryBind("@UserId", query.User.InternalId); + } - BindSimilarParams(query, statement); - BindSearchParams(query, statement); + BindSimilarParams(query, statement); + BindSearchParams(query, statement); - // Running this again will bind the params - GetWhereClauses(query, statement); + // Running this again will bind the params + GetWhereClauses(query, statement); - var count = statement.ExecuteQuery().SelectScalarInt().First(); - LogQueryTime("GetCount", commandText, now); - return count; - } + var count = statement.ExecuteQuery().SelectScalarInt().First(); + LogQueryTime("GetCount", commandText, now); + return count; } - } } @@ -2624,67 +2602,64 @@ namespace Emby.Server.Implementations.Data } } - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var connection = CreateConnection(true)) - { - var list = new List(); + var list = new List(); - using (var statement = PrepareStatementSafe(connection, commandText)) + using (var statement = PrepareStatementSafe(connection, commandText)) + { + if (EnableJoinUserData(query)) { - if (EnableJoinUserData(query)) - { - statement.TryBind("@UserId", query.User.InternalId); - } + statement.TryBind("@UserId", query.User.InternalId); + } - BindSimilarParams(query, statement); - BindSearchParams(query, statement); + BindSimilarParams(query, statement); + BindSearchParams(query, statement); - // Running this again will bind the params - GetWhereClauses(query, statement); + // Running this again will bind the params + GetWhereClauses(query, statement); - var hasEpisodeAttributes = HasEpisodeAttributes(query); - var hasServiceName = HasServiceName(query); - var hasProgramAttributes = HasProgramAttributes(query); - var hasStartDate = HasStartDate(query); - var hasTrailerTypes = HasTrailerTypes(query); - var hasArtistFields = HasArtistFields(query); - var hasSeriesFields = HasSeriesFields(query); + var hasEpisodeAttributes = HasEpisodeAttributes(query); + var hasServiceName = HasServiceName(query); + var hasProgramAttributes = HasProgramAttributes(query); + var hasStartDate = HasStartDate(query); + var hasTrailerTypes = HasTrailerTypes(query); + var hasArtistFields = HasArtistFields(query); + var hasSeriesFields = HasSeriesFields(query); - foreach (var row in statement.ExecuteQuery()) + foreach (var row in statement.ExecuteQuery()) + { + var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields); + if (item != null) { - var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields); - if (item != null) - { - list.Add(item); - } + list.Add(item); } } + } - // Hack for right now since we currently don't support filtering out these duplicates within a query - if (query.EnableGroupByMetadataKey) + // Hack for right now since we currently don't support filtering out these duplicates within a query + if (query.EnableGroupByMetadataKey) + { + var limit = query.Limit ?? int.MaxValue; + limit -= 4; + var newList = new List(); + + foreach (var item in list) { - var limit = query.Limit ?? int.MaxValue; - limit -= 4; - var newList = new List(); + AddItem(newList, item); - foreach (var item in list) + if (newList.Count >= limit) { - AddItem(newList, item); - - if (newList.Count >= limit) - { - break; - } + break; } - - list = newList; } - LogQueryTime("GetItemList", commandText, now); - - return list; + list = newList; } + + LogQueryTime("GetItemList", commandText, now); + + return list; } } @@ -2845,75 +2820,72 @@ namespace Emby.Server.Implementations.Data statementTexts.Add(commandText); } - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var connection = CreateConnection(true)) + return connection.RunInTransaction(db => { - return connection.RunInTransaction(db => - { - var result = new QueryResult(); - var statements = PrepareAllSafe(db, statementTexts); + var result = new QueryResult(); + var statements = PrepareAllSafe(db, statementTexts); - if (!isReturningZeroItems) + if (!isReturningZeroItems) + { + using (var statement = statements[0]) { - using (var statement = statements[0]) + if (EnableJoinUserData(query)) { - if (EnableJoinUserData(query)) - { - statement.TryBind("@UserId", query.User.InternalId); - } + statement.TryBind("@UserId", query.User.InternalId); + } - BindSimilarParams(query, statement); - BindSearchParams(query, statement); + BindSimilarParams(query, statement); + BindSearchParams(query, statement); // Running this again will bind the params GetWhereClauses(query, statement); - var hasEpisodeAttributes = HasEpisodeAttributes(query); - var hasServiceName = HasServiceName(query); - var hasProgramAttributes = HasProgramAttributes(query); - var hasStartDate = HasStartDate(query); - var hasTrailerTypes = HasTrailerTypes(query); - var hasArtistFields = HasArtistFields(query); - var hasSeriesFields = HasSeriesFields(query); + var hasEpisodeAttributes = HasEpisodeAttributes(query); + var hasServiceName = HasServiceName(query); + var hasProgramAttributes = HasProgramAttributes(query); + var hasStartDate = HasStartDate(query); + var hasTrailerTypes = HasTrailerTypes(query); + var hasArtistFields = HasArtistFields(query); + var hasSeriesFields = HasSeriesFields(query); - foreach (var row in statement.ExecuteQuery()) + foreach (var row in statement.ExecuteQuery()) + { + var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields); + if (item != null) { - var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields); - if (item != null) - { - list.Add(item); - } + list.Add(item); } } } + } - if (query.EnableTotalRecordCount) + if (query.EnableTotalRecordCount) + { + using (var statement = statements[statements.Count - 1]) { - using (var statement = statements[statements.Count - 1]) + if (EnableJoinUserData(query)) { - if (EnableJoinUserData(query)) - { - statement.TryBind("@UserId", query.User.InternalId); - } + statement.TryBind("@UserId", query.User.InternalId); + } - BindSimilarParams(query, statement); - BindSearchParams(query, statement); + BindSimilarParams(query, statement); + BindSearchParams(query, statement); // Running this again will bind the params GetWhereClauses(query, statement); - result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First(); - } + result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First(); } + } - LogQueryTime("GetItems", commandText, now); + LogQueryTime("GetItems", commandText, now); - result.Items = list.ToArray(); - return result; + result.Items = list.ToArray(); + return result; - }, ReadTransactionMode); - } + }, ReadTransactionMode); } } @@ -3080,35 +3052,32 @@ namespace Emby.Server.Implementations.Data } } - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var connection = CreateConnection(true)) - { - var list = new List(); + var list = new List(); - using (var statement = PrepareStatementSafe(connection, commandText)) + using (var statement = PrepareStatementSafe(connection, commandText)) + { + if (EnableJoinUserData(query)) { - if (EnableJoinUserData(query)) - { - statement.TryBind("@UserId", query.User.InternalId); - } + statement.TryBind("@UserId", query.User.InternalId); + } - BindSimilarParams(query, statement); - BindSearchParams(query, statement); + BindSimilarParams(query, statement); + BindSearchParams(query, statement); - // Running this again will bind the params - GetWhereClauses(query, statement); + // Running this again will bind the params + GetWhereClauses(query, statement); - foreach (var row in statement.ExecuteQuery()) - { - list.Add(row[0].ReadGuidFromBlob()); - } + foreach (var row in statement.ExecuteQuery()) + { + list.Add(row[0].ReadGuidFromBlob()); } + } - LogQueryTime("GetItemList", commandText, now); + LogQueryTime("GetItemList", commandText, now); - return list; - } + return list; } } @@ -3149,39 +3118,36 @@ namespace Emby.Server.Implementations.Data } } - using (WriteLock.Read()) + var list = new List>(); + using (var connection = CreateConnection(true)) { - var list = new List>(); - using (var connection = CreateConnection(true)) + using (var statement = PrepareStatementSafe(connection, commandText)) { - using (var statement = PrepareStatementSafe(connection, commandText)) + if (EnableJoinUserData(query)) { - if (EnableJoinUserData(query)) - { - statement.TryBind("@UserId", query.User.InternalId); - } + statement.TryBind("@UserId", query.User.InternalId); + } - // Running this again will bind the params - GetWhereClauses(query, statement); + // Running this again will bind the params + GetWhereClauses(query, statement); - foreach (var row in statement.ExecuteQuery()) - { - var id = row.GetGuid(0); - string path = null; + foreach (var row in statement.ExecuteQuery()) + { + var id = row.GetGuid(0); + string path = null; - if (!row.IsDBNull(1)) - { - path = row.GetString(1); - } - list.Add(new Tuple(id, path)); + if (!row.IsDBNull(1)) + { + path = row.GetString(1); } + list.Add(new Tuple(id, path)); } } + } - LogQueryTime("GetItemIdsWithPath", commandText, now); + LogQueryTime("GetItemIdsWithPath", commandText, now); - return list; - } + return list; } public QueryResult GetItemIds(InternalItemsQuery query) @@ -3265,64 +3231,61 @@ namespace Emby.Server.Implementations.Data statementTexts.Add(commandText); } - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var connection = CreateConnection(true)) + return connection.RunInTransaction(db => { - return connection.RunInTransaction(db => - { - var result = new QueryResult(); + var result = new QueryResult(); - var statements = PrepareAllSafe(db, statementTexts); + var statements = PrepareAllSafe(db, statementTexts); - if (!isReturningZeroItems) + if (!isReturningZeroItems) + { + using (var statement = statements[0]) { - using (var statement = statements[0]) + if (EnableJoinUserData(query)) { - if (EnableJoinUserData(query)) - { - statement.TryBind("@UserId", query.User.InternalId); - } + statement.TryBind("@UserId", query.User.InternalId); + } - BindSimilarParams(query, statement); - BindSearchParams(query, statement); + BindSimilarParams(query, statement); + BindSearchParams(query, statement); // Running this again will bind the params GetWhereClauses(query, statement); - foreach (var row in statement.ExecuteQuery()) - { - list.Add(row[0].ReadGuidFromBlob()); - } + foreach (var row in statement.ExecuteQuery()) + { + list.Add(row[0].ReadGuidFromBlob()); } } + } - if (query.EnableTotalRecordCount) + if (query.EnableTotalRecordCount) + { + using (var statement = statements[statements.Count - 1]) { - using (var statement = statements[statements.Count - 1]) + if (EnableJoinUserData(query)) { - if (EnableJoinUserData(query)) - { - statement.TryBind("@UserId", query.User.InternalId); - } + statement.TryBind("@UserId", query.User.InternalId); + } - BindSimilarParams(query, statement); - BindSearchParams(query, statement); + BindSimilarParams(query, statement); + BindSearchParams(query, statement); // Running this again will bind the params GetWhereClauses(query, statement); - result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First(); - } + result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First(); } + } - LogQueryTime("GetItemIds", commandText, now); + LogQueryTime("GetItemIds", commandText, now); - result.Items = list.ToArray(); - return result; + result.Items = list.ToArray(); + return result; - }, ReadTransactionMode); - } + }, ReadTransactionMode); } } @@ -4899,14 +4862,12 @@ namespace Emby.Server.Implementations.Data private void UpdateInheritedTags(CancellationToken cancellationToken) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { - using (var connection = CreateConnection()) + connection.RunInTransaction(db => { - connection.RunInTransaction(db => + connection.ExecuteAll(string.Join(";", new string[] { - connection.ExecuteAll(string.Join(";", new string[] - { "delete from itemvalues where type = 6", "insert into itemvalues (ItemId, Type, Value, CleanValue) select ItemId, 6, Value, CleanValue from ItemValues where Type=4", @@ -4916,10 +4877,9 @@ FROM AncestorIds LEFT JOIN ItemValues ON (AncestorIds.AncestorId = ItemValues.ItemId) where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type = 4 " - })); + })); - }, TransactionMode); - } + }, TransactionMode); } } @@ -4965,13 +4925,11 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type CheckDisposed(); - using (WriteLock.Write()) + using (var connection = CreateConnection()) { - using (var connection = CreateConnection()) + connection.RunInTransaction(db => { - connection.RunInTransaction(db => - { - var idBlob = id.ToGuidBlob(); + var idBlob = id.ToGuidBlob(); // Delete people ExecuteWithSingleParam(db, "delete from People where ItemId=@Id", idBlob); @@ -4990,8 +4948,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type // Delete the item ExecuteWithSingleParam(db, "delete from TypedBaseItems where guid=@Id", idBlob); - }, TransactionMode); - } + }, TransactionMode); } } @@ -5025,23 +4982,20 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type commandText += " order by ListOrder"; - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var connection = CreateConnection(true)) + var list = new List(); + using (var statement = PrepareStatementSafe(connection, commandText)) { - var list = new List(); - using (var statement = PrepareStatementSafe(connection, commandText)) - { - // Run this again to bind the params - GetPeopleWhereClauses(query, statement); + // Run this again to bind the params + GetPeopleWhereClauses(query, statement); - foreach (var row in statement.ExecuteQuery()) - { - list.Add(row.GetString(0)); - } + foreach (var row in statement.ExecuteQuery()) + { + list.Add(row.GetString(0)); } - return list; } + return list; } } @@ -5065,25 +5019,22 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type commandText += " order by ListOrder"; - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var connection = CreateConnection(true)) + var list = new List(); + + using (var statement = PrepareStatementSafe(connection, commandText)) { - var list = new List(); + // Run this again to bind the params + GetPeopleWhereClauses(query, statement); - using (var statement = PrepareStatementSafe(connection, commandText)) + foreach (var row in statement.ExecuteQuery()) { - // Run this again to bind the params - GetPeopleWhereClauses(query, statement); - - foreach (var row in statement.ExecuteQuery()) - { - list.Add(GetPerson(row)); - } + list.Add(GetPerson(row)); } - - return list; } + + return list; } } @@ -5294,27 +5245,24 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type commandText += " Group By CleanValue"; - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var connection = CreateConnection(true)) - { - var list = new List(); + var list = new List(); - using (var statement = PrepareStatementSafe(connection, commandText)) + using (var statement = PrepareStatementSafe(connection, commandText)) + { + foreach (var row in statement.ExecuteQuery()) { - foreach (var row in statement.ExecuteQuery()) + if (!row.IsDBNull(0)) { - if (!row.IsDBNull(0)) - { - list.Add(row.GetString(0)); - } + list.Add(row.GetString(0)); } } + } - LogQueryTime("GetItemValueNames", commandText, now); + LogQueryTime("GetItemValueNames", commandText, now); - return list; - } + return list; } } @@ -5483,100 +5431,97 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type statementTexts.Add(countText); } - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var connection = CreateConnection(true)) + return connection.RunInTransaction(db => { - return connection.RunInTransaction(db => - { - var list = new List<(BaseItem, ItemCounts)>(); - var result = new QueryResult<(BaseItem, ItemCounts)>(); + var list = new List<(BaseItem, ItemCounts)>(); + var result = new QueryResult<(BaseItem, ItemCounts)>(); - var statements = PrepareAllSafe(db, statementTexts); + var statements = PrepareAllSafe(db, statementTexts); - if (!isReturningZeroItems) + if (!isReturningZeroItems) + { + using (var statement = statements[0]) { - using (var statement = statements[0]) + statement.TryBind("@SelectType", returnType); + if (EnableJoinUserData(query)) { - statement.TryBind("@SelectType", returnType); - if (EnableJoinUserData(query)) - { - statement.TryBind("@UserId", query.User.InternalId); - } + statement.TryBind("@UserId", query.User.InternalId); + } - if (typeSubQuery != null) - { - GetWhereClauses(typeSubQuery, null); - } - BindSimilarParams(query, statement); - BindSearchParams(query, statement); - GetWhereClauses(innerQuery, statement); - GetWhereClauses(outerQuery, statement); - - var hasEpisodeAttributes = HasEpisodeAttributes(query); - var hasProgramAttributes = HasProgramAttributes(query); - var hasServiceName = HasServiceName(query); - var hasStartDate = HasStartDate(query); - var hasTrailerTypes = HasTrailerTypes(query); - var hasArtistFields = HasArtistFields(query); - var hasSeriesFields = HasSeriesFields(query); - - foreach (var row in statement.ExecuteQuery()) + if (typeSubQuery != null) + { + GetWhereClauses(typeSubQuery, null); + } + BindSimilarParams(query, statement); + BindSearchParams(query, statement); + GetWhereClauses(innerQuery, statement); + GetWhereClauses(outerQuery, statement); + + var hasEpisodeAttributes = HasEpisodeAttributes(query); + var hasProgramAttributes = HasProgramAttributes(query); + var hasServiceName = HasServiceName(query); + var hasStartDate = HasStartDate(query); + var hasTrailerTypes = HasTrailerTypes(query); + var hasArtistFields = HasArtistFields(query); + var hasSeriesFields = HasSeriesFields(query); + + foreach (var row in statement.ExecuteQuery()) + { + var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields); + if (item != null) { - var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields); - if (item != null) - { - var countStartColumn = columns.Count - 1; + var countStartColumn = columns.Count - 1; - list.Add((item, GetItemCounts(row, countStartColumn, typesToCount))); - } + list.Add((item, GetItemCounts(row, countStartColumn, typesToCount))); } - - LogQueryTime("GetItemValues", commandText, now); } + + LogQueryTime("GetItemValues", commandText, now); } + } - if (query.EnableTotalRecordCount) - { - commandText = "select " - + string.Join(",", GetFinalColumnsToSelect(query, new[] { "count (distinct PresentationUniqueKey)" })) - + GetFromText() - + GetJoinUserDataText(query) - + whereText; + if (query.EnableTotalRecordCount) + { + commandText = "select " + + string.Join(",", GetFinalColumnsToSelect(query, new[] { "count (distinct PresentationUniqueKey)" })) + + GetFromText() + + GetJoinUserDataText(query) + + whereText; - using (var statement = statements[statements.Count - 1]) + using (var statement = statements[statements.Count - 1]) + { + statement.TryBind("@SelectType", returnType); + if (EnableJoinUserData(query)) { - statement.TryBind("@SelectType", returnType); - if (EnableJoinUserData(query)) - { - statement.TryBind("@UserId", query.User.InternalId); - } + statement.TryBind("@UserId", query.User.InternalId); + } - if (typeSubQuery != null) - { - GetWhereClauses(typeSubQuery, null); - } - BindSimilarParams(query, statement); - BindSearchParams(query, statement); - GetWhereClauses(innerQuery, statement); - GetWhereClauses(outerQuery, statement); + if (typeSubQuery != null) + { + GetWhereClauses(typeSubQuery, null); + } + BindSimilarParams(query, statement); + BindSearchParams(query, statement); + GetWhereClauses(innerQuery, statement); + GetWhereClauses(outerQuery, statement); - result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First(); + result.TotalRecordCount = statement.ExecuteQuery().SelectScalarInt().First(); - LogQueryTime("GetItemValues", commandText, now); - } + LogQueryTime("GetItemValues", commandText, now); } + } - if (result.TotalRecordCount == 0) - { - result.TotalRecordCount = list.Count; - } - result.Items = list.ToArray(); + if (result.TotalRecordCount == 0) + { + result.TotalRecordCount = list.Count; + } + result.Items = list.ToArray(); - return result; + return result; - }, ReadTransactionMode); - } + }, ReadTransactionMode); } } @@ -5753,22 +5698,18 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type CheckDisposed(); - using (WriteLock.Write()) + using (var connection = CreateConnection()) { - using (var connection = CreateConnection()) + connection.RunInTransaction(db => { - connection.RunInTransaction(db => - { - var itemIdBlob = itemId.ToGuidBlob(); + var itemIdBlob = itemId.ToGuidBlob(); // First delete chapters db.Execute("delete from People where ItemId=@ItemId", itemIdBlob); - InsertPeople(itemIdBlob, people, db); - - }, TransactionMode); + InsertPeople(itemIdBlob, people, db); - } + }, TransactionMode); } } @@ -5874,34 +5815,31 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type cmdText += " order by StreamIndex ASC"; - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var connection = CreateConnection(true)) + var list = new List(); + + using (var statement = PrepareStatementSafe(connection, cmdText)) { - var list = new List(); + statement.TryBind("@ItemId", query.ItemId.ToGuidBlob()); - using (var statement = PrepareStatementSafe(connection, cmdText)) + if (query.Type.HasValue) { - statement.TryBind("@ItemId", query.ItemId.ToGuidBlob()); - - if (query.Type.HasValue) - { - statement.TryBind("@StreamType", query.Type.Value.ToString()); - } - - if (query.Index.HasValue) - { - statement.TryBind("@StreamIndex", query.Index.Value); - } + statement.TryBind("@StreamType", query.Type.Value.ToString()); + } - foreach (var row in statement.ExecuteQuery()) - { - list.Add(GetMediaStream(row)); - } + if (query.Index.HasValue) + { + statement.TryBind("@StreamIndex", query.Index.Value); } - return list; + foreach (var row in statement.ExecuteQuery()) + { + list.Add(GetMediaStream(row)); + } } + + return list; } } @@ -5921,21 +5859,18 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type cancellationToken.ThrowIfCancellationRequested(); - using (WriteLock.Write()) + using (var connection = CreateConnection()) { - using (var connection = CreateConnection()) + connection.RunInTransaction(db => { - connection.RunInTransaction(db => - { - var itemIdBlob = id.ToGuidBlob(); + var itemIdBlob = id.ToGuidBlob(); // First delete chapters db.Execute("delete from mediastreams where ItemId=@ItemId", itemIdBlob); - InsertMediaStreams(itemIdBlob, streams, db); + InsertMediaStreams(itemIdBlob, streams, db); - }, TransactionMode); - } + }, TransactionMode); } } diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs index 4109b7ad1..f544dfac4 100644 --- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs @@ -7,7 +7,6 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Persistence; -using MediaBrowser.Model.IO; using Microsoft.Extensions.Logging; using SQLitePCL.pretty; @@ -33,13 +32,8 @@ namespace Emby.Server.Implementations.Data /// Opens the connection to the database /// /// Task. - public void Initialize(ReaderWriterLockSlim writeLock, ManagedConnection managedConnection, IUserManager userManager) + public void Initialize(IUserManager userManager) { - _connection = managedConnection; - - WriteLock.Dispose(); - WriteLock = writeLock; - using (var connection = CreateConnection()) { var userDatasTableExists = TableExists(connection, "UserDatas"); @@ -178,15 +172,12 @@ namespace Emby.Server.Implementations.Data { cancellationToken.ThrowIfCancellationRequested(); - using (WriteLock.Write()) + using (var connection = CreateConnection()) { - using (var connection = CreateConnection()) + connection.RunInTransaction(db => { - connection.RunInTransaction(db => - { - SaveUserData(db, internalUserId, key, userData); - }, TransactionMode); - } + SaveUserData(db, internalUserId, key, userData); + }, TransactionMode); } } @@ -249,18 +240,15 @@ namespace Emby.Server.Implementations.Data { cancellationToken.ThrowIfCancellationRequested(); - using (WriteLock.Write()) + using (var connection = CreateConnection()) { - using (var connection = CreateConnection()) + connection.RunInTransaction(db => { - connection.RunInTransaction(db => + foreach (var userItemData in userDataList) { - foreach (var userItemData in userDataList) - { - SaveUserData(db, internalUserId, userItemData.Key, userItemData); - } - }, TransactionMode); - } + SaveUserData(db, internalUserId, userItemData.Key, userItemData); + } + }, TransactionMode); } } @@ -281,28 +269,26 @@ namespace Emby.Server.Implementations.Data { throw new ArgumentNullException(nameof(internalUserId)); } + if (string.IsNullOrEmpty(key)) { throw new ArgumentNullException(nameof(key)); } - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var connection = CreateConnection(true)) + using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from UserDatas where key =@Key and userId=@UserId")) { - using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from UserDatas where key =@Key and userId=@UserId")) - { - statement.TryBind("@UserId", internalUserId); - statement.TryBind("@Key", key); + statement.TryBind("@UserId", internalUserId); + statement.TryBind("@Key", key); - foreach (var row in statement.ExecuteQuery()) - { - return ReadRow(row); - } + foreach (var row in statement.ExecuteQuery()) + { + return ReadRow(row); } - - return null; } + + return null; } } @@ -335,18 +321,15 @@ namespace Emby.Server.Implementations.Data var list = new List(); - using (WriteLock.Read()) + using (var connection = CreateConnection()) { - using (var connection = CreateConnection()) + using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from UserDatas where userId=@UserId")) { - using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from UserDatas where userId=@UserId")) - { - statement.TryBind("@UserId", internalUserId); + statement.TryBind("@UserId", internalUserId); - foreach (var row in statement.ExecuteQuery()) - { - list.Add(ReadRow(row)); - } + foreach (var row in statement.ExecuteQuery()) + { + list.Add(ReadRow(row)); } } } @@ -397,10 +380,5 @@ namespace Emby.Server.Implementations.Data { // handled by library database } - - protected override void CloseConnection() - { - // handled by library database - } } } diff --git a/Emby.Server.Implementations/Data/SqliteUserRepository.cs b/Emby.Server.Implementations/Data/SqliteUserRepository.cs index 5957b2903..785452ad3 100644 --- a/Emby.Server.Implementations/Data/SqliteUserRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserRepository.cs @@ -60,7 +60,7 @@ namespace Emby.Server.Implementations.Data } } - private void TryMigrateToLocalUsersTable(ManagedConnection connection) + private void TryMigrateToLocalUsersTable(SQLiteDatabaseConnection connection) { try { @@ -119,31 +119,28 @@ namespace Emby.Server.Implementations.Data var serialized = _jsonSerializer.SerializeToBytes(user); - using (WriteLock.Write()) + using (var connection = CreateConnection()) { - using (var connection = CreateConnection()) + connection.RunInTransaction(db => { - connection.RunInTransaction(db => + using (var statement = db.PrepareStatement("insert into LocalUsersv2 (guid, data) values (@guid, @data)")) { - using (var statement = db.PrepareStatement("insert into LocalUsersv2 (guid, data) values (@guid, @data)")) - { - statement.TryBind("@guid", user.Id.ToGuidBlob()); - statement.TryBind("@data", serialized); + statement.TryBind("@guid", user.Id.ToGuidBlob()); + statement.TryBind("@data", serialized); - statement.MoveNext(); - } + statement.MoveNext(); + } - var createdUser = GetUser(user.Id, false); + var createdUser = GetUser(user.Id, connection); - if (createdUser == null) - { - throw new ApplicationException("created user should never be null"); - } + if (createdUser == null) + { + throw new ApplicationException("created user should never be null"); + } - user.InternalId = createdUser.InternalId; + user.InternalId = createdUser.InternalId; - }, TransactionMode); - } + }, TransactionMode); } } @@ -156,39 +153,30 @@ namespace Emby.Server.Implementations.Data var serialized = _jsonSerializer.SerializeToBytes(user); - using (WriteLock.Write()) + using (var connection = CreateConnection()) { - using (var connection = CreateConnection()) + connection.RunInTransaction(db => { - connection.RunInTransaction(db => + using (var statement = db.PrepareStatement("update LocalUsersv2 set data=@data where Id=@InternalId")) { - using (var statement = db.PrepareStatement("update LocalUsersv2 set data=@data where Id=@InternalId")) - { - statement.TryBind("@InternalId", user.InternalId); - statement.TryBind("@data", serialized); - statement.MoveNext(); - } + statement.TryBind("@InternalId", user.InternalId); + statement.TryBind("@data", serialized); + statement.MoveNext(); + } - }, TransactionMode); - } + }, TransactionMode); } } - private User GetUser(Guid guid, bool openLock) + private User GetUser(Guid guid, SQLiteDatabaseConnection connection) { - using (openLock ? WriteLock.Read() : null) + using (var statement = connection.PrepareStatement("select id,guid,data from LocalUsersv2 where guid=@guid")) { - using (var connection = CreateConnection(true)) - { - using (var statement = connection.PrepareStatement("select id,guid,data from LocalUsersv2 where guid=@guid")) - { - statement.TryBind("@guid", guid); + statement.TryBind("@guid", guid); - foreach (var row in statement.ExecuteQuery()) - { - return GetUser(row); - } - } + foreach (var row in statement.ExecuteQuery()) + { + return GetUser(row); } } @@ -218,14 +206,11 @@ namespace Emby.Server.Implementations.Data { var list = new List(); - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var connection = CreateConnection(true)) + foreach (var row in connection.Query("select id,guid,data from LocalUsersv2")) { - foreach (var row in connection.Query("select id,guid,data from LocalUsersv2")) - { - list.Add(GetUser(row)); - } + list.Add(GetUser(row)); } } @@ -245,19 +230,16 @@ namespace Emby.Server.Implementations.Data throw new ArgumentNullException(nameof(user)); } - using (WriteLock.Write()) + using (var connection = CreateConnection()) { - using (var connection = CreateConnection()) + connection.RunInTransaction(db => { - connection.RunInTransaction(db => + using (var statement = db.PrepareStatement("delete from LocalUsersv2 where Id=@id")) { - using (var statement = db.PrepareStatement("delete from LocalUsersv2 where Id=@id")) - { - statement.TryBind("@id", user.InternalId); - statement.MoveNext(); - } - }, TransactionMode); - } + statement.TryBind("@id", user.InternalId); + statement.MoveNext(); + } + }, TransactionMode); } } } diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs index 29b8dfd3d..abc23239e 100644 --- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs +++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs @@ -48,7 +48,7 @@ namespace Emby.Server.Implementations.Security } } - private void TryMigrate(ManagedConnection connection, bool tableNewlyCreated) + private void TryMigrate(SQLiteDatabaseConnection connection, bool tableNewlyCreated) { try { @@ -87,31 +87,28 @@ namespace Emby.Server.Implementations.Security throw new ArgumentNullException(nameof(info)); } - using (WriteLock.Write()) + using (var connection = CreateConnection()) { - using (var connection = CreateConnection()) + connection.RunInTransaction(db => { - connection.RunInTransaction(db => + using (var statement = db.PrepareStatement("insert into Tokens (AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, UserName, IsActive, DateCreated, DateLastActivity) values (@AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @UserName, @IsActive, @DateCreated, @DateLastActivity)")) { - using (var statement = db.PrepareStatement("insert into Tokens (AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, UserName, IsActive, DateCreated, DateLastActivity) values (@AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @UserName, @IsActive, @DateCreated, @DateLastActivity)")) - { - statement.TryBind("@AccessToken", info.AccessToken); - - statement.TryBind("@DeviceId", info.DeviceId); - statement.TryBind("@AppName", info.AppName); - statement.TryBind("@AppVersion", info.AppVersion); - statement.TryBind("@DeviceName", info.DeviceName); - statement.TryBind("@UserId", (info.UserId.Equals(Guid.Empty) ? null : info.UserId.ToString("N"))); - statement.TryBind("@UserName", info.UserName); - statement.TryBind("@IsActive", true); - statement.TryBind("@DateCreated", info.DateCreated.ToDateTimeParamValue()); - statement.TryBind("@DateLastActivity", info.DateLastActivity.ToDateTimeParamValue()); - - statement.MoveNext(); - } - - }, TransactionMode); - } + statement.TryBind("@AccessToken", info.AccessToken); + + statement.TryBind("@DeviceId", info.DeviceId); + statement.TryBind("@AppName", info.AppName); + statement.TryBind("@AppVersion", info.AppVersion); + statement.TryBind("@DeviceName", info.DeviceName); + statement.TryBind("@UserId", (info.UserId.Equals(Guid.Empty) ? null : info.UserId.ToString("N"))); + statement.TryBind("@UserName", info.UserName); + statement.TryBind("@IsActive", true); + statement.TryBind("@DateCreated", info.DateCreated.ToDateTimeParamValue()); + statement.TryBind("@DateLastActivity", info.DateLastActivity.ToDateTimeParamValue()); + + statement.MoveNext(); + } + + }, TransactionMode); } } @@ -122,31 +119,28 @@ namespace Emby.Server.Implementations.Security throw new ArgumentNullException(nameof(info)); } - using (WriteLock.Write()) + using (var connection = CreateConnection()) { - using (var connection = CreateConnection()) + connection.RunInTransaction(db => { - connection.RunInTransaction(db => + using (var statement = db.PrepareStatement("Update Tokens set AccessToken=@AccessToken, DeviceId=@DeviceId, AppName=@AppName, AppVersion=@AppVersion, DeviceName=@DeviceName, UserId=@UserId, UserName=@UserName, DateCreated=@DateCreated, DateLastActivity=@DateLastActivity where Id=@Id")) { - using (var statement = db.PrepareStatement("Update Tokens set AccessToken=@AccessToken, DeviceId=@DeviceId, AppName=@AppName, AppVersion=@AppVersion, DeviceName=@DeviceName, UserId=@UserId, UserName=@UserName, DateCreated=@DateCreated, DateLastActivity=@DateLastActivity where Id=@Id")) - { - statement.TryBind("@Id", info.Id); - - statement.TryBind("@AccessToken", info.AccessToken); - - statement.TryBind("@DeviceId", info.DeviceId); - statement.TryBind("@AppName", info.AppName); - statement.TryBind("@AppVersion", info.AppVersion); - statement.TryBind("@DeviceName", info.DeviceName); - statement.TryBind("@UserId", (info.UserId.Equals(Guid.Empty) ? null : info.UserId.ToString("N"))); - statement.TryBind("@UserName", info.UserName); - statement.TryBind("@DateCreated", info.DateCreated.ToDateTimeParamValue()); - statement.TryBind("@DateLastActivity", info.DateLastActivity.ToDateTimeParamValue()); - - statement.MoveNext(); - } - }, TransactionMode); - } + statement.TryBind("@Id", info.Id); + + statement.TryBind("@AccessToken", info.AccessToken); + + statement.TryBind("@DeviceId", info.DeviceId); + statement.TryBind("@AppName", info.AppName); + statement.TryBind("@AppVersion", info.AppVersion); + statement.TryBind("@DeviceName", info.DeviceName); + statement.TryBind("@UserId", (info.UserId.Equals(Guid.Empty) ? null : info.UserId.ToString("N"))); + statement.TryBind("@UserName", info.UserName); + statement.TryBind("@DateCreated", info.DateCreated.ToDateTimeParamValue()); + statement.TryBind("@DateLastActivity", info.DateLastActivity.ToDateTimeParamValue()); + + statement.MoveNext(); + } + }, TransactionMode); } } @@ -157,20 +151,17 @@ namespace Emby.Server.Implementations.Security throw new ArgumentNullException(nameof(info)); } - using (WriteLock.Write()) + using (var connection = CreateConnection()) { - using (var connection = CreateConnection()) + connection.RunInTransaction(db => { - connection.RunInTransaction(db => + using (var statement = db.PrepareStatement("Delete from Tokens where Id=@Id")) { - using (var statement = db.PrepareStatement("Delete from Tokens where Id=@Id")) - { - statement.TryBind("@Id", info.Id); + statement.TryBind("@Id", info.Id); - statement.MoveNext(); - } - }, TransactionMode); - } + statement.MoveNext(); + } + }, TransactionMode); } } @@ -257,45 +248,42 @@ namespace Emby.Server.Implementations.Security var list = new List(); - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var connection = CreateConnection(true)) + return connection.RunInTransaction(db => { - return connection.RunInTransaction(db => - { - var result = new QueryResult(); + var result = new QueryResult(); - var statementTexts = new List(); - statementTexts.Add(commandText); - statementTexts.Add("select count (Id) from Tokens" + whereTextWithoutPaging); + var statementTexts = new List(); + statementTexts.Add(commandText); + statementTexts.Add("select count (Id) from Tokens" + whereTextWithoutPaging); - var statements = PrepareAllSafe(db, statementTexts) - .ToList(); + var statements = PrepareAllSafe(db, statementTexts) + .ToList(); - using (var statement = statements[0]) - { - BindAuthenticationQueryParams(query, statement); + using (var statement = statements[0]) + { + BindAuthenticationQueryParams(query, statement); - foreach (var row in statement.ExecuteQuery()) - { - list.Add(Get(row)); - } + foreach (var row in statement.ExecuteQuery()) + { + list.Add(Get(row)); + } - using (var totalCountStatement = statements[1]) - { - BindAuthenticationQueryParams(query, totalCountStatement); + using (var totalCountStatement = statements[1]) + { + BindAuthenticationQueryParams(query, totalCountStatement); - result.TotalRecordCount = totalCountStatement.ExecuteQuery() - .SelectScalarInt() - .First(); - } + result.TotalRecordCount = totalCountStatement.ExecuteQuery() + .SelectScalarInt() + .First(); } + } - result.Items = list.ToArray(); - return result; + result.Items = list.ToArray(); + return result; - }, ReadTransactionMode); - } + }, ReadTransactionMode); } } @@ -358,31 +346,28 @@ namespace Emby.Server.Implementations.Security public DeviceOptions GetDeviceOptions(string deviceId) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var connection = CreateConnection(true)) + return connection.RunInTransaction(db => { - return connection.RunInTransaction(db => + using (var statement = PrepareStatementSafe(db, "select CustomName from Devices where Id=@DeviceId")) { - using (var statement = PrepareStatementSafe(db, "select CustomName from Devices where Id=@DeviceId")) - { - statement.TryBind("@DeviceId", deviceId); + statement.TryBind("@DeviceId", deviceId); - var result = new DeviceOptions(); + var result = new DeviceOptions(); - foreach (var row in statement.ExecuteQuery()) + foreach (var row in statement.ExecuteQuery()) + { + if (row[0].SQLiteType != SQLiteType.Null) { - if (row[0].SQLiteType != SQLiteType.Null) - { - result.CustomName = row[0].ToString(); - } + result.CustomName = row[0].ToString(); } - - return result; } - }, ReadTransactionMode); - } + return result; + } + + }, ReadTransactionMode); } } @@ -393,30 +378,27 @@ namespace Emby.Server.Implementations.Security throw new ArgumentNullException(nameof(options)); } - using (WriteLock.Write()) + using (var connection = CreateConnection()) { - using (var connection = CreateConnection()) + connection.RunInTransaction(db => { - connection.RunInTransaction(db => + using (var statement = db.PrepareStatement("replace into devices (Id, CustomName, Capabilities) VALUES (@Id, @CustomName, (Select Capabilities from Devices where Id=@Id))")) { - using (var statement = db.PrepareStatement("replace into devices (Id, CustomName, Capabilities) VALUES (@Id, @CustomName, (Select Capabilities from Devices where Id=@Id))")) - { - statement.TryBind("@Id", deviceId); - - if (string.IsNullOrWhiteSpace(options.CustomName)) - { - statement.TryBindNull("@CustomName"); - } - else - { - statement.TryBind("@CustomName", options.CustomName); - } + statement.TryBind("@Id", deviceId); - statement.MoveNext(); + if (string.IsNullOrWhiteSpace(options.CustomName)) + { + statement.TryBindNull("@CustomName"); + } + else + { + statement.TryBind("@CustomName", options.CustomName); } - }, TransactionMode); - } + statement.MoveNext(); + } + + }, TransactionMode); } } } -- cgit v1.2.3 From c30ba14c1f9701638bbb47e81d3e7027cb778135 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Tue, 26 Feb 2019 18:30:13 +0100 Subject: Use a connection pool instead of creating new connections --- .../Activity/ActivityRepository.cs | 11 +- .../Data/BaseSqliteRepository.cs | 114 ++++++++++----------- .../Data/ManagedConnection.cs | 87 ++++++++++++++++ .../Data/SqliteDisplayPreferencesRepository.cs | 11 +- .../Data/SqliteItemRepository.cs | 47 +++++---- .../Data/SqliteUserDataRepository.cs | 11 +- .../Data/SqliteUserRepository.cs | 15 +-- .../Security/AuthenticationRepository.cs | 17 +-- 8 files changed, 199 insertions(+), 114 deletions(-) create mode 100644 Emby.Server.Implementations/Data/ManagedConnection.cs (limited to 'Emby.Server.Implementations/Data/BaseSqliteRepository.cs') diff --git a/Emby.Server.Implementations/Activity/ActivityRepository.cs b/Emby.Server.Implementations/Activity/ActivityRepository.cs index 495d96977..a38cb38d7 100644 --- a/Emby.Server.Implementations/Activity/ActivityRepository.cs +++ b/Emby.Server.Implementations/Activity/ActivityRepository.cs @@ -43,7 +43,8 @@ namespace Emby.Server.Implementations.Activity private void InitializeInternal() { - using (var connection = CreateConnection()) + CreateConnections().GetAwaiter().GetResult(); + using (var connection = GetConnection()) { RunDefaultInitialization(connection); @@ -57,7 +58,7 @@ namespace Emby.Server.Implementations.Activity } } - private void TryMigrate(SQLiteDatabaseConnection connection) + private void TryMigrate(ManagedConnection connection) { try { @@ -85,7 +86,7 @@ namespace Emby.Server.Implementations.Activity throw new ArgumentNullException(nameof(entry)); } - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { @@ -123,7 +124,7 @@ namespace Emby.Server.Implementations.Activity throw new ArgumentNullException(nameof(entry)); } - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { @@ -157,7 +158,7 @@ namespace Emby.Server.Implementations.Activity public QueryResult GetActivityLogEntries(DateTime? minDate, bool? hasUserId, int? startIndex, int? limit) { - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { var commandText = BaseActivitySelectText; var whereClauses = new List(); diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 29edddb3a..6a19ea373 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -27,98 +28,93 @@ namespace Emby.Server.Implementations.Data internal static int ThreadSafeMode { get; set; } + protected virtual ConnectionFlags DefaultConnectionFlags => ConnectionFlags.SharedCached | ConnectionFlags.FullMutex; + + private readonly SemaphoreSlim WriteLock = new SemaphoreSlim(1, 1); + + private SQLiteDatabaseConnection WriteConnection; + + private readonly BlockingCollection ReadConnectionPool = new BlockingCollection(); + static BaseSqliteRepository() { ThreadSafeMode = raw.sqlite3_threadsafe(); } - private static bool _versionLogged; - private string _defaultWal; - protected SQLiteDatabaseConnection CreateConnection(bool isReadOnly = false) + protected async Task CreateConnections() { - if (!_versionLogged) - { - _versionLogged = true; - Logger.LogInformation("Sqlite version: " + SQLite3.Version); - Logger.LogInformation("Sqlite compiler options: " + string.Join(",", SQLite3.CompilerOptions)); - } - - ConnectionFlags connectionFlags; - - if (isReadOnly) - { - //Logger.LogInformation("Opening read connection"); - //connectionFlags = ConnectionFlags.Create; - connectionFlags = ConnectionFlags.ReadOnly; - } - else - { - //Logger.LogInformation("Opening write connection"); - connectionFlags = ConnectionFlags.Create; - connectionFlags |= ConnectionFlags.ReadWrite; - } - - connectionFlags |= ConnectionFlags.SharedCached; - connectionFlags |= ConnectionFlags.FullMutex; - - var db = SQLite3.Open(DbFilePath, connectionFlags, null); + await WriteLock.WaitAsync().ConfigureAwait(false); try { - if (string.IsNullOrWhiteSpace(_defaultWal)) + if (WriteConnection == null) { - _defaultWal = db.Query("PRAGMA journal_mode").SelectScalarString().First(); - - Logger.LogInformation("Default journal_mode for {0} is {1}", DbFilePath, _defaultWal); + WriteConnection = SQLite3.Open( + DbFilePath, + DefaultConnectionFlags | ConnectionFlags.Create | ConnectionFlags.ReadWrite, + null); } - var queries = new List + if (string.IsNullOrWhiteSpace(_defaultWal)) { - //"PRAGMA cache size=-10000" - //"PRAGMA read_uncommitted = true", - //"PRAGMA synchronous=Normal" - }; + _defaultWal = WriteConnection.Query("PRAGMA journal_mode").SelectScalarString().First(); - if (CacheSize.HasValue) - { - queries.Add("PRAGMA cache_size=" + CacheSize.Value.ToString(CultureInfo.InvariantCulture)); + Logger.LogInformation("Default journal_mode for {0} is {1}", DbFilePath, _defaultWal); } if (EnableTempStoreMemory) { - queries.Add("PRAGMA temp_store = memory"); + WriteConnection.Execute("PRAGMA temp_store = memory"); } else { - queries.Add("PRAGMA temp_store = file"); - } - - foreach (var query in queries) - { - db.Execute(query); + WriteConnection.Execute("PRAGMA temp_store = file"); } } catch { - using (db) - { - - } throw; } + finally + { + WriteLock.Release(); + } - return db; + // Add one reading connection for each thread + int threads = System.Environment.ProcessorCount; + for (int i = 0; i <= threads; i++) + { + ReadConnectionPool.Add(SQLite3.Open(DbFilePath, DefaultConnectionFlags | ConnectionFlags.ReadOnly, null)); + } } - public IStatement PrepareStatement(SQLiteDatabaseConnection connection, string sql) + protected ManagedConnection GetConnection(bool isReadOnly = false) + { + if (isReadOnly) + { + return new ManagedConnection(ReadConnectionPool.Take(), ReadConnectionPool); + } + else + { + if (WriteConnection == null) + { + throw new InvalidOperationException("Can't access the write connection at this time."); + } + + WriteLock.Wait(); + return new ManagedConnection(WriteConnection, WriteLock); + } + } + + public IStatement PrepareStatement(ManagedConnection connection, string sql) { return connection.PrepareStatement(sql); } - public IStatement PrepareStatementSafe(SQLiteDatabaseConnection connection, string sql) + public IStatement PrepareStatementSafe(ManagedConnection connection, string sql) { return connection.PrepareStatement(sql); } @@ -143,7 +139,7 @@ namespace Emby.Server.Implementations.Data return sql.Select(connection.PrepareStatement).ToList(); } - protected bool TableExists(SQLiteDatabaseConnection connection, string name) + protected bool TableExists(ManagedConnection connection, string name) { return connection.RunInTransaction(db => { @@ -163,7 +159,7 @@ namespace Emby.Server.Implementations.Data }, ReadTransactionMode); } - protected void RunDefaultInitialization(SQLiteDatabaseConnection db) + protected void RunDefaultInitialization(ManagedConnection db) { var queries = new List { @@ -192,9 +188,7 @@ namespace Emby.Server.Implementations.Data Logger.LogInformation("PRAGMA synchronous=" + db.Query("PRAGMA synchronous").SelectScalarString().First()); } - protected virtual bool EnableTempStoreMemory => false; - - protected virtual int? CacheSize => null; + protected virtual bool EnableTempStoreMemory => true; private bool _disposed; protected void CheckDisposed() diff --git a/Emby.Server.Implementations/Data/ManagedConnection.cs b/Emby.Server.Implementations/Data/ManagedConnection.cs new file mode 100644 index 000000000..71b934a9b --- /dev/null +++ b/Emby.Server.Implementations/Data/ManagedConnection.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; +using SQLitePCL.pretty; + +namespace Emby.Server.Implementations.Data +{ + public class ManagedConnection : IDisposable + { + private SQLiteDatabaseConnection _db; + private SemaphoreSlim _writeLock; + private BlockingCollection _readConPool; + private bool _disposed = false; + + public ManagedConnection(SQLiteDatabaseConnection db, SemaphoreSlim writeLock) + { + _db = db; + _writeLock = writeLock; + } + + public ManagedConnection(SQLiteDatabaseConnection db, BlockingCollection queue) + { + _db = db; + _readConPool = queue; + } + + public IStatement PrepareStatement(string sql) + { + return _db.PrepareStatement(sql); + } + + public IEnumerable PrepareAll(string sql) + { + return _db.PrepareAll(sql); + } + + public void ExecuteAll(string sql) + { + _db.ExecuteAll(sql); + } + + public void Execute(string sql, params object[] values) + { + _db.Execute(sql, values); + } + + public void RunQueries(string[] sql) + { + _db.RunQueries(sql); + } + + public void RunInTransaction(Action action, TransactionMode mode) + { + _db.RunInTransaction(action, mode); + } + + public T RunInTransaction(Func action, TransactionMode mode) + { + return _db.RunInTransaction(action, mode); + } + + public IEnumerable> Query(string sql) + { + return _db.Query(sql); + } + + public IEnumerable> Query(string sql, params object[] values) + { + return _db.Query(sql, values); + } + + public void Dispose() + { + if (_disposed) + { + return; + } + + _writeLock?.Release(); + _readConPool?.Add(_db); + + _db = null; // Don't dispose it + _disposed = true; + } + } +} diff --git a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs index 86a7c1551..d620f3962 100644 --- a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs @@ -61,7 +61,8 @@ namespace Emby.Server.Implementations.Data /// Task. private void InitializeInternal() { - using (var connection = CreateConnection()) + CreateConnections().GetAwaiter().GetResult(); + using (var connection = GetConnection()) { RunDefaultInitialization(connection); @@ -98,7 +99,7 @@ namespace Emby.Server.Implementations.Data cancellationToken.ThrowIfCancellationRequested(); - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { @@ -139,7 +140,7 @@ namespace Emby.Server.Implementations.Data cancellationToken.ThrowIfCancellationRequested(); - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { @@ -168,7 +169,7 @@ namespace Emby.Server.Implementations.Data var guidId = displayPreferencesId.GetMD5(); - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where id = @id and userId=@userId and client=@client")) { @@ -199,7 +200,7 @@ namespace Emby.Server.Implementations.Data { var list = new List(); - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where userId=@userId")) { diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index baa5b713a..e96b6ce3a 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -92,8 +92,6 @@ namespace Emby.Server.Implementations.Data private const string ChaptersTableName = "Chapters2"; - protected override int? CacheSize => 20000; - protected override bool EnableTempStoreMemory => true; /// @@ -101,7 +99,8 @@ namespace Emby.Server.Implementations.Data /// public void Initialize(SqliteUserDataRepository userDataRepo, IUserManager userManager) { - using (var connection = CreateConnection()) + CreateConnections().GetAwaiter().GetResult(); + using (var connection = GetConnection()) { RunDefaultInitialization(connection); @@ -551,7 +550,7 @@ namespace Emby.Server.Implementations.Data CheckDisposed(); - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { @@ -602,7 +601,7 @@ namespace Emby.Server.Implementations.Data tuples.Add((item, ancestorIds, topParent, userdataKey, inheritedTags)); } - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { @@ -1186,7 +1185,7 @@ namespace Emby.Server.Implementations.Data CheckDisposed(); - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { using (var statement = PrepareStatementSafe(connection, "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems where guid = @guid")) { @@ -1899,7 +1898,7 @@ namespace Emby.Server.Implementations.Data { CheckDisposed(); - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { var list = new List(); @@ -1928,7 +1927,7 @@ namespace Emby.Server.Implementations.Data { CheckDisposed(); - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { using (var statement = PrepareStatementSafe(connection, "select StartPositionTicks,Name,ImagePath,ImageDateModified from " + ChaptersTableName + " where ItemId = @ItemId and ChapterIndex=@ChapterIndex")) { @@ -1997,7 +1996,7 @@ namespace Emby.Server.Implementations.Data throw new ArgumentNullException(nameof(chapters)); } - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { @@ -2533,7 +2532,7 @@ namespace Emby.Server.Implementations.Data commandText += " where " + string.Join(" AND ", whereClauses); } - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { using (var statement = PrepareStatementSafe(connection, commandText)) { @@ -2602,7 +2601,7 @@ namespace Emby.Server.Implementations.Data } } - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { var list = new List(); @@ -2820,7 +2819,7 @@ namespace Emby.Server.Implementations.Data statementTexts.Add(commandText); } - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { return connection.RunInTransaction(db => { @@ -3052,7 +3051,7 @@ namespace Emby.Server.Implementations.Data } } - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { var list = new List(); @@ -3119,7 +3118,7 @@ namespace Emby.Server.Implementations.Data } var list = new List>(); - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { using (var statement = PrepareStatementSafe(connection, commandText)) { @@ -3231,7 +3230,7 @@ namespace Emby.Server.Implementations.Data statementTexts.Add(commandText); } - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { return connection.RunInTransaction(db => { @@ -4862,7 +4861,7 @@ namespace Emby.Server.Implementations.Data private void UpdateInheritedTags(CancellationToken cancellationToken) { - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { @@ -4925,7 +4924,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type CheckDisposed(); - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { @@ -4982,7 +4981,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type commandText += " order by ListOrder"; - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { var list = new List(); using (var statement = PrepareStatementSafe(connection, commandText)) @@ -5019,7 +5018,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type commandText += " order by ListOrder"; - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { var list = new List(); @@ -5245,7 +5244,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type commandText += " Group By CleanValue"; - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { var list = new List(); @@ -5431,7 +5430,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type statementTexts.Add(countText); } - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { return connection.RunInTransaction(db => { @@ -5698,7 +5697,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type CheckDisposed(); - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { @@ -5815,7 +5814,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type cmdText += " order by StreamIndex ASC"; - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { var list = new List(); @@ -5859,7 +5858,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type cancellationToken.ThrowIfCancellationRequested(); - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs index f544dfac4..9dc31d597 100644 --- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs @@ -34,7 +34,8 @@ namespace Emby.Server.Implementations.Data /// Task. public void Initialize(IUserManager userManager) { - using (var connection = CreateConnection()) + CreateConnections().GetAwaiter().GetResult(); + using (var connection = GetConnection()) { var userDatasTableExists = TableExists(connection, "UserDatas"); var userDataTableExists = TableExists(connection, "userdata"); @@ -172,7 +173,7 @@ namespace Emby.Server.Implementations.Data { cancellationToken.ThrowIfCancellationRequested(); - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { @@ -240,7 +241,7 @@ namespace Emby.Server.Implementations.Data { cancellationToken.ThrowIfCancellationRequested(); - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { @@ -275,7 +276,7 @@ namespace Emby.Server.Implementations.Data throw new ArgumentNullException(nameof(key)); } - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from UserDatas where key =@Key and userId=@UserId")) { @@ -321,7 +322,7 @@ namespace Emby.Server.Implementations.Data var list = new List(); - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from UserDatas where userId=@UserId")) { diff --git a/Emby.Server.Implementations/Data/SqliteUserRepository.cs b/Emby.Server.Implementations/Data/SqliteUserRepository.cs index 785452ad3..ef8ae60b3 100644 --- a/Emby.Server.Implementations/Data/SqliteUserRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserRepository.cs @@ -40,7 +40,8 @@ namespace Emby.Server.Implementations.Data /// Task. public void Initialize() { - using (var connection = CreateConnection()) + CreateConnections().GetAwaiter().GetResult(); + using (var connection = GetConnection()) { RunDefaultInitialization(connection); @@ -60,7 +61,7 @@ namespace Emby.Server.Implementations.Data } } - private void TryMigrateToLocalUsersTable(SQLiteDatabaseConnection connection) + private void TryMigrateToLocalUsersTable(ManagedConnection connection) { try { @@ -119,7 +120,7 @@ namespace Emby.Server.Implementations.Data var serialized = _jsonSerializer.SerializeToBytes(user); - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { @@ -153,7 +154,7 @@ namespace Emby.Server.Implementations.Data var serialized = _jsonSerializer.SerializeToBytes(user); - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { @@ -168,7 +169,7 @@ namespace Emby.Server.Implementations.Data } } - private User GetUser(Guid guid, SQLiteDatabaseConnection connection) + private User GetUser(Guid guid, ManagedConnection connection) { using (var statement = connection.PrepareStatement("select id,guid,data from LocalUsersv2 where guid=@guid")) { @@ -206,7 +207,7 @@ namespace Emby.Server.Implementations.Data { var list = new List(); - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { foreach (var row in connection.Query("select id,guid,data from LocalUsersv2")) { @@ -230,7 +231,7 @@ namespace Emby.Server.Implementations.Data throw new ArgumentNullException(nameof(user)); } - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs index abc23239e..dfcd6af0d 100644 --- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs +++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs @@ -23,7 +23,8 @@ namespace Emby.Server.Implementations.Security public void Initialize() { - using (var connection = CreateConnection()) + CreateConnections().GetAwaiter().GetResult(); + using (var connection = GetConnection()) { RunDefaultInitialization(connection); @@ -48,7 +49,7 @@ namespace Emby.Server.Implementations.Security } } - private void TryMigrate(SQLiteDatabaseConnection connection, bool tableNewlyCreated) + private void TryMigrate(ManagedConnection connection, bool tableNewlyCreated) { try { @@ -87,7 +88,7 @@ namespace Emby.Server.Implementations.Security throw new ArgumentNullException(nameof(info)); } - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { @@ -119,7 +120,7 @@ namespace Emby.Server.Implementations.Security throw new ArgumentNullException(nameof(info)); } - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { @@ -151,7 +152,7 @@ namespace Emby.Server.Implementations.Security throw new ArgumentNullException(nameof(info)); } - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { @@ -248,7 +249,7 @@ namespace Emby.Server.Implementations.Security var list = new List(); - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { return connection.RunInTransaction(db => { @@ -346,7 +347,7 @@ namespace Emby.Server.Implementations.Security public DeviceOptions GetDeviceOptions(string deviceId) { - using (var connection = CreateConnection(true)) + using (var connection = GetConnection(true)) { return connection.RunInTransaction(db => { @@ -378,7 +379,7 @@ namespace Emby.Server.Implementations.Security throw new ArgumentNullException(nameof(options)); } - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { -- cgit v1.2.3 From e5248cfaa25a4aaa00e9cc8ba7d23a2b3c690b6e Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Tue, 26 Feb 2019 18:58:33 +0100 Subject: Properly dispose --- .../Data/BaseSqliteRepository.cs | 53 ++++++++++++---------- 1 file changed, 30 insertions(+), 23 deletions(-) (limited to 'Emby.Server.Implementations/Data/BaseSqliteRepository.cs') diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 6a19ea373..33bbbbfe4 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -28,7 +27,7 @@ namespace Emby.Server.Implementations.Data internal static int ThreadSafeMode { get; set; } - protected virtual ConnectionFlags DefaultConnectionFlags => ConnectionFlags.SharedCached | ConnectionFlags.FullMutex; + protected virtual ConnectionFlags DefaultConnectionFlags => ConnectionFlags.SharedCached | ConnectionFlags.NoMutex; private readonly SemaphoreSlim WriteLock = new SemaphoreSlim(1, 1); @@ -39,6 +38,7 @@ namespace Emby.Server.Implementations.Data static BaseSqliteRepository() { ThreadSafeMode = raw.sqlite3_threadsafe(); + raw.sqlite3_enable_shared_cache(1); } private string _defaultWal; @@ -55,6 +55,7 @@ namespace Emby.Server.Implementations.Data DbFilePath, DefaultConnectionFlags | ConnectionFlags.Create | ConnectionFlags.ReadWrite, null); + SQLiteDatabaseConnectionBuilder.InMemory. } if (string.IsNullOrWhiteSpace(_defaultWal)) @@ -110,34 +111,22 @@ namespace Emby.Server.Implementations.Data } public IStatement PrepareStatement(ManagedConnection connection, string sql) - { - return connection.PrepareStatement(sql); - } + => connection.PrepareStatement(sql); public IStatement PrepareStatementSafe(ManagedConnection connection, string sql) - { - return connection.PrepareStatement(sql); - } + => connection.PrepareStatement(sql); public IStatement PrepareStatement(IDatabaseConnection connection, string sql) - { - return connection.PrepareStatement(sql); - } + => connection.PrepareStatement(sql); public IStatement PrepareStatementSafe(IDatabaseConnection connection, string sql) - { - return connection.PrepareStatement(sql); - } + => connection.PrepareStatement(sql); - public List PrepareAll(IDatabaseConnection connection, IEnumerable sql) - { - return PrepareAllSafe(connection, sql); - } + public IEnumerable PrepareAll(IDatabaseConnection connection, IEnumerable sql) + => PrepareAllSafe(connection, sql); - public List PrepareAllSafe(IDatabaseConnection connection, IEnumerable sql) - { - return sql.Select(connection.PrepareStatement).ToList(); - } + public IEnumerable PrepareAllSafe(IDatabaseConnection connection, IEnumerable sql) + => sql.Select(connection.PrepareStatement); protected bool TableExists(ManagedConnection connection, string name) { @@ -201,7 +190,6 @@ namespace Emby.Server.Implementations.Data public void Dispose() { - Dispose(true); } @@ -218,6 +206,25 @@ namespace Emby.Server.Implementations.Data return; } + if (dispose) + { + WriteLock.Wait(); + try + { + WriteConnection.Dispose(); + } + finally + { + WriteLock.Release(); + } + + foreach (var i in ReadConnectionPool) + { + i.Dispose(); + } + + ReadConnectionPool.Dispose(); + } _disposed = true; } -- cgit v1.2.3 From 30842656a7fb1d23eef245dcfb57287ebdb960a0 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Tue, 26 Feb 2019 19:01:18 +0100 Subject: Properly dispose --- Emby.Server.Implementations/Data/BaseSqliteRepository.cs | 1 - Emby.Server.Implementations/Data/SqliteItemRepository.cs | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'Emby.Server.Implementations/Data/BaseSqliteRepository.cs') diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 33bbbbfe4..db63f68d0 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -55,7 +55,6 @@ namespace Emby.Server.Implementations.Data DbFilePath, DefaultConnectionFlags | ConnectionFlags.Create | ConnectionFlags.ReadWrite, null); - SQLiteDatabaseConnectionBuilder.InMemory. } if (string.IsNullOrWhiteSpace(_defaultWal)) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index e96b6ce3a..a2f490c4a 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -616,7 +616,7 @@ namespace Emby.Server.Implementations.Data { GetSaveItemCommandText(), "delete from AncestorIds where ItemId=@ItemId" - }); + }).ToList(); using (var saveItemStatement = statements[0]) using (var deleteAncestorsStatement = statements[1]) @@ -2824,7 +2824,7 @@ namespace Emby.Server.Implementations.Data return connection.RunInTransaction(db => { var result = new QueryResult(); - var statements = PrepareAllSafe(db, statementTexts); + var statements = PrepareAllSafe(db, statementTexts).ToList(); if (!isReturningZeroItems) { @@ -3236,7 +3236,7 @@ namespace Emby.Server.Implementations.Data { var result = new QueryResult(); - var statements = PrepareAllSafe(db, statementTexts); + var statements = PrepareAllSafe(db, statementTexts).ToList(); if (!isReturningZeroItems) { @@ -5437,7 +5437,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type var list = new List<(BaseItem, ItemCounts)>(); var result = new QueryResult<(BaseItem, ItemCounts)>(); - var statements = PrepareAllSafe(db, statementTexts); + var statements = PrepareAllSafe(db, statementTexts).ToList(); if (!isReturningZeroItems) { -- cgit v1.2.3 From 27c29bbb4c75d5fc5c9111c5552c37a1f137dd58 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Mon, 11 Mar 2019 22:33:27 +0100 Subject: Back to a single connection --- .../Activity/ActivityRepository.cs | 1 - .../Data/BaseSqliteRepository.cs | 80 ++++++---------------- .../Data/ManagedConnection.cs | 13 +--- .../Data/SqliteDisplayPreferencesRepository.cs | 1 - .../Data/SqliteItemRepository.cs | 1 - .../Data/SqliteUserDataRepository.cs | 1 - .../Data/SqliteUserRepository.cs | 4 +- .../Security/AuthenticationRepository.cs | 1 - .../ScheduledTasksWebSocketListener.cs | 1 - .../Session/SessionInfoWebSocketListener.cs | 1 - 10 files changed, 23 insertions(+), 81 deletions(-) (limited to 'Emby.Server.Implementations/Data/BaseSqliteRepository.cs') diff --git a/Emby.Server.Implementations/Activity/ActivityRepository.cs b/Emby.Server.Implementations/Activity/ActivityRepository.cs index a38cb38d7..63931e134 100644 --- a/Emby.Server.Implementations/Activity/ActivityRepository.cs +++ b/Emby.Server.Implementations/Activity/ActivityRepository.cs @@ -43,7 +43,6 @@ namespace Emby.Server.Implementations.Activity private void InitializeInternal() { - CreateConnections().GetAwaiter().GetResult(); using (var connection = GetConnection()) { RunDefaultInitialization(connection); diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index db63f68d0..33a0b7ddf 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -1,9 +1,7 @@ using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading; -using System.Threading.Tasks; using Microsoft.Extensions.Logging; using SQLitePCL; using SQLitePCL.pretty; @@ -33,8 +31,6 @@ namespace Emby.Server.Implementations.Data private SQLiteDatabaseConnection WriteConnection; - private readonly BlockingCollection ReadConnectionPool = new BlockingCollection(); - static BaseSqliteRepository() { ThreadSafeMode = raw.sqlite3_threadsafe(); @@ -43,70 +39,37 @@ namespace Emby.Server.Implementations.Data private string _defaultWal; - protected async Task CreateConnections() + protected ManagedConnection GetConnection(bool isReadOnly = false) { - await WriteLock.WaitAsync().ConfigureAwait(false); - - try + WriteLock.Wait(); + if (WriteConnection != null) { - if (WriteConnection == null) - { - WriteConnection = SQLite3.Open( - DbFilePath, - DefaultConnectionFlags | ConnectionFlags.Create | ConnectionFlags.ReadWrite, - null); - } + return new ManagedConnection(WriteConnection, WriteLock); + } - if (string.IsNullOrWhiteSpace(_defaultWal)) - { - _defaultWal = WriteConnection.Query("PRAGMA journal_mode").SelectScalarString().First(); + WriteConnection = SQLite3.Open( + DbFilePath, + DefaultConnectionFlags | ConnectionFlags.Create | ConnectionFlags.ReadWrite, + null); - Logger.LogInformation("Default journal_mode for {0} is {1}", DbFilePath, _defaultWal); - } - if (EnableTempStoreMemory) - { - WriteConnection.Execute("PRAGMA temp_store = memory"); - } - else - { - WriteConnection.Execute("PRAGMA temp_store = file"); - } - } - catch + if (string.IsNullOrWhiteSpace(_defaultWal)) { + _defaultWal = WriteConnection.Query("PRAGMA journal_mode").SelectScalarString().First(); - throw; - } - finally - { - WriteLock.Release(); + Logger.LogInformation("Default journal_mode for {0} is {1}", DbFilePath, _defaultWal); } - // Add one reading connection for each thread - int threads = System.Environment.ProcessorCount; - for (int i = 0; i <= threads; i++) - { - ReadConnectionPool.Add(SQLite3.Open(DbFilePath, DefaultConnectionFlags | ConnectionFlags.ReadOnly, null)); - } - } - - protected ManagedConnection GetConnection(bool isReadOnly = false) - { - if (isReadOnly) + if (EnableTempStoreMemory) { - return new ManagedConnection(ReadConnectionPool.Take(), ReadConnectionPool); + WriteConnection.Execute("PRAGMA temp_store = memory"); } else { - if (WriteConnection == null) - { - throw new InvalidOperationException("Can't access the write connection at this time."); - } - - WriteLock.Wait(); - return new ManagedConnection(WriteConnection, WriteLock); + WriteConnection.Execute("PRAGMA temp_store = file"); } + + return new ManagedConnection(WriteConnection, WriteLock); } public IStatement PrepareStatement(ManagedConnection connection, string sql) @@ -217,14 +180,11 @@ namespace Emby.Server.Implementations.Data WriteLock.Release(); } - foreach (var i in ReadConnectionPool) - { - i.Dispose(); - } - - ReadConnectionPool.Dispose(); + WriteLock.Dispose(); } + WriteConnection = null; + _disposed = true; } diff --git a/Emby.Server.Implementations/Data/ManagedConnection.cs b/Emby.Server.Implementations/Data/ManagedConnection.cs index 71b934a9b..4c3424410 100644 --- a/Emby.Server.Implementations/Data/ManagedConnection.cs +++ b/Emby.Server.Implementations/Data/ManagedConnection.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; using SQLitePCL.pretty; @@ -9,8 +8,7 @@ namespace Emby.Server.Implementations.Data public class ManagedConnection : IDisposable { private SQLiteDatabaseConnection _db; - private SemaphoreSlim _writeLock; - private BlockingCollection _readConPool; + private readonly SemaphoreSlim _writeLock; private bool _disposed = false; public ManagedConnection(SQLiteDatabaseConnection db, SemaphoreSlim writeLock) @@ -19,12 +17,6 @@ namespace Emby.Server.Implementations.Data _writeLock = writeLock; } - public ManagedConnection(SQLiteDatabaseConnection db, BlockingCollection queue) - { - _db = db; - _readConPool = queue; - } - public IStatement PrepareStatement(string sql) { return _db.PrepareStatement(sql); @@ -77,8 +69,7 @@ namespace Emby.Server.Implementations.Data return; } - _writeLock?.Release(); - _readConPool?.Add(_db); + _writeLock.Release(); _db = null; // Don't dispose it _disposed = true; diff --git a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs index d620f3962..7f8df7626 100644 --- a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs @@ -61,7 +61,6 @@ namespace Emby.Server.Implementations.Data /// Task. private void InitializeInternal() { - CreateConnections().GetAwaiter().GetResult(); using (var connection = GetConnection()) { RunDefaultInitialization(connection); diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index a2f490c4a..9e96d7745 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -99,7 +99,6 @@ namespace Emby.Server.Implementations.Data /// public void Initialize(SqliteUserDataRepository userDataRepo, IUserManager userManager) { - CreateConnections().GetAwaiter().GetResult(); using (var connection = GetConnection()) { RunDefaultInitialization(connection); diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs index 9dc31d597..355755014 100644 --- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs @@ -34,7 +34,6 @@ namespace Emby.Server.Implementations.Data /// Task. public void Initialize(IUserManager userManager) { - CreateConnections().GetAwaiter().GetResult(); using (var connection = GetConnection()) { var userDatasTableExists = TableExists(connection, "UserDatas"); diff --git a/Emby.Server.Implementations/Data/SqliteUserRepository.cs b/Emby.Server.Implementations/Data/SqliteUserRepository.cs index ef8ae60b3..e79b3d601 100644 --- a/Emby.Server.Implementations/Data/SqliteUserRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserRepository.cs @@ -40,7 +40,6 @@ namespace Emby.Server.Implementations.Data /// Task. public void Initialize() { - CreateConnections().GetAwaiter().GetResult(); using (var connection = GetConnection()) { RunDefaultInitialization(connection); @@ -90,8 +89,7 @@ namespace Emby.Server.Implementations.Data user.Password = null; var serialized = _jsonSerializer.SerializeToBytes(user); - using (WriteLock.Write()) - using (var connection = CreateConnection()) + using (var connection = GetConnection()) { connection.RunInTransaction(db => { diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs index dfcd6af0d..efe56c081 100644 --- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs +++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs @@ -23,7 +23,6 @@ namespace Emby.Server.Implementations.Security public void Initialize() { - CreateConnections().GetAwaiter().GetResult(); using (var connection = GetConnection()) { RunDefaultInitialization(connection); diff --git a/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs index d24a18743..d9530ffb7 100644 --- a/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs +++ b/MediaBrowser.Api/ScheduledTasks/ScheduledTasksWebSocketListener.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Linq; -using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Events; diff --git a/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs b/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs index b79e9f84b..f1a6622fb 100644 --- a/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs +++ b/MediaBrowser.Api/Session/SessionInfoWebSocketListener.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Net; -- cgit v1.2.3 From b6954f3bfd68c87923348444a5923406cf672f9b Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Mon, 11 Mar 2019 23:07:38 +0100 Subject: More --- .../Activity/ActivityRepository.cs | 8 ++--- .../Data/BaseSqliteRepository.cs | 42 +++++++++------------- .../Data/SqliteDisplayPreferencesRepository.cs | 6 ++-- Jellyfin.Server/Program.cs | 7 +++- 4 files changed, 30 insertions(+), 33 deletions(-) (limited to 'Emby.Server.Implementations/Data/BaseSqliteRepository.cs') diff --git a/Emby.Server.Implementations/Activity/ActivityRepository.cs b/Emby.Server.Implementations/Activity/ActivityRepository.cs index 63931e134..cac1a9feb 100644 --- a/Emby.Server.Implementations/Activity/ActivityRepository.cs +++ b/Emby.Server.Implementations/Activity/ActivityRepository.cs @@ -15,14 +15,14 @@ namespace Emby.Server.Implementations.Activity { public class ActivityRepository : BaseSqliteRepository, IActivityRepository { - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - protected IFileSystem FileSystem { get; private set; } + private static readonly CultureInfo _usCulture = new CultureInfo("en-US"); + private readonly IFileSystem _fileSystem; public ActivityRepository(ILoggerFactory loggerFactory, IServerApplicationPaths appPaths, IFileSystem fileSystem) : base(loggerFactory.CreateLogger(nameof(ActivityRepository))) { DbFilePath = Path.Combine(appPaths.DataPath, "activitylog.db"); - FileSystem = fileSystem; + _fileSystem = fileSystem; } public void Initialize() @@ -35,7 +35,7 @@ namespace Emby.Server.Implementations.Activity { Logger.LogError(ex, "Error loading database file. Will reset and retry."); - FileSystem.DeleteFile(DbFilePath); + _fileSystem.DeleteFile(DbFilePath); InitializeInternal(); } diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 33a0b7ddf..f3bd07bb0 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -12,7 +12,7 @@ namespace Emby.Server.Implementations.Data { protected string DbFilePath { get; set; } - protected ILogger Logger { get; private set; } + protected ILogger Logger { get; } protected BaseSqliteRepository(ILogger logger) { @@ -23,31 +23,23 @@ namespace Emby.Server.Implementations.Data protected TransactionMode ReadTransactionMode => TransactionMode.Deferred; - internal static int ThreadSafeMode { get; set; } - protected virtual ConnectionFlags DefaultConnectionFlags => ConnectionFlags.SharedCached | ConnectionFlags.NoMutex; - private readonly SemaphoreSlim WriteLock = new SemaphoreSlim(1, 1); - - private SQLiteDatabaseConnection WriteConnection; + private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1); - static BaseSqliteRepository() - { - ThreadSafeMode = raw.sqlite3_threadsafe(); - raw.sqlite3_enable_shared_cache(1); - } + private SQLiteDatabaseConnection _writeConnection; private string _defaultWal; - protected ManagedConnection GetConnection(bool isReadOnly = false) + protected ManagedConnection GetConnection(bool _ = false) { - WriteLock.Wait(); - if (WriteConnection != null) + _writeLock.Wait(); + if (_writeConnection != null) { - return new ManagedConnection(WriteConnection, WriteLock); + return new ManagedConnection(_writeConnection, _writeLock); } - WriteConnection = SQLite3.Open( + _writeConnection = SQLite3.Open( DbFilePath, DefaultConnectionFlags | ConnectionFlags.Create | ConnectionFlags.ReadWrite, null); @@ -55,21 +47,21 @@ namespace Emby.Server.Implementations.Data if (string.IsNullOrWhiteSpace(_defaultWal)) { - _defaultWal = WriteConnection.Query("PRAGMA journal_mode").SelectScalarString().First(); + _defaultWal = _writeConnection.Query("PRAGMA journal_mode").SelectScalarString().First(); Logger.LogInformation("Default journal_mode for {0} is {1}", DbFilePath, _defaultWal); } if (EnableTempStoreMemory) { - WriteConnection.Execute("PRAGMA temp_store = memory"); + _writeConnection.Execute("PRAGMA temp_store = memory"); } else { - WriteConnection.Execute("PRAGMA temp_store = file"); + _writeConnection.Execute("PRAGMA temp_store = file"); } - return new ManagedConnection(WriteConnection, WriteLock); + return new ManagedConnection(_writeConnection, _writeLock); } public IStatement PrepareStatement(ManagedConnection connection, string sql) @@ -170,20 +162,20 @@ namespace Emby.Server.Implementations.Data if (dispose) { - WriteLock.Wait(); + _writeLock.Wait(); try { - WriteConnection.Dispose(); + _writeConnection.Dispose(); } finally { - WriteLock.Release(); + _writeLock.Release(); } - WriteLock.Dispose(); + _writeLock.Dispose(); } - WriteConnection = null; + _writeConnection = null; _disposed = true; } diff --git a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs index 7f8df7626..1d44b0b29 100644 --- a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs @@ -18,13 +18,13 @@ namespace Emby.Server.Implementations.Data /// public class SqliteDisplayPreferencesRepository : BaseSqliteRepository, IDisplayPreferencesRepository { - protected IFileSystem FileSystem { get; private set; } + private readonly IFileSystem _fileSystem; public SqliteDisplayPreferencesRepository(ILoggerFactory loggerFactory, IJsonSerializer jsonSerializer, IApplicationPaths appPaths, IFileSystem fileSystem) : base(loggerFactory.CreateLogger(nameof(SqliteDisplayPreferencesRepository))) { _jsonSerializer = jsonSerializer; - FileSystem = fileSystem; + _fileSystem = fileSystem; DbFilePath = Path.Combine(appPaths.DataPath, "displaypreferences.db"); } @@ -49,7 +49,7 @@ namespace Emby.Server.Implementations.Data { Logger.LogError(ex, "Error loading database file. Will reset and retry."); - FileSystem.DeleteFile(DbFilePath); + _fileSystem.DeleteFile(DbFilePath); InitializeInternal(); } diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 91752a16d..11c09db98 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -24,6 +24,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Serilog; using Serilog.AspNetCore; +using SQLitePCL; using ILogger = Microsoft.Extensions.Logging.ILogger; namespace Jellyfin.Server @@ -126,7 +127,11 @@ namespace Jellyfin.Server ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; }); #pragma warning restore CA5359 - SQLitePCL.Batteries_V2.Init(); + Batteries_V2.Init(); + if (raw.sqlite3_enable_shared_cache(1) != raw.SQLITE_OK) + { + Console.WriteLine("WARN: Failed to enable shared cache for SQLite"); + } using (var appHost = new CoreAppHost( appPaths, -- cgit v1.2.3 From e88ebd748d98cf9bd2a3978d36254f1644ce751a Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Tue, 2 Apr 2019 22:15:18 +0200 Subject: Final fixes --- .../Data/BaseSqliteRepository.cs | 44 +++++++++------------- .../Data/SqliteItemRepository.cs | 40 ++++++++++---------- .../Data/SqliteUserDataRepository.cs | 7 +++- .../Security/AuthenticationRepository.cs | 6 +-- Jellyfin.Server/Program.cs | 4 -- 5 files changed, 47 insertions(+), 54 deletions(-) (limited to 'Emby.Server.Implementations/Data/BaseSqliteRepository.cs') diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index f3bd07bb0..63cef80b0 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using Microsoft.Extensions.Logging; -using SQLitePCL; using SQLitePCL.pretty; namespace Emby.Server.Implementations.Data @@ -23,23 +22,23 @@ namespace Emby.Server.Implementations.Data protected TransactionMode ReadTransactionMode => TransactionMode.Deferred; - protected virtual ConnectionFlags DefaultConnectionFlags => ConnectionFlags.SharedCached | ConnectionFlags.NoMutex; + protected virtual ConnectionFlags DefaultConnectionFlags => ConnectionFlags.NoMutex; - private readonly SemaphoreSlim _writeLock = new SemaphoreSlim(1, 1); + protected SemaphoreSlim WriteLock = new SemaphoreSlim(1, 1); - private SQLiteDatabaseConnection _writeConnection; + protected SQLiteDatabaseConnection WriteConnection; private string _defaultWal; protected ManagedConnection GetConnection(bool _ = false) { - _writeLock.Wait(); - if (_writeConnection != null) + WriteLock.Wait(); + if (WriteConnection != null) { - return new ManagedConnection(_writeConnection, _writeLock); + return new ManagedConnection(WriteConnection, WriteLock); } - _writeConnection = SQLite3.Open( + WriteConnection = SQLite3.Open( DbFilePath, DefaultConnectionFlags | ConnectionFlags.Create | ConnectionFlags.ReadWrite, null); @@ -47,38 +46,29 @@ namespace Emby.Server.Implementations.Data if (string.IsNullOrWhiteSpace(_defaultWal)) { - _defaultWal = _writeConnection.Query("PRAGMA journal_mode").SelectScalarString().First(); + _defaultWal = WriteConnection.Query("PRAGMA journal_mode").SelectScalarString().First(); Logger.LogInformation("Default journal_mode for {0} is {1}", DbFilePath, _defaultWal); } if (EnableTempStoreMemory) { - _writeConnection.Execute("PRAGMA temp_store = memory"); + WriteConnection.Execute("PRAGMA temp_store = memory"); } else { - _writeConnection.Execute("PRAGMA temp_store = file"); + WriteConnection.Execute("PRAGMA temp_store = file"); } - return new ManagedConnection(_writeConnection, _writeLock); + return new ManagedConnection(WriteConnection, WriteLock); } public IStatement PrepareStatement(ManagedConnection connection, string sql) => connection.PrepareStatement(sql); - public IStatement PrepareStatementSafe(ManagedConnection connection, string sql) - => connection.PrepareStatement(sql); - public IStatement PrepareStatement(IDatabaseConnection connection, string sql) => connection.PrepareStatement(sql); - public IStatement PrepareStatementSafe(IDatabaseConnection connection, string sql) - => connection.PrepareStatement(sql); - - public IEnumerable PrepareAll(IDatabaseConnection connection, IEnumerable sql) - => PrepareAllSafe(connection, sql); - public IEnumerable PrepareAllSafe(IDatabaseConnection connection, IEnumerable sql) => sql.Select(connection.PrepareStatement); @@ -145,6 +135,7 @@ namespace Emby.Server.Implementations.Data public void Dispose() { Dispose(true); + GC.SuppressFinalize(this); } private readonly object _disposeLock = new object(); @@ -162,20 +153,21 @@ namespace Emby.Server.Implementations.Data if (dispose) { - _writeLock.Wait(); + WriteLock.Wait(); try { - _writeConnection.Dispose(); + WriteConnection.Dispose(); } finally { - _writeLock.Release(); + WriteLock.Release(); } - _writeLock.Dispose(); + WriteLock.Dispose(); } - _writeConnection = null; + WriteConnection = null; + WriteLock = null; _disposed = true; } diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 9e96d7745..462d91e41 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -317,7 +317,7 @@ namespace Emby.Server.Implementations.Data connection.RunQueries(postQueries); } - userDataRepo.Initialize(userManager); + userDataRepo.Initialize(userManager, WriteLock, WriteConnection); } private static readonly string[] _retriveItemColumns = @@ -551,16 +551,16 @@ namespace Emby.Server.Implementations.Data using (var connection = GetConnection()) { - connection.RunInTransaction(db => + connection.RunInTransaction((Action)(db => { - using (var saveImagesStatement = PrepareStatement(db, "Update TypedBaseItems set Images=@Images where guid=@Id")) + using (var saveImagesStatement = base.PrepareStatement((IDatabaseConnection)db, (string)"Update TypedBaseItems set Images=@Images where guid=@Id")) { saveImagesStatement.TryBind("@Id", item.Id.ToGuidBlob()); saveImagesStatement.TryBind("@Images", SerializeImages(item)); saveImagesStatement.MoveNext(); } - }, TransactionMode); + }), TransactionMode); } } @@ -1186,7 +1186,7 @@ namespace Emby.Server.Implementations.Data using (var connection = GetConnection(true)) { - using (var statement = PrepareStatementSafe(connection, "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems where guid = @guid")) + using (var statement = PrepareStatement(connection, "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems where guid = @guid")) { statement.TryBind("@guid", id); @@ -1901,7 +1901,7 @@ namespace Emby.Server.Implementations.Data { var list = new List(); - using (var statement = PrepareStatementSafe(connection, "select StartPositionTicks,Name,ImagePath,ImageDateModified from " + ChaptersTableName + " where ItemId = @ItemId order by ChapterIndex asc")) + using (var statement = PrepareStatement(connection, "select StartPositionTicks,Name,ImagePath,ImageDateModified from " + ChaptersTableName + " where ItemId = @ItemId order by ChapterIndex asc")) { statement.TryBind("@ItemId", item.Id); @@ -1928,7 +1928,7 @@ namespace Emby.Server.Implementations.Data using (var connection = GetConnection(true)) { - using (var statement = PrepareStatementSafe(connection, "select StartPositionTicks,Name,ImagePath,ImageDateModified from " + ChaptersTableName + " where ItemId = @ItemId and ChapterIndex=@ChapterIndex")) + using (var statement = PrepareStatement(connection, "select StartPositionTicks,Name,ImagePath,ImageDateModified from " + ChaptersTableName + " where ItemId = @ItemId and ChapterIndex=@ChapterIndex")) { statement.TryBind("@ItemId", item.Id); statement.TryBind("@ChapterIndex", index); @@ -2028,7 +2028,7 @@ namespace Emby.Server.Implementations.Data } insertText.Length -= 1; // Remove last , - using (var statement = PrepareStatementSafe(db, insertText.ToString())) + using (var statement = PrepareStatement(db, insertText.ToString())) { statement.TryBind("@ItemId", idBlob); @@ -2533,7 +2533,7 @@ namespace Emby.Server.Implementations.Data using (var connection = GetConnection(true)) { - using (var statement = PrepareStatementSafe(connection, commandText)) + using (var statement = PrepareStatement(connection, commandText)) { if (EnableJoinUserData(query)) { @@ -2604,7 +2604,7 @@ namespace Emby.Server.Implementations.Data { var list = new List(); - using (var statement = PrepareStatementSafe(connection, commandText)) + using (var statement = PrepareStatement(connection, commandText)) { if (EnableJoinUserData(query)) { @@ -3054,7 +3054,7 @@ namespace Emby.Server.Implementations.Data { var list = new List(); - using (var statement = PrepareStatementSafe(connection, commandText)) + using (var statement = PrepareStatement(connection, commandText)) { if (EnableJoinUserData(query)) { @@ -3119,7 +3119,7 @@ namespace Emby.Server.Implementations.Data var list = new List>(); using (var connection = GetConnection(true)) { - using (var statement = PrepareStatementSafe(connection, commandText)) + using (var statement = PrepareStatement(connection, commandText)) { if (EnableJoinUserData(query)) { @@ -4983,7 +4983,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type using (var connection = GetConnection(true)) { var list = new List(); - using (var statement = PrepareStatementSafe(connection, commandText)) + using (var statement = PrepareStatement(connection, commandText)) { // Run this again to bind the params GetPeopleWhereClauses(query, statement); @@ -5021,7 +5021,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type { var list = new List(); - using (var statement = PrepareStatementSafe(connection, commandText)) + using (var statement = PrepareStatement(connection, commandText)) { // Run this again to bind the params GetPeopleWhereClauses(query, statement); @@ -5146,7 +5146,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type insertText.AppendFormat("(@ItemId, @AncestorId{0}, @AncestorIdText{0})", i.ToString(CultureInfo.InvariantCulture)); } - using (var statement = PrepareStatementSafe(db, insertText.ToString())) + using (var statement = PrepareStatement(db, insertText.ToString())) { statement.TryBind("@ItemId", itemIdBlob); @@ -5247,7 +5247,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type { var list = new List(); - using (var statement = PrepareStatementSafe(connection, commandText)) + using (var statement = PrepareStatement(connection, commandText)) { foreach (var row in statement.ExecuteQuery()) { @@ -5651,7 +5651,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type isSubsequentRow = true; } - using (var statement = PrepareStatementSafe(db, insertText.ToString())) + using (var statement = PrepareStatement(db, insertText.ToString())) { statement.TryBind("@ItemId", idBlob); @@ -5735,7 +5735,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type isSubsequentRow = true; } - using (var statement = PrepareStatementSafe(db, insertText.ToString())) + using (var statement = PrepareStatement(db, insertText.ToString())) { statement.TryBind("@ItemId", idBlob); @@ -5817,7 +5817,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type { var list = new List(); - using (var statement = PrepareStatementSafe(connection, cmdText)) + using (var statement = PrepareStatement(connection, cmdText)) { statement.TryBind("@ItemId", query.ItemId.ToGuidBlob()); @@ -5902,7 +5902,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type insertText.Append(")"); } - using (var statement = PrepareStatementSafe(db, insertText.ToString())) + using (var statement = PrepareStatement(db, insertText.ToString())) { statement.TryBind("@ItemId", idBlob); diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs index 355755014..6ac398937 100644 --- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs @@ -32,8 +32,13 @@ namespace Emby.Server.Implementations.Data /// Opens the connection to the database /// /// Task. - public void Initialize(IUserManager userManager) + public void Initialize(IUserManager userManager, SemaphoreSlim dbLock, SQLiteDatabaseConnection dbConnection) { + WriteLock.Dispose(); + WriteLock = dbLock; + WriteConnection?.Dispose(); + WriteConnection = dbConnection; + using (var connection = GetConnection()) { var userDatasTableExists = TableExists(connection, "UserDatas"); diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs index efe56c081..29afb9f64 100644 --- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs +++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs @@ -348,9 +348,9 @@ namespace Emby.Server.Implementations.Security { using (var connection = GetConnection(true)) { - return connection.RunInTransaction(db => + return connection.RunInTransaction((Func)(db => { - using (var statement = PrepareStatementSafe(db, "select CustomName from Devices where Id=@DeviceId")) + using (var statement = base.PrepareStatement((IDatabaseConnection)db, (string)"select CustomName from Devices where Id=@DeviceId")) { statement.TryBind("@DeviceId", deviceId); @@ -367,7 +367,7 @@ namespace Emby.Server.Implementations.Security return result; } - }, ReadTransactionMode); + }), ReadTransactionMode); } } diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 11c09db98..9454b28d6 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -128,10 +128,6 @@ namespace Jellyfin.Server #pragma warning restore CA5359 Batteries_V2.Init(); - if (raw.sqlite3_enable_shared_cache(1) != raw.SQLITE_OK) - { - Console.WriteLine("WARN: Failed to enable shared cache for SQLite"); - } using (var appHost = new CoreAppHost( appPaths, -- cgit v1.2.3 From d00ad28efd10e2bb312c9a08055f83df26065494 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Wed, 3 Apr 2019 13:46:07 +0200 Subject: Address comments --- .../Activity/ActivityRepository.cs | 2 +- .../Data/BaseSqliteRepository.cs | 2 +- .../Data/SqliteItemRepository.cs | 24 ++++++++++++++-------- .../Data/SqliteUserDataRepository.cs | 5 ----- .../Security/AuthenticationRepository.cs | 8 ++++---- 5 files changed, 21 insertions(+), 20 deletions(-) (limited to 'Emby.Server.Implementations/Data/BaseSqliteRepository.cs') diff --git a/Emby.Server.Implementations/Activity/ActivityRepository.cs b/Emby.Server.Implementations/Activity/ActivityRepository.cs index e45add355..f8a1b32af 100644 --- a/Emby.Server.Implementations/Activity/ActivityRepository.cs +++ b/Emby.Server.Implementations/Activity/ActivityRepository.cs @@ -215,7 +215,7 @@ namespace Emby.Server.Implementations.Activity var list = new List(); var result = new QueryResult(); - var statements = PrepareAllSafe(db, statementTexts).ToList(); + var statements = PrepareAll(db, statementTexts).ToList(); using (var statement = statements[0]) { diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 63cef80b0..c5af156bb 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -69,7 +69,7 @@ namespace Emby.Server.Implementations.Data public IStatement PrepareStatement(IDatabaseConnection connection, string sql) => connection.PrepareStatement(sql); - public IEnumerable PrepareAllSafe(IDatabaseConnection connection, IEnumerable sql) + public IEnumerable PrepareAll(IDatabaseConnection connection, IEnumerable sql) => sql.Select(connection.PrepareStatement); protected bool TableExists(ManagedConnection connection, string name) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 462d91e41..5dc104347 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -518,10 +518,11 @@ namespace Emby.Server.Implementations.Data { saveItemCommandCommandText += ","; } + saveItemCommandCommandText += "@" + saveColumns[i]; } - saveItemCommandCommandText += ")"; - return saveItemCommandCommandText; + + return saveItemCommandCommandText + ")"; } /// @@ -551,16 +552,16 @@ namespace Emby.Server.Implementations.Data using (var connection = GetConnection()) { - connection.RunInTransaction((Action)(db => + connection.RunInTransaction(db => { - using (var saveImagesStatement = base.PrepareStatement((IDatabaseConnection)db, (string)"Update TypedBaseItems set Images=@Images where guid=@Id")) + using (var saveImagesStatement = base.PrepareStatement(db, "Update TypedBaseItems set Images=@Images where guid=@Id")) { saveImagesStatement.TryBind("@Id", item.Id.ToGuidBlob()); saveImagesStatement.TryBind("@Images", SerializeImages(item)); saveImagesStatement.MoveNext(); } - }), TransactionMode); + }, TransactionMode); } } @@ -611,7 +612,7 @@ namespace Emby.Server.Implementations.Data private void SaveItemsInTranscation(IDatabaseConnection db, IEnumerable<(BaseItem, List, BaseItem, string, List)> tuples) { - var statements = PrepareAllSafe(db, new string[] + var statements = PrepareAll(db, new string[] { GetSaveItemCommandText(), "delete from AncestorIds where ItemId=@ItemId" @@ -990,6 +991,7 @@ namespace Emby.Server.Implementations.Data { albumArtists = string.Join("|", hasAlbumArtists.AlbumArtists); } + saveItemStatement.TryBind("@AlbumArtists", albumArtists); saveItemStatement.TryBind("@ExternalId", item.ExternalId); @@ -1026,6 +1028,7 @@ namespace Emby.Server.Implementations.Data { continue; } + str.Append($"{i.Key}={i.Value}|"); } @@ -1033,6 +1036,7 @@ namespace Emby.Server.Implementations.Data { return null; } + str.Length -= 1; // Remove last | return str.ToString(); } @@ -1070,6 +1074,7 @@ namespace Emby.Server.Implementations.Data { return null; } + StringBuilder str = new StringBuilder(); foreach (var i in images) { @@ -1079,6 +1084,7 @@ namespace Emby.Server.Implementations.Data } str.Append(ToValueString(i) + "|"); } + str.Length -= 1; // Remove last | return str.ToString(); } @@ -2823,7 +2829,7 @@ namespace Emby.Server.Implementations.Data return connection.RunInTransaction(db => { var result = new QueryResult(); - var statements = PrepareAllSafe(db, statementTexts).ToList(); + var statements = PrepareAll(db, statementTexts).ToList(); if (!isReturningZeroItems) { @@ -3235,7 +3241,7 @@ namespace Emby.Server.Implementations.Data { var result = new QueryResult(); - var statements = PrepareAllSafe(db, statementTexts).ToList(); + var statements = PrepareAll(db, statementTexts).ToList(); if (!isReturningZeroItems) { @@ -5436,7 +5442,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type var list = new List<(BaseItem, ItemCounts)>(); var result = new QueryResult<(BaseItem, ItemCounts)>(); - var statements = PrepareAllSafe(db, statementTexts).ToList(); + var statements = PrepareAll(db, statementTexts).ToList(); if (!isReturningZeroItems) { diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs index 6ac398937..0580203c5 100644 --- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs @@ -380,10 +380,5 @@ namespace Emby.Server.Implementations.Data return userData; } - - protected override void Dispose(bool dispose) - { - // handled by library database - } } } diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs index 29afb9f64..c8ecd7e6e 100644 --- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs +++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs @@ -258,7 +258,7 @@ namespace Emby.Server.Implementations.Security statementTexts.Add(commandText); statementTexts.Add("select count (Id) from Tokens" + whereTextWithoutPaging); - var statements = PrepareAllSafe(db, statementTexts) + var statements = PrepareAll(db, statementTexts) .ToList(); using (var statement = statements[0]) @@ -348,9 +348,9 @@ namespace Emby.Server.Implementations.Security { using (var connection = GetConnection(true)) { - return connection.RunInTransaction((Func)(db => + return connection.RunInTransaction(db => { - using (var statement = base.PrepareStatement((IDatabaseConnection)db, (string)"select CustomName from Devices where Id=@DeviceId")) + using (var statement = base.PrepareStatement(db, "select CustomName from Devices where Id=@DeviceId")) { statement.TryBind("@DeviceId", deviceId); @@ -367,7 +367,7 @@ namespace Emby.Server.Implementations.Security return result; } - }), ReadTransactionMode); + }, ReadTransactionMode); } } -- cgit v1.2.3 From 7898af4cebe58bc11d120552594098041fff56fb Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Wed, 3 Apr 2019 17:34:54 +0200 Subject: Reworked PRAGMA statements use --- .../Activity/ActivityRepository.cs | 2 - .../Data/BaseSqliteRepository.cs | 90 +++++++++++----------- .../Data/SqliteDisplayPreferencesRepository.cs | 2 - .../Data/SqliteItemRepository.cs | 4 +- .../Data/SqliteUserDataRepository.cs | 2 - .../Data/SqliteUserRepository.cs | 2 - .../Security/AuthenticationRepository.cs | 2 - 7 files changed, 45 insertions(+), 59 deletions(-) (limited to 'Emby.Server.Implementations/Data/BaseSqliteRepository.cs') diff --git a/Emby.Server.Implementations/Activity/ActivityRepository.cs b/Emby.Server.Implementations/Activity/ActivityRepository.cs index f8a1b32af..de46ab965 100644 --- a/Emby.Server.Implementations/Activity/ActivityRepository.cs +++ b/Emby.Server.Implementations/Activity/ActivityRepository.cs @@ -45,8 +45,6 @@ namespace Emby.Server.Implementations.Activity { using (var connection = GetConnection()) { - RunDefaultInitialization(connection); - connection.RunQueries(new[] { "create table if not exists ActivityLog (Id INTEGER PRIMARY KEY, Name TEXT NOT NULL, Overview TEXT, ShortOverview TEXT, Type TEXT NOT NULL, ItemId TEXT, UserId TEXT, DateCreated DATETIME NOT NULL, LogSeverity TEXT NOT NULL)", diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index c5af156bb..4da6665c2 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -9,27 +9,37 @@ namespace Emby.Server.Implementations.Data { public abstract class BaseSqliteRepository : IDisposable { - protected string DbFilePath { get; set; } - - protected ILogger Logger { get; } + private bool _disposed = false; protected BaseSqliteRepository(ILogger logger) { Logger = logger; } + protected string DbFilePath { get; set; } + + protected ILogger Logger { get; } + + protected virtual ConnectionFlags DefaultConnectionFlags => ConnectionFlags.NoMutex; + protected TransactionMode TransactionMode => TransactionMode.Deferred; protected TransactionMode ReadTransactionMode => TransactionMode.Deferred; - protected virtual ConnectionFlags DefaultConnectionFlags => ConnectionFlags.NoMutex; + protected virtual int? CacheSize => null; + + protected virtual string JournalMode => "WAL"; + + protected virtual int? PageSize => null; + + protected virtual TempStoreMode TempStore => TempStoreMode.Default; + + protected virtual SynchronousMode? Synchronous => null; protected SemaphoreSlim WriteLock = new SemaphoreSlim(1, 1); protected SQLiteDatabaseConnection WriteConnection; - private string _defaultWal; - protected ManagedConnection GetConnection(bool _ = false) { WriteLock.Wait(); @@ -43,23 +53,28 @@ namespace Emby.Server.Implementations.Data DefaultConnectionFlags | ConnectionFlags.Create | ConnectionFlags.ReadWrite, null); - - if (string.IsNullOrWhiteSpace(_defaultWal)) + if (CacheSize.HasValue) { - _defaultWal = WriteConnection.Query("PRAGMA journal_mode").SelectScalarString().First(); + WriteConnection.Execute("PRAGMA cache_size=" + (int)CacheSize.Value); + } - Logger.LogInformation("Default journal_mode for {0} is {1}", DbFilePath, _defaultWal); + if (!string.IsNullOrWhiteSpace(JournalMode)) + { + WriteConnection.Execute("PRAGMA journal_mode=" + JournalMode); } - if (EnableTempStoreMemory) + if (Synchronous.HasValue) { - WriteConnection.Execute("PRAGMA temp_store = memory"); + WriteConnection.Execute("PRAGMA synchronous=" + (int)Synchronous.Value); } - else + + if (PageSize.HasValue) { - WriteConnection.Execute("PRAGMA temp_store = file"); + WriteConnection.Execute("PRAGMA page_size=" + (int)PageSize.Value); } + WriteConnection.Execute("PRAGMA temp_store=" + (int)TempStore); + return new ManagedConnection(WriteConnection, WriteLock); } @@ -92,38 +107,6 @@ namespace Emby.Server.Implementations.Data }, ReadTransactionMode); } - protected void RunDefaultInitialization(ManagedConnection db) - { - var queries = new List - { - "PRAGMA journal_mode=WAL", - "PRAGMA page_size=4096", - "PRAGMA synchronous=Normal" - }; - - if (EnableTempStoreMemory) - { - queries.AddRange(new List - { - "pragma default_temp_store = memory", - "pragma temp_store = memory" - }); - } - else - { - queries.AddRange(new List - { - "pragma temp_store = file" - }); - } - - db.ExecuteAll(string.Join(";", queries)); - Logger.LogInformation("PRAGMA synchronous=" + db.Query("PRAGMA synchronous").SelectScalarString().First()); - } - - protected virtual bool EnableTempStoreMemory => true; - - private bool _disposed; protected void CheckDisposed() { if (_disposed) @@ -199,4 +182,19 @@ namespace Emby.Server.Implementations.Data connection.Execute("alter table " + table + " add column " + columnName + " " + type + " NULL"); } } + + public enum SynchronousMode + { + Off = 0, + Normal = 1, + Full = 2, + Extra = 3 + } + + public enum TempStoreMode + { + Default = 0, + File = 1, + Memory = 2 + } } diff --git a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs index 1d44b0b29..01ef9851d 100644 --- a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs @@ -63,8 +63,6 @@ namespace Emby.Server.Implementations.Data { using (var connection = GetConnection()) { - RunDefaultInitialization(connection); - string[] queries = { "create table if not exists userdisplaypreferences (id GUID NOT NULL, userId GUID NOT NULL, client text NOT NULL, data BLOB NOT NULL)", diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 5dc104347..8a56e16bb 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -92,7 +92,7 @@ namespace Emby.Server.Implementations.Data private const string ChaptersTableName = "Chapters2"; - protected override bool EnableTempStoreMemory => true; + protected override TempStoreMode TempStore => TempStoreMode.Memory; /// /// Opens the connection to the database @@ -101,8 +101,6 @@ namespace Emby.Server.Implementations.Data { using (var connection = GetConnection()) { - RunDefaultInitialization(connection); - const string createMediaStreamsTableCommand = "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, CodecTag TEXT NULL, Comment TEXT NULL, NalLengthSize TEXT NULL, IsAvc BIT NULL, Title TEXT NULL, TimeBase TEXT NULL, CodecTimeBase TEXT NULL, ColorPrimaries TEXT NULL, ColorSpace TEXT NULL, ColorTransfer TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))"; diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs index 0580203c5..4035bb99d 100644 --- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs @@ -128,8 +128,6 @@ namespace Emby.Server.Implementations.Data return list; } - protected override bool EnableTempStoreMemory => true; - /// /// Saves the user data. /// diff --git a/Emby.Server.Implementations/Data/SqliteUserRepository.cs b/Emby.Server.Implementations/Data/SqliteUserRepository.cs index a0c6d2903..cd364e7f4 100644 --- a/Emby.Server.Implementations/Data/SqliteUserRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserRepository.cs @@ -42,8 +42,6 @@ namespace Emby.Server.Implementations.Data { using (var connection = GetConnection()) { - RunDefaultInitialization(connection); - var localUsersTableExists = TableExists(connection, "LocalUsersv2"); connection.RunQueries(new[] { diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs index c8ecd7e6e..545e11bf9 100644 --- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs +++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs @@ -25,8 +25,6 @@ namespace Emby.Server.Implementations.Security { using (var connection = GetConnection()) { - RunDefaultInitialization(connection); - var tableNewlyCreated = !TableExists(connection, "Tokens"); string[] queries = { -- cgit v1.2.3 From db2765aae5556fd4e05e1c310027bdbd699327d2 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Wed, 3 Apr 2019 18:02:43 +0200 Subject: Last bit of cleanup --- .../Data/BaseSqliteRepository.cs | 56 +++++++++++----------- 1 file changed, 27 insertions(+), 29 deletions(-) (limited to 'Emby.Server.Implementations/Data/BaseSqliteRepository.cs') diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 4da6665c2..7938d6b7e 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -107,6 +107,33 @@ namespace Emby.Server.Implementations.Data }, ReadTransactionMode); } + protected List GetColumnNames(IDatabaseConnection connection, string table) + { + var list = new List(); + + foreach (var row in connection.Query("PRAGMA table_info(" + table + ")")) + { + if (row[1].SQLiteType != SQLiteType.Null) + { + var name = row[1].ToString(); + + list.Add(name); + } + } + + return list; + } + + protected void AddColumn(IDatabaseConnection connection, string table, string columnName, string type, List existingColumnNames) + { + if (existingColumnNames.Contains(columnName, StringComparer.OrdinalIgnoreCase)) + { + return; + } + + connection.Execute("alter table " + table + " add column " + columnName + " " + type + " NULL"); + } + protected void CheckDisposed() { if (_disposed) @@ -121,8 +148,6 @@ namespace Emby.Server.Implementations.Data GC.SuppressFinalize(this); } - private readonly object _disposeLock = new object(); - /// /// Releases unmanaged and - optionally - managed resources. /// @@ -154,33 +179,6 @@ namespace Emby.Server.Implementations.Data _disposed = true; } - - protected List GetColumnNames(IDatabaseConnection connection, string table) - { - var list = new List(); - - foreach (var row in connection.Query("PRAGMA table_info(" + table + ")")) - { - if (row[1].SQLiteType != SQLiteType.Null) - { - var name = row[1].ToString(); - - list.Add(name); - } - } - - return list; - } - - protected void AddColumn(IDatabaseConnection connection, string table, string columnName, string type, List existingColumnNames) - { - if (existingColumnNames.Contains(columnName, StringComparer.OrdinalIgnoreCase)) - { - return; - } - - connection.Execute("alter table " + table + " add column " + columnName + " " + type + " NULL"); - } } public enum SynchronousMode -- cgit v1.2.3 From 45c13141f9ac3da07f4d15c1fb90442d3eb855e2 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Mon, 1 Jul 2019 17:59:01 +0200 Subject: Address comments --- .../Data/BaseSqliteRepository.cs | 15 +++++---- .../Data/SqliteItemRepository.cs | 38 +++++++++++----------- 2 files changed, 27 insertions(+), 26 deletions(-) (limited to 'Emby.Server.Implementations/Data/BaseSqliteRepository.cs') diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 7938d6b7e..6e061c154 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -36,9 +36,9 @@ namespace Emby.Server.Implementations.Data protected virtual SynchronousMode? Synchronous => null; - protected SemaphoreSlim WriteLock = new SemaphoreSlim(1, 1); + protected SemaphoreSlim WriteLock { get; set; } = new SemaphoreSlim(1, 1); - protected SQLiteDatabaseConnection WriteConnection; + protected SQLiteDatabaseConnection WriteConnection { get; set; } protected ManagedConnection GetConnection(bool _ = false) { @@ -55,7 +55,7 @@ namespace Emby.Server.Implementations.Data if (CacheSize.HasValue) { - WriteConnection.Execute("PRAGMA cache_size=" + (int)CacheSize.Value); + WriteConnection.Execute("PRAGMA cache_size=" + CacheSize.Value); } if (!string.IsNullOrWhiteSpace(JournalMode)) @@ -70,7 +70,7 @@ namespace Emby.Server.Implementations.Data if (PageSize.HasValue) { - WriteConnection.Execute("PRAGMA page_size=" + (int)PageSize.Value); + WriteConnection.Execute("PRAGMA page_size=" + PageSize.Value); } WriteConnection.Execute("PRAGMA temp_store=" + (int)TempStore); @@ -109,7 +109,7 @@ namespace Emby.Server.Implementations.Data protected List GetColumnNames(IDatabaseConnection connection, string table) { - var list = new List(); + var columnNames = new List(); foreach (var row in connection.Query("PRAGMA table_info(" + table + ")")) { @@ -117,11 +117,11 @@ namespace Emby.Server.Implementations.Data { var name = row[1].ToString(); - list.Add(name); + columnNames.Add(name); } } - return list; + return columnNames; } protected void AddColumn(IDatabaseConnection connection, string table, string columnName, string type, List existingColumnNames) @@ -142,6 +142,7 @@ namespace Emby.Server.Implementations.Data } } + /// public void Dispose() { Dispose(true); diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 8a56e16bb..1cefcec7c 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -36,13 +36,9 @@ namespace Emby.Server.Implementations.Data /// public class SqliteItemRepository : BaseSqliteRepository, IItemRepository { - private readonly TypeMapper _typeMapper; + private const string ChaptersTableName = "Chapters2"; - /// - /// Gets the name of the repository - /// - /// The name. - public string Name => "SQLite"; + private readonly TypeMapper _typeMapper; /// /// Gets the json serializer. @@ -54,12 +50,9 @@ namespace Emby.Server.Implementations.Data /// The _app paths /// private readonly IServerConfigurationManager _config; - private IServerApplicationHost _appHost; - + private readonly IServerApplicationHost _appHost; private readonly ILocalizationManager _localization; - public IImageProcessor ImageProcessor { get; set; } - /// /// Initializes a new instance of the class. /// @@ -90,10 +83,17 @@ namespace Emby.Server.Implementations.Data DbFilePath = Path.Combine(_config.ApplicationPaths.DataPath, "library.db"); } - private const string ChaptersTableName = "Chapters2"; + /// + public string Name => "SQLite"; + + /// + protected override int? CacheSize => 20000; + /// protected override TempStoreMode TempStore => TempStoreMode.Memory; + public IImageProcessor ImageProcessor { get; set; } + /// /// Opens the connection to the database /// @@ -1903,7 +1903,7 @@ namespace Emby.Server.Implementations.Data using (var connection = GetConnection(true)) { - var list = new List(); + var chapters = new List(); using (var statement = PrepareStatement(connection, "select StartPositionTicks,Name,ImagePath,ImageDateModified from " + ChaptersTableName + " where ItemId = @ItemId order by ChapterIndex asc")) { @@ -1911,11 +1911,11 @@ namespace Emby.Server.Implementations.Data foreach (var row in statement.ExecuteQuery()) { - list.Add(GetChapter(row, item)); + chapters.Add(GetChapter(row, item)); } } - return list; + return chapters; } } @@ -2606,7 +2606,7 @@ namespace Emby.Server.Implementations.Data using (var connection = GetConnection(true)) { - var list = new List(); + var items = new List(); using (var statement = PrepareStatement(connection, commandText)) { @@ -2634,7 +2634,7 @@ namespace Emby.Server.Implementations.Data var item = GetItem(row, query, hasProgramAttributes, hasEpisodeAttributes, hasServiceName, hasStartDate, hasTrailerTypes, hasArtistFields, hasSeriesFields); if (item != null) { - list.Add(item); + items.Add(item); } } } @@ -2646,7 +2646,7 @@ namespace Emby.Server.Implementations.Data limit -= 4; var newList = new List(); - foreach (var item in list) + foreach (var item in items) { AddItem(newList, item); @@ -2656,12 +2656,12 @@ namespace Emby.Server.Implementations.Data } } - list = newList; + items = newList; } LogQueryTime("GetItemList", commandText, now); - return list; + return items; } } -- cgit v1.2.3 From 29ae7b9aeb46ac297ba5c3253d73cd4cd325c042 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Mon, 1 Jul 2019 18:24:35 +0200 Subject: Add docs --- .../Data/BaseSqliteRepository.cs | 86 ++++++++++++++++++++++ 1 file changed, 86 insertions(+) (limited to 'Emby.Server.Implementations/Data/BaseSqliteRepository.cs') diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 6e061c154..9bc0bb945 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -16,28 +16,78 @@ namespace Emby.Server.Implementations.Data Logger = logger; } + /// + /// Gets or sets the path to the DB file. + /// + /// Path to the DB file. protected string DbFilePath { get; set; } + /// + /// Gets the logger. + /// + /// The logger. protected ILogger Logger { get; } + /// + /// Gets the default connection flags. + /// + /// The default connection flags. protected virtual ConnectionFlags DefaultConnectionFlags => ConnectionFlags.NoMutex; + /// + /// Gets the transaction mode. + /// + /// The transaction mode.> protected TransactionMode TransactionMode => TransactionMode.Deferred; + /// + /// Gets the transaction mode for read-only operations. + /// + /// The transaction mode. protected TransactionMode ReadTransactionMode => TransactionMode.Deferred; + /// + /// Gets the cache size. + /// + /// The cache size or null. protected virtual int? CacheSize => null; + /// + /// Gets the journal mode. + /// + /// The journal mode. protected virtual string JournalMode => "WAL"; + /// + /// Gets the page size. + /// + /// The page size or null. protected virtual int? PageSize => null; + /// + /// Gets the temp store mode. + /// + /// The temp store mode. + /// protected virtual TempStoreMode TempStore => TempStoreMode.Default; + /// + /// Gets the synchronous mode. + /// + /// The synchronous mode or null. + /// protected virtual SynchronousMode? Synchronous => null; + /// + /// Gets or sets the write lock. + /// + /// The write lock. protected SemaphoreSlim WriteLock { get; set; } = new SemaphoreSlim(1, 1); + /// + /// Gets or sets the write connection. + /// + /// The write connection. protected SQLiteDatabaseConnection WriteConnection { get; set; } protected ManagedConnection GetConnection(bool _ = false) @@ -182,18 +232,54 @@ namespace Emby.Server.Implementations.Data } } + /// + /// The disk synchronization mode, controls how aggressively SQLite will write data + /// all the way out to physical storage. + /// public enum SynchronousMode { + /// + /// SQLite continues without syncing as soon as it has handed data off to the operating system + /// Off = 0, + + /// + /// SQLite database engine will still sync at the most critical moments + /// Normal = 1, + + /// + /// SQLite database engine will use the xSync method of the VFS + /// to ensure that all content is safely written to the disk surface prior to continuing. + /// Full = 2, + + /// + /// EXTRA synchronous is like FULL with the addition that the directory containing a rollback journal + /// is synced after that journal is unlinked to commit a transaction in DELETE mode. + /// Extra = 3 } + /// + /// Storage mode used by temporary database files. + /// public enum TempStoreMode { + /// + /// The compile-time C preprocessor macro SQLITE_TEMP_STORE + /// is used to determine where temporary tables and indices are stored. + /// Default = 0, + + /// + /// Temporary tables and indices are stored in a file. + /// File = 1, + + /// + /// Temporary tables and indices are kept in as if they were pure in-memory databases memory. + /// Memory = 2 } } -- cgit v1.2.3 From 7587fe56d83fd6b3031cb11a91d94b9348c08846 Mon Sep 17 00:00:00 2001 From: Erwin de Haan Date: Thu, 4 Jul 2019 20:54:57 +0200 Subject: Moved VACUUM down to the end of the list. --- Emby.Server.Implementations/Data/BaseSqliteRepository.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'Emby.Server.Implementations/Data/BaseSqliteRepository.cs') diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 821c4b448..eabe7d120 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -202,8 +202,7 @@ namespace Emby.Server.Implementations.Data protected void RunDefaultInitialization(ManagedConnection db) { var queries = new List - { - "VACUUM", + { "PRAGMA journal_mode=WAL", "PRAGMA page_size=4096", "PRAGMA synchronous=Normal" @@ -224,6 +223,8 @@ namespace Emby.Server.Implementations.Data "pragma temp_store = file" }); } + // Configuration and pragmas can affect VACUUM so it needs to be last. + queries.Add("VACUUM"); db.ExecuteAll(string.Join(";", queries)); Logger.LogInformation("PRAGMA synchronous=" + db.Query("PRAGMA synchronous").SelectScalarString().First()); -- cgit v1.2.3 From acf52b9b55ef16809b05092eda6aca2b4cafb964 Mon Sep 17 00:00:00 2001 From: Erwin de Haan Date: Thu, 4 Jul 2019 20:55:49 +0200 Subject: Cleanup extra spaces. --- Emby.Server.Implementations/Data/BaseSqliteRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Emby.Server.Implementations/Data/BaseSqliteRepository.cs') diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index eabe7d120..aea37ffb1 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -202,7 +202,7 @@ namespace Emby.Server.Implementations.Data protected void RunDefaultInitialization(ManagedConnection db) { var queries = new List - { + { "PRAGMA journal_mode=WAL", "PRAGMA page_size=4096", "PRAGMA synchronous=Normal" -- cgit v1.2.3 From 0dbc294836bbf1f11e370efeeae0904d3bb099e0 Mon Sep 17 00:00:00 2001 From: Erwin de Haan Date: Sat, 6 Jul 2019 23:50:06 +0200 Subject: Move VACUUM command to fix merge error This fixes a syntax error. --- Emby.Server.Implementations/Data/BaseSqliteRepository.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'Emby.Server.Implementations/Data/BaseSqliteRepository.cs') diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 919453d2a..010ad6384 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -124,6 +124,9 @@ namespace Emby.Server.Implementations.Data } WriteConnection.Execute("PRAGMA temp_store=" + (int)TempStore); + + // Configuration and pragmas can affect VACUUM so it needs to be last. + WriteConnection.Execute("VACUUM"); return new ManagedConnection(WriteConnection, WriteLock); } @@ -170,8 +173,6 @@ namespace Emby.Server.Implementations.Data columnNames.Add(name); } } - // Configuration and pragmas can affect VACUUM so it needs to be last. - queries.Add("VACUUM"); return columnNames; } -- cgit v1.2.3 From d62a3f0e5735347ecca0bf7e00c4388b3783e54b Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Thu, 15 Aug 2019 00:00:21 +0200 Subject: Fix master --- Emby.Server.Implementations/Data/BaseSqliteRepository.cs | 4 ++-- Jellyfin.Server/Jellyfin.Server.csproj | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Emby.Server.Implementations/Data/BaseSqliteRepository.cs') diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs index 010ad6384..a5bb47afb 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -124,7 +124,7 @@ namespace Emby.Server.Implementations.Data } WriteConnection.Execute("PRAGMA temp_store=" + (int)TempStore); - + // Configuration and pragmas can affect VACUUM so it needs to be last. WriteConnection.Execute("VACUUM"); @@ -218,7 +218,7 @@ namespace Emby.Server.Implementations.Data WriteLock.Wait(); try { - WriteConnection.Dispose(); + WriteConnection?.Dispose(); } finally { diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index e87283477..ec7c026e5 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -43,7 +43,7 @@ - + -- cgit v1.2.3