From a9a808a9c407a14af9e041cff20e7fe6af3e5061 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 11 Dec 2016 00:12:00 -0500 Subject: [PATCH] fix db locking errors --- .../Activity/ActivityRepository.cs | 8 +- .../Data/BaseSqliteRepository.cs | 116 ++++++++-- .../SqliteDisplayPreferencesRepository.cs | 16 +- .../Data/SqliteFileOrganizationRepository.cs | 20 +- .../Data/SqliteItemRepository.cs | 201 +++++++++--------- .../Data/SqliteUserDataRepository.cs | 16 +- .../Data/SqliteUserRepository.cs | 12 +- .../SqliteNotificationsRepository.cs | 38 ++-- .../Security/AuthenticationRepository.cs | 12 +- .../Social/SharingRepository.cs | 8 +- .../Sync/SyncRepository.cs | 74 +++---- MediaBrowser.Controller/Entities/TV/Season.cs | 6 +- 12 files changed, 310 insertions(+), 217 deletions(-) diff --git a/Emby.Server.Implementations/Activity/ActivityRepository.cs b/Emby.Server.Implementations/Activity/ActivityRepository.cs index 9513c224f..17aef7268 100644 --- a/Emby.Server.Implementations/Activity/ActivityRepository.cs +++ b/Emby.Server.Implementations/Activity/ActivityRepository.cs @@ -52,9 +52,9 @@ namespace Emby.Server.Implementations.Activity throw new ArgumentNullException("entry"); } - using (var connection = CreateConnection()) + using (WriteLock.Write()) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { connection.RunInTransaction(db => { @@ -80,9 +80,9 @@ namespace Emby.Server.Implementations.Activity public QueryResult GetActivityLogEntries(DateTime? minDate, int? startIndex, int? limit) { - using (var connection = CreateConnection(true)) + using (WriteLock.Read()) { - using (WriteLock.Read()) + using (var connection = CreateConnection(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 f132c9765..bef2ce149 100644 --- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs +++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs @@ -20,14 +20,7 @@ namespace Emby.Server.Implementations.Data { Logger = logger; - WriteLock = AllowLockRecursion ? - new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion) : - new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); - } - - protected virtual bool AllowLockRecursion - { - get { return false; } + WriteLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); } protected TransactionMode TransactionMode @@ -35,12 +28,26 @@ namespace Emby.Server.Implementations.Data get { return TransactionMode.Immediate; } } + protected TransactionMode ReadTransactionMode + { + get { return TransactionMode.Deferred; } + } + + internal static int ThreadSafeMode { get; set; } + 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); + //CheckOk(rc); + + rc = raw.sqlite3_enable_shared_cache(1); + + ThreadSafeMode = raw.sqlite3_threadsafe(); } private static bool _versionLogged; @@ -61,16 +68,19 @@ namespace Emby.Server.Implementations.Data if (isReadOnly) { //Logger.Info("Opening read connection"); + //connectionFlags = ConnectionFlags.ReadOnly; + connectionFlags = ConnectionFlags.Create; + connectionFlags |= ConnectionFlags.ReadWrite; } else { //Logger.Info("Opening write connection"); + connectionFlags = ConnectionFlags.Create; + connectionFlags |= ConnectionFlags.ReadWrite; } - connectionFlags = ConnectionFlags.Create; - connectionFlags |= ConnectionFlags.ReadWrite; - connectionFlags |= ConnectionFlags.SharedCached; - //connectionFlags |= ConnectionFlags.NoMutex; + //connectionFlags |= ConnectionFlags.SharedCached; + connectionFlags |= ConnectionFlags.NoMutex; var db = SQLite3.Open(DbFilePath, connectionFlags, null); @@ -114,7 +124,8 @@ namespace Emby.Server.Implementations.Data db.ExecuteAll(string.Join(";", queries.ToArray())); } } - else*/ if (queries.Count > 0) + else*/ + if (queries.Count > 0) { db.ExecuteAll(string.Join(";", queries.ToArray())); } @@ -122,6 +133,26 @@ namespace Emby.Server.Implementations.Data return db; } + public IStatement PrepareStatement(IDatabaseConnection connection, string sql) + { + return connection.PrepareStatement(sql); + } + + public IStatement PrepareStatementSafe(IDatabaseConnection connection, string sql) + { + return connection.PrepareStatement(sql); + } + + public List PrepareAll(IDatabaseConnection connection, string sql) + { + return connection.PrepareAll(sql).ToList(); + } + + public List PrepareAllSafe(IDatabaseConnection connection, string sql) + { + return connection.PrepareAll(sql).ToList(); + } + protected void RunDefaultInitialization(IDatabaseConnection db) { var queries = new List @@ -288,12 +319,69 @@ namespace Emby.Server.Implementations.Data } } + public class DummyToken : IDisposable + { + public void Dispose() + { + } + } + public static IDisposable Read(this ReaderWriterLockSlim obj) { - return new ReadLockToken(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); + } + } + + public static class SemaphpreSlimExtensions + { + private sealed class WriteLockToken : IDisposable + { + private SemaphoreSlim _sync; + public WriteLockToken(SemaphoreSlim sync) + { + _sync = sync; + var task = sync.WaitAsync(); + Task.WaitAll(task); + } + public void Dispose() + { + if (_sync != null) + { + _sync.Release(); + _sync = null; + } + } + } + + public class DummyToken : IDisposable + { + public void Dispose() + { + } + } + + public static IDisposable Read(this SemaphoreSlim obj) + { + return Write(obj); + } + public static IDisposable Write(this SemaphoreSlim obj) + { + //if (BaseSqliteRepository.ThreadSafeMode > 0) + //{ + // return new DummyToken(); + //} return new WriteLockToken(obj); } } diff --git a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs index 0197efb51..f3d84315e 100644 --- a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs @@ -88,9 +88,9 @@ namespace Emby.Server.Implementations.Data cancellationToken.ThrowIfCancellationRequested(); - using (var connection = CreateConnection()) + using (WriteLock.Write()) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { connection.RunInTransaction(db => { @@ -132,9 +132,9 @@ namespace Emby.Server.Implementations.Data cancellationToken.ThrowIfCancellationRequested(); - using (var connection = CreateConnection()) + using (WriteLock.Write()) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { connection.RunInTransaction(db => { @@ -164,9 +164,9 @@ namespace Emby.Server.Implementations.Data var guidId = displayPreferencesId.GetMD5(); - using (var connection = CreateConnection(true)) + using (WriteLock.Read()) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where id = @id and userId=@userId and client=@client")) { @@ -198,9 +198,9 @@ namespace Emby.Server.Implementations.Data { var list = new List(); - using (var connection = CreateConnection(true)) + using (WriteLock.Read()) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where userId=@userId")) { diff --git a/Emby.Server.Implementations/Data/SqliteFileOrganizationRepository.cs b/Emby.Server.Implementations/Data/SqliteFileOrganizationRepository.cs index 603437120..9fbe8669d 100644 --- a/Emby.Server.Implementations/Data/SqliteFileOrganizationRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteFileOrganizationRepository.cs @@ -52,9 +52,9 @@ namespace Emby.Server.Implementations.Data cancellationToken.ThrowIfCancellationRequested(); - using (var connection = CreateConnection()) + using (WriteLock.Write()) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { connection.RunInTransaction(db => { @@ -92,9 +92,9 @@ namespace Emby.Server.Implementations.Data throw new ArgumentNullException("id"); } - using (var connection = CreateConnection()) + using (WriteLock.Write()) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { connection.RunInTransaction(db => { @@ -110,9 +110,9 @@ namespace Emby.Server.Implementations.Data public async Task DeleteAll() { - using (var connection = CreateConnection()) + using (WriteLock.Write()) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { connection.RunInTransaction(db => { @@ -131,9 +131,9 @@ namespace Emby.Server.Implementations.Data throw new ArgumentNullException("query"); } - using (var connection = CreateConnection(true)) + using (WriteLock.Read()) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { var commandText = "SELECT ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults"; @@ -182,9 +182,9 @@ namespace Emby.Server.Implementations.Data throw new ArgumentNullException("id"); } - using (var connection = CreateConnection(true)) + using (WriteLock.Read()) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { using (var statement = connection.PrepareStatement("select ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults where ResultId=@ResultId")) { diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 14723c0a7..1d9cec87e 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -99,14 +99,6 @@ namespace Emby.Server.Implementations.Data DbFilePath = Path.Combine(_config.ApplicationPaths.DataPath, "library.db"); } - protected override bool AllowLockRecursion - { - get - { - return true; - } - } - private const string ChaptersTableName = "Chapters2"; protected override int? CacheSize @@ -387,7 +379,7 @@ namespace Emby.Server.Implementations.Data userDataRepo.Initialize(WriteLock); - _backgroundConnection = CreateConnection(true); + //_backgroundConnection = CreateConnection(true); _shrinkMemoryTimer = _timerFactory.Create(OnShrinkMemoryTimerCallback, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(30)); } @@ -396,9 +388,9 @@ namespace Emby.Server.Implementations.Data { try { - using (var connection = CreateConnection()) + lock (WriteLock) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { connection.RunQueries(new string[] { @@ -682,19 +674,23 @@ namespace Emby.Server.Implementations.Data CheckDisposed(); - var tuples = new List>>(); + var tuples = new List, BaseItem, string>>(); foreach (var item in items) { var ancestorIds = item.SupportsAncestors ? item.GetAncestorIds().Distinct().ToList() : null; - tuples.Add(new Tuple>(item, ancestorIds)); + var topParent = item.GetTopParent(); + + var userdataKey = item.GetUserDataKeys().FirstOrDefault(); + + tuples.Add(new Tuple, BaseItem, string>(item, ancestorIds, topParent, userdataKey)); } - using (var connection = CreateConnection()) + lock (WriteLock) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { connection.RunInTransaction(db => { @@ -704,11 +700,11 @@ namespace Emby.Server.Implementations.Data } } - private void SaveItemsInTranscation(IDatabaseConnection db, List>> tuples) + private void SaveItemsInTranscation(IDatabaseConnection db, List, BaseItem, string>> tuples) { var requiresReset = false; - var statements = db.PrepareAll(string.Join(";", new string[] + var statements = PrepareAll(db, string.Join(";", new string[] { GetSaveItemCommandText(), "delete from AncestorIds where ItemId=@ItemId", @@ -729,8 +725,10 @@ namespace Emby.Server.Implementations.Data } var item = tuple.Item1; + var topParent = tuple.Item3; + var userDataKey = tuple.Item4; - SaveItem(item, saveItemStatement); + SaveItem(item, topParent, userDataKey, saveItemStatement); //Logger.Debug(_saveItemCommand.CommandText); if (item.SupportsAncestors) @@ -747,7 +745,7 @@ namespace Emby.Server.Implementations.Data } } - private void SaveItem(BaseItem item, IStatement saveItemStatement) + private void SaveItem(BaseItem item, BaseItem topParent, string userDataKey, IStatement saveItemStatement) { saveItemStatement.TryBind("@guid", item.Id); saveItemStatement.TryBind("@type", item.GetType().FullName); @@ -840,7 +838,7 @@ namespace Emby.Server.Implementations.Data saveItemStatement.TryBindNull("@Genres"); } - saveItemStatement.TryBind("@InheritedParentalRatingValue", item.GetInheritedParentalRatingValue() ?? 0); + saveItemStatement.TryBind("@InheritedParentalRatingValue", item.InheritedParentalRatingValue); saveItemStatement.TryBind("@SortName", item.SortName); saveItemStatement.TryBind("@RunTimeTicks", item.RunTimeTicks); @@ -922,7 +920,6 @@ namespace Emby.Server.Implementations.Data saveItemStatement.TryBind("@UnratedType", item.GetBlockUnratedType().ToString()); - var topParent = item.GetTopParent(); if (topParent != null) { //Logger.Debug("Item {0} has top parent {1}", item.Id, topParent.Id); @@ -957,7 +954,7 @@ namespace Emby.Server.Implementations.Data saveItemStatement.TryBind("@CriticRating", item.CriticRating); saveItemStatement.TryBind("@CriticRatingSummary", item.CriticRatingSummary); - var inheritedTags = item.GetInheritedTags(); + var inheritedTags = item.InheritedTags; if (inheritedTags.Count > 0) { saveItemStatement.TryBind("@InheritedTags", string.Join("|", inheritedTags.ToArray())); @@ -976,7 +973,7 @@ namespace Emby.Server.Implementations.Data saveItemStatement.TryBind("@CleanName", GetCleanValue(item.Name)); } - saveItemStatement.TryBind("@PresentationUniqueKey", item.GetPresentationUniqueKey()); + saveItemStatement.TryBind("@PresentationUniqueKey", item.PresentationUniqueKey); saveItemStatement.TryBind("@SlugName", item.SlugName); saveItemStatement.TryBind("@OriginalTitle", item.OriginalTitle); @@ -1013,7 +1010,14 @@ namespace Emby.Server.Implementations.Data saveItemStatement.TryBindNull("@SeriesName"); } - saveItemStatement.TryBind("@UserDataKey", item.GetUserDataKeys().FirstOrDefault()); + if (string.IsNullOrWhiteSpace(userDataKey)) + { + saveItemStatement.TryBindNull("@UserDataKey"); + } + else + { + saveItemStatement.TryBind("@UserDataKey", userDataKey); + } var episode = item as Episode; if (episode != null) @@ -1253,11 +1257,11 @@ namespace Emby.Server.Implementations.Data CheckDisposed(); //Logger.Info("Retrieving item {0}", id.ToString("N")); - using (var connection = CreateConnection(true)) + lock (WriteLock) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var statement = connection.PrepareStatement("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); @@ -2079,11 +2083,11 @@ namespace Emby.Server.Implementations.Data var list = new List(); - using (var connection = CreateConnection(true)) + lock (WriteLock) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var statement = connection.PrepareStatement("select StartPositionTicks,Name,ImagePath,ImageDateModified from " + ChaptersTableName + " where ItemId = @ItemId order by ChapterIndex asc")) + using (var statement = PrepareStatementSafe(connection, "select StartPositionTicks,Name,ImagePath,ImageDateModified from " + ChaptersTableName + " where ItemId = @ItemId order by ChapterIndex asc")) { statement.TryBind("@ItemId", id); @@ -2113,11 +2117,11 @@ namespace Emby.Server.Implementations.Data throw new ArgumentNullException("id"); } - using (var connection = CreateConnection(true)) + lock (WriteLock) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var statement = connection.PrepareStatement("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", id); statement.TryBind("@ChapterIndex", index); @@ -2194,16 +2198,16 @@ namespace Emby.Server.Implementations.Data var index = 0; - using (var connection = CreateConnection()) + lock (WriteLock) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { connection.RunInTransaction(db => { // First delete chapters db.Execute("delete from " + ChaptersTableName + " where ItemId=@ItemId", id.ToGuidParamValue()); - using (var saveChapterStatement = db.PrepareStatement("replace into " + ChaptersTableName + " (ItemId, ChapterIndex, StartPositionTicks, Name, ImagePath, ImageDateModified) values (@ItemId, @ChapterIndex, @StartPositionTicks, @Name, @ImagePath, @ImageDateModified)")) + using (var saveChapterStatement = PrepareStatement(db, "replace into " + ChaptersTableName + " (ItemId, ChapterIndex, StartPositionTicks, Name, ImagePath, ImageDateModified) values (@ItemId, @ChapterIndex, @StartPositionTicks, @Name, @ImagePath, @ImageDateModified)")) { foreach (var chapter in chapters) { @@ -2488,11 +2492,11 @@ namespace Emby.Server.Implementations.Data } } - using (var connection = CreateConnection(true)) + lock (WriteLock) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var statement = connection.PrepareStatement(commandText)) + using (var statement = PrepareStatementSafe(connection, commandText)) { if (EnableJoinUserData(query)) { @@ -2513,9 +2517,9 @@ namespace Emby.Server.Implementations.Data } } } - - LogQueryTime("GetItemList", commandText, now); } + + LogQueryTime("GetItemList", commandText, now); } // Hack for right now since we currently don't support filtering out these duplicates within a query @@ -2683,11 +2687,11 @@ namespace Emby.Server.Implementations.Data statementTexts.Add(commandText); } - using (var connection = CreateConnection(true)) + lock (WriteLock) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - var statements = connection.PrepareAll(string.Join(";", statementTexts.ToArray())) + var statements = PrepareAllSafe(connection, string.Join(";", statementTexts.ToArray())) .ToList(); if (!isReturningZeroItems) @@ -2902,11 +2906,11 @@ namespace Emby.Server.Implementations.Data var list = new List(); - using (var connection = CreateConnection(true)) + lock (WriteLock) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var statement = connection.PrepareStatement(commandText)) + using (var statement = PrepareStatementSafe(connection, commandText)) { if (EnableJoinUserData(query)) { @@ -2923,11 +2927,11 @@ namespace Emby.Server.Implementations.Data list.Add(row[0].ReadGuid()); } } - - LogQueryTime("GetItemList", commandText, now); - - return list; } + + LogQueryTime("GetItemList", commandText, now); + + return list; } } @@ -2973,11 +2977,11 @@ namespace Emby.Server.Implementations.Data var list = new List>(); - using (var connection = CreateConnection(true)) + lock (WriteLock) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var statement = connection.PrepareStatement(commandText)) + using (var statement = PrepareStatementSafe(connection, commandText)) { if (EnableJoinUserData(query)) { @@ -2999,11 +3003,11 @@ namespace Emby.Server.Implementations.Data list.Add(new Tuple(id, path)); } } - - LogQueryTime("GetItemIdsWithPath", commandText, now); - - return list; } + + LogQueryTime("GetItemIdsWithPath", commandText, now); + + return list; } } @@ -3087,13 +3091,13 @@ namespace Emby.Server.Implementations.Data statementTexts.Add(commandText); } - using (var connection = CreateConnection(true)) + lock (WriteLock) { - var statements = connection.PrepareAll(string.Join(";", statementTexts.ToArray())) - .ToList(); - - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { + var statements = PrepareAllSafe(connection, string.Join(";", statementTexts.ToArray())) + .ToList(); + var totalRecordCount = 0; if (!isReturningZeroItems) @@ -4457,9 +4461,9 @@ namespace Emby.Server.Implementations.Data var commandText = "select Guid,InheritedTags,(select group_concat(Tags, '|') from TypedBaseItems where (guid=outer.guid) OR (guid in (Select AncestorId from AncestorIds where ItemId=Outer.guid))) as NewInheritedTags from typedbaseitems as Outer where NewInheritedTags <> InheritedTags"; - using (var connection = CreateConnection()) + lock (WriteLock) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { foreach (var row in connection.Query(commandText)) { @@ -4476,7 +4480,7 @@ namespace Emby.Server.Implementations.Data } // write lock here - using (var statement = connection.PrepareStatement("Update TypedBaseItems set InheritedTags=@InheritedTags where Guid=@Guid")) + using (var statement = PrepareStatement(connection, "Update TypedBaseItems set InheritedTags=@InheritedTags where Guid=@Guid")) { foreach (var item in newValues) { @@ -4531,9 +4535,9 @@ namespace Emby.Server.Implementations.Data CheckDisposed(); - using (var connection = CreateConnection()) + lock (WriteLock) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { connection.RunInTransaction(db => { @@ -4561,7 +4565,7 @@ namespace Emby.Server.Implementations.Data private void ExecuteWithSingleParam(IDatabaseConnection db, string query, byte[] value) { - using (var statement = db.PrepareStatement(query)) + using (var statement = PrepareStatement(db, query)) { statement.TryBind("@Id", value); @@ -4591,11 +4595,11 @@ namespace Emby.Server.Implementations.Data var list = new List(); - using (var connection = CreateConnection(true)) + lock (WriteLock) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var statement = connection.PrepareStatement(commandText)) + using (var statement = PrepareStatementSafe(connection, commandText)) { // Run this again to bind the params GetPeopleWhereClauses(query, statement); @@ -4605,8 +4609,8 @@ namespace Emby.Server.Implementations.Data list.Add(row.GetString(0)); } } - return list; } + return list; } } @@ -4632,11 +4636,11 @@ namespace Emby.Server.Implementations.Data var list = new List(); - using (var connection = CreateConnection(true)) + lock (WriteLock) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var statement = connection.PrepareStatement(commandText)) + using (var statement = PrepareStatementSafe(connection, commandText)) { // Run this again to bind the params GetPeopleWhereClauses(query, statement); @@ -4847,15 +4851,18 @@ namespace Emby.Server.Implementations.Data commandText += " Group By CleanValue"; - using (var connection = CreateConnection(true)) + lock (WriteLock) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - foreach (var row in connection.Query(commandText)) + using (var statement = PrepareStatementSafe(connection, commandText)) { - if (!row.IsDBNull(0)) + foreach (var row in statement.ExecuteQuery()) { - list.Add(row.GetString(0)); + if (!row.IsDBNull(0)) + { + list.Add(row.GetString(0)); + } } } } @@ -5023,11 +5030,11 @@ namespace Emby.Server.Implementations.Data statementTexts.Add(countText); } - using (var connection = CreateConnection(true)) + lock (WriteLock) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - var statements = connection.PrepareAll(string.Join(";", statementTexts.ToArray())).ToList(); + var statements = PrepareAllSafe(connection, string.Join(";", statementTexts.ToArray())).ToList(); if (!isReturningZeroItems) { @@ -5208,7 +5215,7 @@ namespace Emby.Server.Implementations.Data // First delete db.Execute("delete from ItemValues where ItemId=@Id", itemId.ToGuidParamValue()); - using (var statement = db.PrepareStatement("insert into ItemValues (ItemId, Type, Value, CleanValue) values (@ItemId, @Type, @Value, @CleanValue)")) + using (var statement = PrepareStatement(db, "insert into ItemValues (ItemId, Type, Value, CleanValue) values (@ItemId, @Type, @Value, @CleanValue)")) { foreach (var pair in values) { @@ -5246,16 +5253,17 @@ namespace Emby.Server.Implementations.Data CheckDisposed(); - using (var connection = CreateConnection()) + lock (WriteLock) { - using (WriteLock.Write()) - { // First delete + using (var connection = CreateConnection()) + { + // First delete // "delete from People where ItemId=?" connection.Execute("delete from People where ItemId=?", itemId.ToGuidParamValue()); var listIndex = 0; - using (var statement = connection.PrepareStatement( + using (var statement = PrepareStatement(connection, "insert into People (ItemId, Name, Role, PersonType, SortOrder, ListOrder) values (@ItemId, @Name, @Role, @PersonType, @SortOrder, @ListOrder)")) { foreach (var person in people) @@ -5332,11 +5340,11 @@ namespace Emby.Server.Implementations.Data cmdText += " order by StreamIndex ASC"; - using (var connection = CreateConnection(true)) + lock (WriteLock) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { - using (var statement = connection.PrepareStatement(cmdText)) + using (var statement = PrepareStatementSafe(connection, cmdText)) { statement.TryBind("@ItemId", query.ItemId.ToGuidParamValue()); @@ -5377,13 +5385,14 @@ namespace Emby.Server.Implementations.Data cancellationToken.ThrowIfCancellationRequested(); - using (var connection = CreateConnection()) + lock (WriteLock) { - using (WriteLock.Write()) - { // First delete chapters + using (var connection = CreateConnection()) + { + // First delete chapters connection.Execute("delete from mediastreams where ItemId=@ItemId", id.ToGuidParamValue()); - using (var statement = connection.PrepareStatement(string.Format("replace into mediastreams ({0}) values ({1})", + using (var statement = PrepareStatement(connection, string.Format("replace into mediastreams ({0}) values ({1})", string.Join(",", _mediaStreamSaveColumns), string.Join(",", _mediaStreamSaveColumns.Select(i => "@" + i).ToArray())))) { diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs index b65e5d1b3..8acbd0bb8 100644 --- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs @@ -188,9 +188,9 @@ namespace Emby.Server.Implementations.Data { cancellationToken.ThrowIfCancellationRequested(); - using (var connection = CreateConnection()) + lock (WriteLock) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { connection.RunInTransaction(db => { @@ -259,9 +259,9 @@ namespace Emby.Server.Implementations.Data { cancellationToken.ThrowIfCancellationRequested(); - using (var connection = CreateConnection()) + lock (WriteLock) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { connection.RunInTransaction(db => { @@ -296,9 +296,9 @@ namespace Emby.Server.Implementations.Data throw new ArgumentNullException("key"); } - using (var connection = CreateConnection(true)) + lock (WriteLock) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where key =@Key and userId=@UserId")) { @@ -349,9 +349,9 @@ namespace Emby.Server.Implementations.Data var list = new List(); - using (var connection = CreateConnection()) + lock (WriteLock) { - using (WriteLock.Read()) + using (var connection = CreateConnection()) { using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where userId=@UserId")) { diff --git a/Emby.Server.Implementations/Data/SqliteUserRepository.cs b/Emby.Server.Implementations/Data/SqliteUserRepository.cs index 99d7563c7..b2b917e5e 100644 --- a/Emby.Server.Implementations/Data/SqliteUserRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteUserRepository.cs @@ -85,9 +85,9 @@ namespace Emby.Server.Implementations.Data cancellationToken.ThrowIfCancellationRequested(); - using (var connection = CreateConnection()) + using (WriteLock.Write()) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { connection.RunInTransaction(db => { @@ -110,9 +110,9 @@ namespace Emby.Server.Implementations.Data { var list = new List(); - using (var connection = CreateConnection(true)) + using (WriteLock.Read()) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { foreach (var row in connection.Query("select guid,data from users")) { @@ -148,9 +148,9 @@ namespace Emby.Server.Implementations.Data cancellationToken.ThrowIfCancellationRequested(); - using (var connection = CreateConnection()) + using (WriteLock.Write()) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { connection.RunInTransaction(db => { diff --git a/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs b/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs index aae41da19..43e19da65 100644 --- a/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs +++ b/Emby.Server.Implementations/Notifications/SqliteNotificationsRepository.cs @@ -51,24 +51,24 @@ namespace Emby.Server.Implementations.Notifications { var result = new NotificationResult(); + var clauses = new List(); + var paramList = new List(); + + if (query.IsRead.HasValue) + { + clauses.Add("IsRead=?"); + paramList.Add(query.IsRead.Value); + } + + clauses.Add("UserId=?"); + paramList.Add(query.UserId.ToGuidParamValue()); + + var whereClause = " where " + string.Join(" And ", clauses.ToArray()); + using (var connection = CreateConnection(true)) { - using (WriteLock.Read()) + lock (WriteLock) { - var clauses = new List(); - var paramList = new List(); - - if (query.IsRead.HasValue) - { - clauses.Add("IsRead=?"); - paramList.Add(query.IsRead.Value); - } - - clauses.Add("UserId=?"); - paramList.Add(query.UserId.ToGuidParamValue()); - - var whereClause = " where " + string.Join(" And ", clauses.ToArray()); - result.TotalRecordCount = connection.Query("select count(Id) from Notifications" + whereClause, paramList.ToArray()).SelectScalarInt().First(); var commandText = string.Format("select Id,UserId,Date,Name,Description,Url,Level,IsRead,Category,RelatedId from Notifications{0} order by IsRead asc, Date desc", whereClause); @@ -108,7 +108,7 @@ namespace Emby.Server.Implementations.Notifications using (var connection = CreateConnection(true)) { - using (WriteLock.Read()) + lock (WriteLock) { using (var statement = connection.PrepareStatement("select Level from Notifications where UserId=@UserId and IsRead=@IsRead")) { @@ -225,7 +225,7 @@ namespace Emby.Server.Implementations.Notifications using (var connection = CreateConnection()) { - using (WriteLock.Write()) + lock (WriteLock) { connection.RunInTransaction(conn => { @@ -288,7 +288,7 @@ namespace Emby.Server.Implementations.Notifications using (var connection = CreateConnection()) { - using (WriteLock.Write()) + lock (WriteLock) { connection.RunInTransaction(conn => { @@ -310,7 +310,7 @@ namespace Emby.Server.Implementations.Notifications using (var connection = CreateConnection()) { - using (WriteLock.Write()) + lock (WriteLock) { connection.RunInTransaction(conn => { diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs index dbda4a460..dbca4931b 100644 --- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs +++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs @@ -66,9 +66,9 @@ namespace Emby.Server.Implementations.Security cancellationToken.ThrowIfCancellationRequested(); - using (var connection = CreateConnection()) + using (WriteLock.Write()) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { connection.RunInTransaction(db => { @@ -202,9 +202,9 @@ namespace Emby.Server.Implementations.Security var list = new List(); - using (var connection = CreateConnection(true)) + using (WriteLock.Read()) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { using (var statement = connection.PrepareStatement(commandText)) { @@ -241,9 +241,9 @@ namespace Emby.Server.Implementations.Security throw new ArgumentNullException("id"); } - using (var connection = CreateConnection(true)) + using (WriteLock.Read()) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { var commandText = BaseSelectText + " where Id=@Id"; diff --git a/Emby.Server.Implementations/Social/SharingRepository.cs b/Emby.Server.Implementations/Social/SharingRepository.cs index 12d846e81..e8230947e 100644 --- a/Emby.Server.Implementations/Social/SharingRepository.cs +++ b/Emby.Server.Implementations/Social/SharingRepository.cs @@ -52,9 +52,9 @@ namespace Emby.Server.Implementations.Social throw new ArgumentNullException("info.Id"); } - using (var connection = CreateConnection()) + using (WriteLock.Write()) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { connection.RunInTransaction(db => { @@ -77,9 +77,9 @@ namespace Emby.Server.Implementations.Social throw new ArgumentNullException("id"); } - using (var connection = CreateConnection(true)) + using (WriteLock.Read()) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { var commandText = "select Id, ItemId, UserId, ExpirationDate from Shares where id = ?"; diff --git a/Emby.Server.Implementations/Sync/SyncRepository.cs b/Emby.Server.Implementations/Sync/SyncRepository.cs index 037507872..885f8e64a 100644 --- a/Emby.Server.Implementations/Sync/SyncRepository.cs +++ b/Emby.Server.Implementations/Sync/SyncRepository.cs @@ -105,9 +105,9 @@ namespace Emby.Server.Implementations.Sync throw new ArgumentNullException("id"); } - using (var connection = CreateConnection(true)) + using (WriteLock.Read()) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { var commandText = BaseJobSelectText + " where Id=?"; var paramList = new List(); @@ -216,9 +216,9 @@ namespace Emby.Server.Implementations.Sync CheckDisposed(); - using (var connection = CreateConnection()) + using (WriteLock.Write()) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { string commandText; var paramList = new List(); @@ -277,9 +277,9 @@ namespace Emby.Server.Implementations.Sync CheckDisposed(); - using (var connection = CreateConnection()) + using (WriteLock.Write()) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { connection.RunInTransaction(conn => { @@ -299,9 +299,9 @@ namespace Emby.Server.Implementations.Sync CheckDisposed(); - using (var connection = CreateConnection(true)) + using (WriteLock.Read()) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { var commandText = BaseJobSelectText; var paramList = new List(); @@ -399,9 +399,9 @@ namespace Emby.Server.Implementations.Sync var guid = new Guid(id); - using (var connection = CreateConnection(true)) + using (WriteLock.Read()) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { var commandText = BaseJobItemSelectText + " where Id=?"; var paramList = new List(); @@ -425,9 +425,9 @@ namespace Emby.Server.Implementations.Sync throw new ArgumentNullException("query"); } - using (var connection = CreateConnection(true)) + using (WriteLock.Read()) { - using (WriteLock.Read()) + using (var connection = CreateConnection(true)) { var commandText = baseSelectText; var paramList = new List(); @@ -505,41 +505,41 @@ namespace Emby.Server.Implementations.Sync var now = DateTime.UtcNow; - using (var connection = CreateConnection(true)) + using (WriteLock.Read()) { - var commandText = "select ItemId,Status,Progress from SyncJobItems"; - var whereClauses = new List(); - - if (!string.IsNullOrWhiteSpace(query.TargetId)) + using (var connection = CreateConnection(true)) { - whereClauses.Add("TargetId=@TargetId"); - } + var commandText = "select ItemId,Status,Progress from SyncJobItems"; + var whereClauses = new List(); - if (query.Statuses.Length > 0) - { - var statuses = string.Join(",", query.Statuses.Select(i => "'" + i.ToString() + "'").ToArray()); + if (!string.IsNullOrWhiteSpace(query.TargetId)) + { + whereClauses.Add("TargetId=@TargetId"); + } - whereClauses.Add(string.Format("Status in ({0})", statuses)); - } + if (query.Statuses.Length > 0) + { + var statuses = string.Join(",", query.Statuses.Select(i => "'" + i.ToString() + "'").ToArray()); - if (whereClauses.Count > 0) - { - commandText += " where " + string.Join(" AND ", whereClauses.ToArray()); - } + whereClauses.Add(string.Format("Status in ({0})", statuses)); + } - var statementTexts = new List + if (whereClauses.Count > 0) + { + commandText += " where " + string.Join(" AND ", whereClauses.ToArray()); + } + + var statementTexts = new List { commandText }; - commandText = commandText - .Replace("select ItemId,Status,Progress from SyncJobItems", "select ItemIds,Status,Progress from SyncJobs") - .Replace("'Synced'", "'Completed','CompletedWithError'"); + commandText = commandText + .Replace("select ItemId,Status,Progress from SyncJobItems", "select ItemIds,Status,Progress from SyncJobs") + .Replace("'Synced'", "'Completed','CompletedWithError'"); - statementTexts.Add(commandText); + statementTexts.Add(commandText); - using (WriteLock.Read()) - { var statements = connection.PrepareAll(string.Join(";", statementTexts.ToArray())) .ToList(); @@ -692,9 +692,9 @@ namespace Emby.Server.Implementations.Sync CheckDisposed(); - using (var connection = CreateConnection()) + using (WriteLock.Write()) { - using (WriteLock.Write()) + using (var connection = CreateConnection()) { string commandText; diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index e0cc496a1..f2a6586e2 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -48,11 +48,7 @@ namespace MediaBrowser.Controller.Entities.TV [IgnoreDataMember] public override Guid? DisplayParentId { - get - { - var series = Series; - return series == null ? ParentId : series.Id; - } + get { return SeriesId; } } [IgnoreDataMember]