From 21077365849d29f912208c55a5ab1befc337e8c6 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 11 Jun 2016 13:10:06 -0400 Subject: [PATCH 1/6] reduce uses of mobile.activepage --- MediaBrowser.Controller/Entities/UserViewBuilder.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 3c1c086ef8..0cb8062742 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -665,6 +665,7 @@ namespace MediaBrowser.Controller.Entities query.SetUser(user); query.Limit = GetSpecialItemsLimit(); query.IncludeItemTypes = new[] { typeof(Episode).Name }; + query.ExcludeLocationTypes = new[] { LocationType.Virtual }; return _libraryManager.GetItemsResult(query); } From 96b1ddfddf43cdc4d18d1de0f49027ae6f0ea1ac Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 11 Jun 2016 13:26:35 -0400 Subject: [PATCH 2/6] update user data db --- .../Persistence/BaseSqliteRepository.cs | 6 - .../Persistence/SqliteUserDataRepository.cs | 325 +++++++++--------- 2 files changed, 159 insertions(+), 172 deletions(-) diff --git a/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs b/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs index f9c892b76a..de0c245bdb 100644 --- a/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs @@ -45,8 +45,6 @@ namespace MediaBrowser.Server.Implementations.Persistence { CheckDisposed(); - await WriteLock.WaitAsync().ConfigureAwait(false); - try { using (var cmd = connection.CreateCommand()) @@ -61,10 +59,6 @@ namespace MediaBrowser.Server.Implementations.Persistence throw; } - finally - { - WriteLock.Release(); - } } private readonly object _disposeLock = new object(); diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs index d81f4ad37b..0ce27fa5a2 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs @@ -15,12 +15,9 @@ namespace MediaBrowser.Server.Implementations.Persistence { public class SqliteUserDataRepository : BaseSqliteRepository, IUserDataRepository { - private IDbConnection _connection; - private readonly IApplicationPaths _appPaths; - public SqliteUserDataRepository(ILogManager logManager, IApplicationPaths appPaths, IDbConnector connector) : base(logManager, connector) { - _appPaths = appPaths; + DbFilePath = Path.Combine(appPaths.DataPath, "userdata_v2.db"); } /// @@ -41,11 +38,9 @@ namespace MediaBrowser.Server.Implementations.Persistence /// Task. public async Task Initialize(IDbConnector dbConnector) { - var dbFile = Path.Combine(_appPaths.DataPath, "userdata_v2.db"); - - _connection = await dbConnector.Connect(dbFile, false).ConfigureAwait(false); - - string[] queries = { + using (var connection = await CreateConnection().ConfigureAwait(false)) + { + string[] queries = { "create table if not exists userdata (key nvarchar, userId GUID, rating float null, played bit, playCount int, isFavorite bit, playbackPositionTicks bigint, lastPlayedDate datetime null)", @@ -58,10 +53,11 @@ namespace MediaBrowser.Server.Implementations.Persistence "pragma shrink_memory" }; - _connection.RunQueries(queries, Logger); + connection.RunQueries(queries, Logger); - _connection.AddColumn(Logger, "userdata", "AudioStreamIndex", "int"); - _connection.AddColumn(Logger, "userdata", "SubtitleStreamIndex", "int"); + connection.AddColumn(Logger, "userdata", "AudioStreamIndex", "int"); + connection.AddColumn(Logger, "userdata", "SubtitleStreamIndex", "int"); + } } /// @@ -123,64 +119,63 @@ namespace MediaBrowser.Server.Implementations.Persistence { cancellationToken.ThrowIfCancellationRequested(); - await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); - - IDbTransaction transaction = null; - - try + using (var connection = await CreateConnection().ConfigureAwait(false)) { - transaction = _connection.BeginTransaction(); + IDbTransaction transaction = null; - using (var cmd = _connection.CreateCommand()) + try { - cmd.CommandText = "replace into userdata (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate,@AudioStreamIndex,@SubtitleStreamIndex)"; + transaction = connection.BeginTransaction(); - cmd.Parameters.Add(cmd, "@key", DbType.String).Value = key; - cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; - cmd.Parameters.Add(cmd, "@rating", DbType.Double).Value = userData.Rating; - cmd.Parameters.Add(cmd, "@played", DbType.Boolean).Value = userData.Played; - cmd.Parameters.Add(cmd, "@playCount", DbType.Int32).Value = userData.PlayCount; - cmd.Parameters.Add(cmd, "@isFavorite", DbType.Boolean).Value = userData.IsFavorite; - cmd.Parameters.Add(cmd, "@playbackPositionTicks", DbType.Int64).Value = userData.PlaybackPositionTicks; - cmd.Parameters.Add(cmd, "@lastPlayedDate", DbType.DateTime).Value = userData.LastPlayedDate; - cmd.Parameters.Add(cmd, "@AudioStreamIndex", DbType.Int32).Value = userData.AudioStreamIndex; - cmd.Parameters.Add(cmd, "@SubtitleStreamIndex", DbType.Int32).Value = userData.SubtitleStreamIndex; + using (var cmd = connection.CreateCommand()) + { + cmd.CommandText = "replace into userdata (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate,@AudioStreamIndex,@SubtitleStreamIndex)"; - cmd.Transaction = transaction; + cmd.Parameters.Add(cmd, "@key", DbType.String).Value = key; + cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; + cmd.Parameters.Add(cmd, "@rating", DbType.Double).Value = userData.Rating; + cmd.Parameters.Add(cmd, "@played", DbType.Boolean).Value = userData.Played; + cmd.Parameters.Add(cmd, "@playCount", DbType.Int32).Value = userData.PlayCount; + cmd.Parameters.Add(cmd, "@isFavorite", DbType.Boolean).Value = userData.IsFavorite; + cmd.Parameters.Add(cmd, "@playbackPositionTicks", DbType.Int64).Value = userData.PlaybackPositionTicks; + cmd.Parameters.Add(cmd, "@lastPlayedDate", DbType.DateTime).Value = userData.LastPlayedDate; + cmd.Parameters.Add(cmd, "@AudioStreamIndex", DbType.Int32).Value = userData.AudioStreamIndex; + cmd.Parameters.Add(cmd, "@SubtitleStreamIndex", DbType.Int32).Value = userData.SubtitleStreamIndex; - cmd.ExecuteNonQuery(); + cmd.Transaction = transaction; + + cmd.ExecuteNonQuery(); + } + + transaction.Commit(); } - - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + catch (OperationCanceledException) { - transaction.Rollback(); + if (transaction != null) + { + transaction.Rollback(); + } + + throw; } - - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save user data:", e); - - if (transaction != null) + catch (Exception e) { - transaction.Rollback(); - } + Logger.ErrorException("Failed to save user data:", e); - throw; - } - finally - { - if (transaction != null) + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally { - transaction.Dispose(); + if (transaction != null) + { + transaction.Dispose(); + } } - - WriteLock.Release(); } } @@ -195,69 +190,68 @@ namespace MediaBrowser.Server.Implementations.Persistence { cancellationToken.ThrowIfCancellationRequested(); - await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); - - IDbTransaction transaction = null; - - try + using (var connection = await CreateConnection().ConfigureAwait(false)) { - transaction = _connection.BeginTransaction(); + IDbTransaction transaction = null; - foreach (var userItemData in userData) + try { - using (var cmd = _connection.CreateCommand()) + transaction = connection.BeginTransaction(); + + foreach (var userItemData in userData) { - cmd.CommandText = "replace into userdata (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate,@AudioStreamIndex,@SubtitleStreamIndex)"; + using (var cmd = connection.CreateCommand()) + { + cmd.CommandText = "replace into userdata (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate,@AudioStreamIndex,@SubtitleStreamIndex)"; - cmd.Parameters.Add(cmd, "@key", DbType.String).Value = userItemData.Key; - cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; - cmd.Parameters.Add(cmd, "@rating", DbType.Double).Value = userItemData.Rating; - cmd.Parameters.Add(cmd, "@played", DbType.Boolean).Value = userItemData.Played; - cmd.Parameters.Add(cmd, "@playCount", DbType.Int32).Value = userItemData.PlayCount; - cmd.Parameters.Add(cmd, "@isFavorite", DbType.Boolean).Value = userItemData.IsFavorite; - cmd.Parameters.Add(cmd, "@playbackPositionTicks", DbType.Int64).Value = userItemData.PlaybackPositionTicks; - cmd.Parameters.Add(cmd, "@lastPlayedDate", DbType.DateTime).Value = userItemData.LastPlayedDate; - cmd.Parameters.Add(cmd, "@AudioStreamIndex", DbType.Int32).Value = userItemData.AudioStreamIndex; - cmd.Parameters.Add(cmd, "@SubtitleStreamIndex", DbType.Int32).Value = userItemData.SubtitleStreamIndex; + cmd.Parameters.Add(cmd, "@key", DbType.String).Value = userItemData.Key; + cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; + cmd.Parameters.Add(cmd, "@rating", DbType.Double).Value = userItemData.Rating; + cmd.Parameters.Add(cmd, "@played", DbType.Boolean).Value = userItemData.Played; + cmd.Parameters.Add(cmd, "@playCount", DbType.Int32).Value = userItemData.PlayCount; + cmd.Parameters.Add(cmd, "@isFavorite", DbType.Boolean).Value = userItemData.IsFavorite; + cmd.Parameters.Add(cmd, "@playbackPositionTicks", DbType.Int64).Value = userItemData.PlaybackPositionTicks; + cmd.Parameters.Add(cmd, "@lastPlayedDate", DbType.DateTime).Value = userItemData.LastPlayedDate; + cmd.Parameters.Add(cmd, "@AudioStreamIndex", DbType.Int32).Value = userItemData.AudioStreamIndex; + cmd.Parameters.Add(cmd, "@SubtitleStreamIndex", DbType.Int32).Value = userItemData.SubtitleStreamIndex; - cmd.Transaction = transaction; + cmd.Transaction = transaction; - cmd.ExecuteNonQuery(); + cmd.ExecuteNonQuery(); + } + + cancellationToken.ThrowIfCancellationRequested(); } - cancellationToken.ThrowIfCancellationRequested(); + transaction.Commit(); } - - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + catch (OperationCanceledException) { - transaction.Rollback(); + if (transaction != null) + { + transaction.Rollback(); + } + + throw; } - - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save user data:", e); - - if (transaction != null) + catch (Exception e) { - transaction.Rollback(); - } + Logger.ErrorException("Failed to save user data:", e); - throw; - } - finally - { - if (transaction != null) + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally { - transaction.Dispose(); + if (transaction != null) + { + transaction.Dispose(); + } } - - WriteLock.Release(); } } @@ -283,22 +277,25 @@ namespace MediaBrowser.Server.Implementations.Persistence throw new ArgumentNullException("key"); } - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where key = @key and userId=@userId"; - - cmd.Parameters.Add(cmd, "@key", DbType.String).Value = key; - cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) + using (var cmd = connection.CreateCommand()) { - if (reader.Read()) - { - return ReadRow(reader); - } - } + cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where key = @key and userId=@userId"; - return null; + cmd.Parameters.Add(cmd, "@key", DbType.String).Value = key; + cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) + { + if (reader.Read()) + { + return ReadRow(reader); + } + } + + return null; + } } } @@ -313,38 +310,41 @@ namespace MediaBrowser.Server.Implementations.Persistence throw new ArgumentNullException("keys"); } - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - var index = 0; - var excludeIds = new List(); - var builder = new StringBuilder(); - foreach (var key in keys) + using (var cmd = connection.CreateCommand()) { - var paramName = "@Key" + index; - excludeIds.Add("Key =" + paramName); - cmd.Parameters.Add(cmd, paramName, DbType.String).Value = key; - builder.Append(" WHEN Key=" + paramName + " THEN " + index); - index++; - } - - var keyText = string.Join(" OR ", excludeIds.ToArray()); - - cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where userId=@userId AND (" + keyText + ") "; - - cmd.CommandText += " ORDER BY (Case " + builder + " Else " + keys.Count.ToString(CultureInfo.InvariantCulture) + " End )"; - cmd.CommandText += " LIMIT 1"; - - cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) - { - if (reader.Read()) + var index = 0; + var excludeIds = new List(); + var builder = new StringBuilder(); + foreach (var key in keys) { - return ReadRow(reader); + var paramName = "@Key" + index; + excludeIds.Add("Key =" + paramName); + cmd.Parameters.Add(cmd, paramName, DbType.String).Value = key; + builder.Append(" WHEN Key=" + paramName + " THEN " + index); + index++; } - } - return null; + var keyText = string.Join(" OR ", excludeIds.ToArray()); + + cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where userId=@userId AND (" + keyText + ") "; + + cmd.CommandText += " ORDER BY (Case " + builder + " Else " + keys.Count.ToString(CultureInfo.InvariantCulture) + " End )"; + cmd.CommandText += " LIMIT 1"; + + cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) + { + if (reader.Read()) + { + return ReadRow(reader); + } + } + + return null; + } } } @@ -360,20 +360,27 @@ namespace MediaBrowser.Server.Implementations.Persistence throw new ArgumentNullException("userId"); } - using (var cmd = _connection.CreateCommand()) + var list = new List(); + + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where userId=@userId"; - - cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + using (var cmd = connection.CreateCommand()) { - while (reader.Read()) + cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where userId=@userId"; + + cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) { - yield return ReadRow(reader); + while (reader.Read()) + { + list.Add(ReadRow(reader)); + } } } } + + return list; } /// @@ -414,19 +421,5 @@ namespace MediaBrowser.Server.Implementations.Persistence return userData; } - - protected override void CloseConnection() - { - if (_connection != null) - { - if (_connection.IsOpen()) - { - _connection.Close(); - } - - _connection.Dispose(); - _connection = null; - } - } } } \ No newline at end of file From da6e94396fb417077010d3a2e5f3282bf06234c3 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 11 Jun 2016 16:12:01 -0400 Subject: [PATCH 3/6] update connection pooling --- .../Chapters/IChapterManager.cs | 2 +- .../Persistence/IItemRepository.cs | 4 +- .../Chapters/ChapterManager.cs | 2 +- .../Activity/ActivityRepository.cs | 7 +- .../Library/LibraryManager.cs | 10 +- .../LiveTv/LiveTvManager.cs | 2 +- .../SqliteNotificationsRepository.cs | 7 +- .../Persistence/BaseSqliteRepository.cs | 12 +- .../SqliteDisplayPreferencesRepository.cs | 7 +- .../Persistence/SqliteExtensions.cs | 13 +- .../SqliteFileOrganizationRepository.cs | 7 +- .../Persistence/SqliteItemRepository.cs | 2963 +++++++++-------- .../Persistence/SqliteUserDataRepository.cs | 7 +- .../Persistence/SqliteUserRepository.cs | 3 - .../Security/AuthenticationRepository.cs | 7 +- .../Social/SharingRepository.cs | 3 - .../Sync/SyncRepository.cs | 3 - 17 files changed, 1587 insertions(+), 1472 deletions(-) diff --git a/MediaBrowser.Controller/Chapters/IChapterManager.cs b/MediaBrowser.Controller/Chapters/IChapterManager.cs index 676ef9c561..27e06fb8dd 100644 --- a/MediaBrowser.Controller/Chapters/IChapterManager.cs +++ b/MediaBrowser.Controller/Chapters/IChapterManager.cs @@ -33,7 +33,7 @@ namespace MediaBrowser.Controller.Chapters /// The chapters. /// The cancellation token. /// Task. - Task SaveChapters(string itemId, IEnumerable chapters, CancellationToken cancellationToken); + Task SaveChapters(string itemId, List chapters, CancellationToken cancellationToken); /// /// Searches the specified video. diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index 7bcc36958a..80a6e4042f 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -81,7 +81,7 @@ namespace MediaBrowser.Controller.Persistence /// The chapters. /// The cancellation token. /// Task. - Task SaveChapters(Guid id, IEnumerable chapters, CancellationToken cancellationToken); + Task SaveChapters(Guid id, List chapters, CancellationToken cancellationToken); /// /// Gets the media streams. @@ -97,7 +97,7 @@ namespace MediaBrowser.Controller.Persistence /// The streams. /// The cancellation token. /// Task. - Task SaveMediaStreams(Guid id, IEnumerable streams, CancellationToken cancellationToken); + Task SaveMediaStreams(Guid id, List streams, CancellationToken cancellationToken); /// /// Gets the item ids. diff --git a/MediaBrowser.Providers/Chapters/ChapterManager.cs b/MediaBrowser.Providers/Chapters/ChapterManager.cs index 6e2cd77eb3..88811c850d 100644 --- a/MediaBrowser.Providers/Chapters/ChapterManager.cs +++ b/MediaBrowser.Providers/Chapters/ChapterManager.cs @@ -259,7 +259,7 @@ namespace MediaBrowser.Providers.Chapters return _itemRepo.GetChapters(new Guid(itemId)); } - public Task SaveChapters(string itemId, IEnumerable chapters, CancellationToken cancellationToken) + public Task SaveChapters(string itemId, List chapters, CancellationToken cancellationToken) { return _itemRepo.SaveChapters(new Guid(itemId), chapters, cancellationToken); } diff --git a/MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs b/MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs index d6ae381e9d..c992def39d 100644 --- a/MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs +++ b/MediaBrowser.Server.Implementations/Activity/ActivityRepository.cs @@ -30,12 +30,7 @@ namespace MediaBrowser.Server.Implementations.Activity string[] queries = { "create table if not exists ActivityLogEntries (Id GUID PRIMARY KEY, Name TEXT, Overview TEXT, ShortOverview TEXT, Type TEXT, ItemId TEXT, UserId TEXT, DateCreated DATETIME, LogSeverity TEXT)", - "create index if not exists idx_ActivityLogEntries on ActivityLogEntries(Id)", - - //pragmas - "pragma temp_store = memory", - - "pragma shrink_memory" + "create index if not exists idx_ActivityLogEntries on ActivityLogEntries(Id)" }; connection.RunQueries(queries, Logger); diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 503fb1aa74..2483ec93e8 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1309,7 +1309,15 @@ namespace MediaBrowser.Server.Implementations.Library AddUserToQuery(query, query.User); } - return ItemRepository.GetItems(query); + if (query.EnableTotalRecordCount) + { + return ItemRepository.GetItems(query); + } + + return new QueryResult + { + Items = ItemRepository.GetItemList(query).ToArray() + }; } public List GetItemIds(InternalItemsQuery query) diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index d7491d2de1..171ed824e8 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -952,7 +952,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv if (query.Limit.HasValue) { - internalQuery.Limit = Math.Max(query.Limit.Value * 5, 300); + internalQuery.Limit = Math.Max(query.Limit.Value * 5, 200); } if (query.HasAired.HasValue) diff --git a/MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs b/MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs index 6c3bc3050e..be8c6d48d6 100644 --- a/MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs +++ b/MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs @@ -32,12 +32,7 @@ namespace MediaBrowser.Server.Implementations.Notifications "create table if not exists Notifications (Id GUID NOT NULL, UserId GUID NOT NULL, Date DATETIME NOT NULL, Name TEXT NOT NULL, Description TEXT, Url TEXT, Level TEXT NOT NULL, IsRead BOOLEAN NOT NULL, Category TEXT NOT NULL, RelatedId TEXT, PRIMARY KEY (Id, UserId))", "create index if not exists idx_Notifications1 on Notifications(Id)", - "create index if not exists idx_Notifications2 on Notifications(UserId)", - - //pragmas - "pragma temp_store = memory", - - "pragma shrink_memory" + "create index if not exists idx_Notifications2 on Notifications(UserId)" }; connection.RunQueries(queries, Logger); diff --git a/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs b/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs index de0c245bdb..c6e7952294 100644 --- a/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs @@ -20,9 +20,17 @@ namespace MediaBrowser.Server.Implementations.Persistence Logger = logManager.GetLogger(GetType().Name); } - protected Task CreateConnection(bool isReadOnly = false) + protected virtual async Task CreateConnection(bool isReadOnly = false) { - return DbConnector.Connect(DbFilePath, false, true); + var connection = await DbConnector.Connect(DbFilePath, false, true).ConfigureAwait(false); + + connection.RunQueries(new [] + { + "pragma temp_store = memory" + + }, Logger); + + return connection; } private bool _disposed; diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs index 1a6a88ebe2..40970dbe4d 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs @@ -53,12 +53,7 @@ namespace MediaBrowser.Server.Implementations.Persistence string[] queries = { "create table if not exists userdisplaypreferences (id GUID, userId GUID, client text, data BLOB)", - "create unique index if not exists userdisplaypreferencesindex on userdisplaypreferences (id, userId, client)", - - //pragmas - "pragma temp_store = memory", - - "pragma shrink_memory" + "create unique index if not exists userdisplaypreferencesindex on userdisplaypreferences (id, userId, client)" }; connection.RunQueries(queries, Logger); diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs index cc9e3ebccf..0a76381e12 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs @@ -26,8 +26,6 @@ namespace MediaBrowser.Server.Implementations.Persistence throw new ArgumentNullException("dbPath"); } - logger.Info("Sqlite {0} opening {1}", SQLiteConnection.SQLiteVersion, dbPath); - var connectionstr = new SQLiteConnectionStringBuilder { PageSize = 4096, @@ -39,7 +37,16 @@ namespace MediaBrowser.Server.Implementations.Persistence ReadOnly = isReadOnly }; - var connection = new SQLiteConnection(connectionstr.ConnectionString); + var connectionString = connectionstr.ConnectionString; + + if (enablePooling) + { + connectionString += ";Max Pool Size=100"; + } + + //logger.Info("Sqlite {0} opening {1}", SQLiteConnection.SQLiteVersion, connectionString); + + var connection = new SQLiteConnection(connectionString); await connection.OpenAsync().ConfigureAwait(false); diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs index 8a4ba6460d..d7e8afdd4c 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs @@ -44,12 +44,7 @@ namespace MediaBrowser.Server.Implementations.Persistence string[] queries = { "create table if not exists FileOrganizerResults (ResultId GUID PRIMARY KEY, OriginalPath TEXT, TargetPath TEXT, FileLength INT, OrganizationDate datetime, Status TEXT, OrganizationType TEXT, StatusMessage TEXT, ExtractedName TEXT, ExtractedYear int null, ExtractedSeasonNumber int null, ExtractedEpisodeNumber int null, ExtractedEndingEpisodeNumber, DuplicatePaths TEXT int null)", - "create index if not exists idx_FileOrganizerResults on FileOrganizerResults(ResultId)", - - //pragmas - "pragma temp_store = memory", - - "pragma shrink_memory" + "create index if not exists idx_FileOrganizerResults on FileOrganizerResults(ResultId)" }; _connection.RunQueries(queries, Logger); diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 9bfdd879da..0eb56a1fc4 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -31,8 +31,6 @@ namespace MediaBrowser.Server.Implementations.Persistence /// public class SqliteItemRepository : BaseSqliteRepository, IItemRepository { - private IDbConnection _connection; - private readonly TypeMapper _typeMapper = new TypeMapper(); /// @@ -58,42 +56,8 @@ namespace MediaBrowser.Server.Implementations.Persistence /// private readonly IServerConfigurationManager _config; - /// - /// The _save item command - /// - private IDbCommand _saveItemCommand; - private readonly string _criticReviewsPath; - private IDbCommand _deleteItemCommand; - - private IDbCommand _deletePeopleCommand; - private IDbCommand _savePersonCommand; - - private IDbCommand _deleteChaptersCommand; - private IDbCommand _saveChapterCommand; - - private IDbCommand _deleteStreamsCommand; - private IDbCommand _saveStreamCommand; - - private IDbCommand _deleteAncestorsCommand; - private IDbCommand _saveAncestorCommand; - - private IDbCommand _deleteUserDataKeysCommand; - private IDbCommand _saveUserDataKeysCommand; - - private IDbCommand _deleteItemValuesCommand; - private IDbCommand _saveItemValuesCommand; - - private IDbCommand _deleteProviderIdsCommand; - private IDbCommand _saveProviderIdsCommand; - - private IDbCommand _deleteImagesCommand; - private IDbCommand _saveImagesCommand; - - private IDbCommand _updateInheritedRatingCommand; - private IDbCommand _updateInheritedTagsCommand; - public const int LatestSchemaVersion = 89; /// @@ -115,6 +79,22 @@ namespace MediaBrowser.Server.Implementations.Persistence _jsonSerializer = jsonSerializer; _criticReviewsPath = Path.Combine(_config.ApplicationPaths.DataPath, "critic-reviews"); + DbFilePath = Path.Combine(_config.ApplicationPaths.DataPath, "library.db"); + } + + protected override async Task CreateConnection(bool isReadOnly = false) + { + var connection = await DbConnector.Connect(DbFilePath, false, true, 20000).ConfigureAwait(false); + + //AttachUserDataDb(connection); + + //connection.RunQueries(new [] + //{ + // "pragma locking_mode=EXCLUSIVE" + + //}, Logger); + + return connection; } private const string ChaptersTableName = "Chapters2"; @@ -125,14 +105,12 @@ namespace MediaBrowser.Server.Implementations.Persistence /// Task. public async Task Initialize(IDbConnector dbConnector) { - var dbFile = Path.Combine(_config.ApplicationPaths.DataPath, "library.db"); + using (var connection = await CreateConnection().ConfigureAwait(false)) + { + var 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, PRIMARY KEY (ItemId, StreamIndex))"; - _connection = await dbConnector.Connect(dbFile, false, false, 6000).ConfigureAwait(false); - - var 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, PRIMARY KEY (ItemId, StreamIndex))"; - - string[] queries = { + string[] queries = { "create table if not exists TypedBaseItems (guid GUID primary key, type TEXT, data BLOB, ParentId GUID, Path TEXT)", "create index if not exists idx_PathTypedBaseItems on TypedBaseItems(Path)", @@ -165,113 +143,113 @@ namespace MediaBrowser.Server.Implementations.Persistence createMediaStreamsTableCommand, "create index if not exists idx_mediastreams1 on mediastreams(ItemId)", - - //pragmas - "pragma temp_store = memory", - - "pragma shrink_memory" + }; - _connection.RunQueries(queries, Logger); + connection.RunQueries(queries, Logger); - _connection.AddColumn(Logger, "AncestorIds", "AncestorIdText", "Text"); + connection.AddColumn(Logger, "AncestorIds", "AncestorIdText", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "Path", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "StartDate", "DATETIME"); - _connection.AddColumn(Logger, "TypedBaseItems", "EndDate", "DATETIME"); - _connection.AddColumn(Logger, "TypedBaseItems", "ChannelId", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "IsMovie", "BIT"); - _connection.AddColumn(Logger, "TypedBaseItems", "IsSports", "BIT"); - _connection.AddColumn(Logger, "TypedBaseItems", "IsKids", "BIT"); - _connection.AddColumn(Logger, "TypedBaseItems", "CommunityRating", "Float"); - _connection.AddColumn(Logger, "TypedBaseItems", "CustomRating", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "IndexNumber", "INT"); - _connection.AddColumn(Logger, "TypedBaseItems", "IsLocked", "BIT"); - _connection.AddColumn(Logger, "TypedBaseItems", "Name", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "OfficialRating", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "Path", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "StartDate", "DATETIME"); + connection.AddColumn(Logger, "TypedBaseItems", "EndDate", "DATETIME"); + connection.AddColumn(Logger, "TypedBaseItems", "ChannelId", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "IsMovie", "BIT"); + connection.AddColumn(Logger, "TypedBaseItems", "IsSports", "BIT"); + connection.AddColumn(Logger, "TypedBaseItems", "IsKids", "BIT"); + connection.AddColumn(Logger, "TypedBaseItems", "CommunityRating", "Float"); + connection.AddColumn(Logger, "TypedBaseItems", "CustomRating", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "IndexNumber", "INT"); + connection.AddColumn(Logger, "TypedBaseItems", "IsLocked", "BIT"); + connection.AddColumn(Logger, "TypedBaseItems", "Name", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "OfficialRating", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "MediaType", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "Overview", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "ParentIndexNumber", "INT"); - _connection.AddColumn(Logger, "TypedBaseItems", "PremiereDate", "DATETIME"); - _connection.AddColumn(Logger, "TypedBaseItems", "ProductionYear", "INT"); - _connection.AddColumn(Logger, "TypedBaseItems", "ParentId", "GUID"); - _connection.AddColumn(Logger, "TypedBaseItems", "Genres", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "ParentalRatingValue", "INT"); - _connection.AddColumn(Logger, "TypedBaseItems", "SchemaVersion", "INT"); - _connection.AddColumn(Logger, "TypedBaseItems", "SortName", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "RunTimeTicks", "BIGINT"); + connection.AddColumn(Logger, "TypedBaseItems", "MediaType", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "Overview", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "ParentIndexNumber", "INT"); + connection.AddColumn(Logger, "TypedBaseItems", "PremiereDate", "DATETIME"); + connection.AddColumn(Logger, "TypedBaseItems", "ProductionYear", "INT"); + connection.AddColumn(Logger, "TypedBaseItems", "ParentId", "GUID"); + connection.AddColumn(Logger, "TypedBaseItems", "Genres", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "ParentalRatingValue", "INT"); + connection.AddColumn(Logger, "TypedBaseItems", "SchemaVersion", "INT"); + connection.AddColumn(Logger, "TypedBaseItems", "SortName", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "RunTimeTicks", "BIGINT"); - _connection.AddColumn(Logger, "TypedBaseItems", "OfficialRatingDescription", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "HomePageUrl", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "VoteCount", "INT"); - _connection.AddColumn(Logger, "TypedBaseItems", "DisplayMediaType", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "DateCreated", "DATETIME"); - _connection.AddColumn(Logger, "TypedBaseItems", "DateModified", "DATETIME"); + connection.AddColumn(Logger, "TypedBaseItems", "OfficialRatingDescription", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "HomePageUrl", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "VoteCount", "INT"); + connection.AddColumn(Logger, "TypedBaseItems", "DisplayMediaType", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "DateCreated", "DATETIME"); + connection.AddColumn(Logger, "TypedBaseItems", "DateModified", "DATETIME"); - _connection.AddColumn(Logger, "TypedBaseItems", "ForcedSortName", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "IsOffline", "BIT"); - _connection.AddColumn(Logger, "TypedBaseItems", "LocationType", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "ForcedSortName", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "IsOffline", "BIT"); + connection.AddColumn(Logger, "TypedBaseItems", "LocationType", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "IsSeries", "BIT"); - _connection.AddColumn(Logger, "TypedBaseItems", "IsLive", "BIT"); - _connection.AddColumn(Logger, "TypedBaseItems", "IsNews", "BIT"); - _connection.AddColumn(Logger, "TypedBaseItems", "IsPremiere", "BIT"); + connection.AddColumn(Logger, "TypedBaseItems", "IsSeries", "BIT"); + connection.AddColumn(Logger, "TypedBaseItems", "IsLive", "BIT"); + connection.AddColumn(Logger, "TypedBaseItems", "IsNews", "BIT"); + connection.AddColumn(Logger, "TypedBaseItems", "IsPremiere", "BIT"); - _connection.AddColumn(Logger, "TypedBaseItems", "EpisodeTitle", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "IsRepeat", "BIT"); + connection.AddColumn(Logger, "TypedBaseItems", "EpisodeTitle", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "IsRepeat", "BIT"); - _connection.AddColumn(Logger, "TypedBaseItems", "PreferredMetadataLanguage", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "PreferredMetadataCountryCode", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "IsHD", "BIT"); - _connection.AddColumn(Logger, "TypedBaseItems", "ExternalEtag", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "DateLastRefreshed", "DATETIME"); + connection.AddColumn(Logger, "TypedBaseItems", "PreferredMetadataLanguage", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "PreferredMetadataCountryCode", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "IsHD", "BIT"); + connection.AddColumn(Logger, "TypedBaseItems", "ExternalEtag", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "DateLastRefreshed", "DATETIME"); - _connection.AddColumn(Logger, "TypedBaseItems", "DateLastSaved", "DATETIME"); - _connection.AddColumn(Logger, "TypedBaseItems", "IsInMixedFolder", "BIT"); - _connection.AddColumn(Logger, "TypedBaseItems", "LockedFields", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "Studios", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "Audio", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "ExternalServiceId", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "Tags", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "IsFolder", "BIT"); - _connection.AddColumn(Logger, "TypedBaseItems", "InheritedParentalRatingValue", "INT"); - _connection.AddColumn(Logger, "TypedBaseItems", "UnratedType", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "TopParentId", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "IsItemByName", "BIT"); - _connection.AddColumn(Logger, "TypedBaseItems", "SourceType", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "TrailerTypes", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "CriticRating", "Float"); - _connection.AddColumn(Logger, "TypedBaseItems", "CriticRatingSummary", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "DateModifiedDuringLastRefresh", "DATETIME"); - _connection.AddColumn(Logger, "TypedBaseItems", "InheritedTags", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "CleanName", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "PresentationUniqueKey", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "SlugName", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "OriginalTitle", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "PrimaryVersionId", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "DateLastMediaAdded", "DATETIME"); - _connection.AddColumn(Logger, "TypedBaseItems", "Album", "Text"); - _connection.AddColumn(Logger, "TypedBaseItems", "IsVirtualItem", "BIT"); - _connection.AddColumn(Logger, "TypedBaseItems", "SeriesName", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "DateLastSaved", "DATETIME"); + connection.AddColumn(Logger, "TypedBaseItems", "IsInMixedFolder", "BIT"); + connection.AddColumn(Logger, "TypedBaseItems", "LockedFields", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "Studios", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "Audio", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "ExternalServiceId", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "Tags", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "IsFolder", "BIT"); + connection.AddColumn(Logger, "TypedBaseItems", "InheritedParentalRatingValue", "INT"); + connection.AddColumn(Logger, "TypedBaseItems", "UnratedType", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "TopParentId", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "IsItemByName", "BIT"); + connection.AddColumn(Logger, "TypedBaseItems", "SourceType", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "TrailerTypes", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "CriticRating", "Float"); + connection.AddColumn(Logger, "TypedBaseItems", "CriticRatingSummary", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "DateModifiedDuringLastRefresh", "DATETIME"); + connection.AddColumn(Logger, "TypedBaseItems", "InheritedTags", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "CleanName", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "PresentationUniqueKey", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "SlugName", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "OriginalTitle", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "PrimaryVersionId", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "DateLastMediaAdded", "DATETIME"); + connection.AddColumn(Logger, "TypedBaseItems", "Album", "Text"); + connection.AddColumn(Logger, "TypedBaseItems", "IsVirtualItem", "BIT"); + connection.AddColumn(Logger, "TypedBaseItems", "SeriesName", "Text"); - _connection.AddColumn(Logger, "UserDataKeys", "Priority", "INT"); + connection.AddColumn(Logger, "UserDataKeys", "Priority", "INT"); - string[] postQueries = - { + string[] postQueries = + { "create index if not exists idx_PresentationUniqueKey on TypedBaseItems(PresentationUniqueKey)", "create index if not exists idx_Type on TypedBaseItems(Type)", "create index if not exists idx_TopParentId on TypedBaseItems(TopParentId)", "create index if not exists idx_TypeTopParentId on TypedBaseItems(Type,TopParentId)" - }; + }; - _connection.RunQueries(postQueries, Logger); + connection.RunQueries(postQueries, Logger); - PrepareStatements(); + new MediaStreamColumns(connection, Logger).AddColumns(); - new MediaStreamColumns(_connection, Logger).AddColumns(); + //AttachUserDataDb(connection); + } + } - DataExtensions.Attach(_connection, Path.Combine(_config.ApplicationPaths.DataPath, "userdata_v2.db"), "UserDataDb"); + private void AttachUserDataDb(IDbConnection connection) + { + DataExtensions.Attach(connection, Path.Combine(_config.ApplicationPaths.DataPath, "userdata_v2.db"), "UserDataDb" + Guid.NewGuid().ToString("N")); } private readonly string[] _retriveItemColumns = @@ -373,220 +351,6 @@ namespace MediaBrowser.Server.Implementations.Persistence "CodecTimeBase" }; - /// - /// Prepares the statements. - /// - private void PrepareStatements() - { - var saveColumns = new List - { - "guid", - "type", - "data", - "Path", - "StartDate", - "EndDate", - "ChannelId", - "IsKids", - "IsMovie", - "IsSports", - "IsSeries", - "IsLive", - "IsNews", - "IsPremiere", - "EpisodeTitle", - "IsRepeat", - "CommunityRating", - "CustomRating", - "IndexNumber", - "IsLocked", - "Name", - "OfficialRating", - "MediaType", - "Overview", - "ParentIndexNumber", - "PremiereDate", - "ProductionYear", - "ParentId", - "Genres", - "ParentalRatingValue", - "InheritedParentalRatingValue", - "SchemaVersion", - "SortName", - "RunTimeTicks", - "OfficialRatingDescription", - "HomePageUrl", - "VoteCount", - "DisplayMediaType", - "DateCreated", - "DateModified", - "ForcedSortName", - "IsOffline", - "LocationType", - "PreferredMetadataLanguage", - "PreferredMetadataCountryCode", - "IsHD", - "ExternalEtag", - "DateLastRefreshed", - "DateLastSaved", - "IsInMixedFolder", - "LockedFields", - "Studios", - "Audio", - "ExternalServiceId", - "Tags", - "IsFolder", - "UnratedType", - "TopParentId", - "IsItemByName", - "SourceType", - "TrailerTypes", - "CriticRating", - "CriticRatingSummary", - "DateModifiedDuringLastRefresh", - "InheritedTags", - "CleanName", - "PresentationUniqueKey", - "SlugName", - "OriginalTitle", - "PrimaryVersionId", - "DateLastMediaAdded", - "Album", - "IsVirtualItem", - "SeriesName" - }; - _saveItemCommand = _connection.CreateCommand(); - _saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values ("; - - for (var i = 1; i <= saveColumns.Count; i++) - { - if (i > 1) - { - _saveItemCommand.CommandText += ","; - } - _saveItemCommand.CommandText += "@" + i.ToString(CultureInfo.InvariantCulture); - - _saveItemCommand.Parameters.Add(_saveItemCommand, "@" + i.ToString(CultureInfo.InvariantCulture)); - } - _saveItemCommand.CommandText += ")"; - - _deleteItemCommand = _connection.CreateCommand(); - _deleteItemCommand.CommandText = "delete from TypedBaseItems where guid=@Id"; - _deleteItemCommand.Parameters.Add(_deleteItemCommand, "@Id"); - - // People - _deletePeopleCommand = _connection.CreateCommand(); - _deletePeopleCommand.CommandText = "delete from People where ItemId=@Id"; - _deletePeopleCommand.Parameters.Add(_deletePeopleCommand, "@Id"); - - _savePersonCommand = _connection.CreateCommand(); - _savePersonCommand.CommandText = "insert into People (ItemId, Name, Role, PersonType, SortOrder, ListOrder) values (@ItemId, @Name, @Role, @PersonType, @SortOrder, @ListOrder)"; - _savePersonCommand.Parameters.Add(_savePersonCommand, "@ItemId"); - _savePersonCommand.Parameters.Add(_savePersonCommand, "@Name"); - _savePersonCommand.Parameters.Add(_savePersonCommand, "@Role"); - _savePersonCommand.Parameters.Add(_savePersonCommand, "@PersonType"); - _savePersonCommand.Parameters.Add(_savePersonCommand, "@SortOrder"); - _savePersonCommand.Parameters.Add(_savePersonCommand, "@ListOrder"); - - // Ancestors - _deleteAncestorsCommand = _connection.CreateCommand(); - _deleteAncestorsCommand.CommandText = "delete from AncestorIds where ItemId=@Id"; - _deleteAncestorsCommand.Parameters.Add(_deleteAncestorsCommand, "@Id"); - - _saveAncestorCommand = _connection.CreateCommand(); - _saveAncestorCommand.CommandText = "insert into AncestorIds (ItemId, AncestorId, AncestorIdText) values (@ItemId, @AncestorId, @AncestorIdText)"; - _saveAncestorCommand.Parameters.Add(_saveAncestorCommand, "@ItemId"); - _saveAncestorCommand.Parameters.Add(_saveAncestorCommand, "@AncestorId"); - _saveAncestorCommand.Parameters.Add(_saveAncestorCommand, "@AncestorIdText"); - - // Chapters - _deleteChaptersCommand = _connection.CreateCommand(); - _deleteChaptersCommand.CommandText = "delete from " + ChaptersTableName + " where ItemId=@ItemId"; - _deleteChaptersCommand.Parameters.Add(_deleteChaptersCommand, "@ItemId"); - - _saveChapterCommand = _connection.CreateCommand(); - _saveChapterCommand.CommandText = "replace into " + ChaptersTableName + " (ItemId, ChapterIndex, StartPositionTicks, Name, ImagePath) values (@ItemId, @ChapterIndex, @StartPositionTicks, @Name, @ImagePath)"; - - _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@ItemId"); - _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@ChapterIndex"); - _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@StartPositionTicks"); - _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@Name"); - _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@ImagePath"); - - // MediaStreams - _deleteStreamsCommand = _connection.CreateCommand(); - _deleteStreamsCommand.CommandText = "delete from mediastreams where ItemId=@ItemId"; - _deleteStreamsCommand.Parameters.Add(_deleteStreamsCommand, "@ItemId"); - - _saveStreamCommand = _connection.CreateCommand(); - - _saveStreamCommand.CommandText = string.Format("replace into mediastreams ({0}) values ({1})", - string.Join(",", _mediaStreamSaveColumns), - string.Join(",", _mediaStreamSaveColumns.Select(i => "@" + i).ToArray())); - - foreach (var col in _mediaStreamSaveColumns) - { - _saveStreamCommand.Parameters.Add(_saveStreamCommand, "@" + col); - } - - _updateInheritedRatingCommand = _connection.CreateCommand(); - _updateInheritedRatingCommand.CommandText = "Update TypedBaseItems set InheritedParentalRatingValue=@InheritedParentalRatingValue where Guid=@Guid"; - _updateInheritedRatingCommand.Parameters.Add(_updateInheritedRatingCommand, "@Guid"); - _updateInheritedRatingCommand.Parameters.Add(_updateInheritedRatingCommand, "@InheritedParentalRatingValue"); - - _updateInheritedTagsCommand = _connection.CreateCommand(); - _updateInheritedTagsCommand.CommandText = "Update TypedBaseItems set InheritedTags=@InheritedTags where Guid=@Guid"; - _updateInheritedTagsCommand.Parameters.Add(_updateInheritedTagsCommand, "@Guid"); - _updateInheritedTagsCommand.Parameters.Add(_updateInheritedTagsCommand, "@InheritedTags"); - - // user data - _deleteUserDataKeysCommand = _connection.CreateCommand(); - _deleteUserDataKeysCommand.CommandText = "delete from UserDataKeys where ItemId=@Id"; - _deleteUserDataKeysCommand.Parameters.Add(_deleteUserDataKeysCommand, "@Id"); - - _saveUserDataKeysCommand = _connection.CreateCommand(); - _saveUserDataKeysCommand.CommandText = "insert into UserDataKeys (ItemId, UserDataKey, Priority) values (@ItemId, @UserDataKey, @Priority)"; - _saveUserDataKeysCommand.Parameters.Add(_saveUserDataKeysCommand, "@ItemId"); - _saveUserDataKeysCommand.Parameters.Add(_saveUserDataKeysCommand, "@UserDataKey"); - _saveUserDataKeysCommand.Parameters.Add(_saveUserDataKeysCommand, "@Priority"); - - // item values - _deleteItemValuesCommand = _connection.CreateCommand(); - _deleteItemValuesCommand.CommandText = "delete from ItemValues where ItemId=@Id"; - _deleteItemValuesCommand.Parameters.Add(_deleteItemValuesCommand, "@Id"); - - _saveItemValuesCommand = _connection.CreateCommand(); - _saveItemValuesCommand.CommandText = "insert into ItemValues (ItemId, Type, Value) values (@ItemId, @Type, @Value)"; - _saveItemValuesCommand.Parameters.Add(_saveItemValuesCommand, "@ItemId"); - _saveItemValuesCommand.Parameters.Add(_saveItemValuesCommand, "@Type"); - _saveItemValuesCommand.Parameters.Add(_saveItemValuesCommand, "@Value"); - - // provider ids - _deleteProviderIdsCommand = _connection.CreateCommand(); - _deleteProviderIdsCommand.CommandText = "delete from ProviderIds where ItemId=@Id"; - _deleteProviderIdsCommand.Parameters.Add(_deleteProviderIdsCommand, "@Id"); - - _saveProviderIdsCommand = _connection.CreateCommand(); - _saveProviderIdsCommand.CommandText = "insert into ProviderIds (ItemId, Name, Value) values (@ItemId, @Name, @Value)"; - _saveProviderIdsCommand.Parameters.Add(_saveProviderIdsCommand, "@ItemId"); - _saveProviderIdsCommand.Parameters.Add(_saveProviderIdsCommand, "@Name"); - _saveProviderIdsCommand.Parameters.Add(_saveProviderIdsCommand, "@Value"); - - // images - _deleteImagesCommand = _connection.CreateCommand(); - _deleteImagesCommand.CommandText = "delete from Images where ItemId=@Id"; - _deleteImagesCommand.Parameters.Add(_deleteImagesCommand, "@Id"); - - _saveImagesCommand = _connection.CreateCommand(); - _saveImagesCommand.CommandText = "insert into Images (ItemId, ImageType, Path, DateModified, IsPlaceHolder, SortOrder) values (@ItemId, @ImageType, @Path, @DateModified, @IsPlaceHolder, @SortOrder)"; - _saveImagesCommand.Parameters.Add(_saveImagesCommand, "@ItemId"); - _saveImagesCommand.Parameters.Add(_saveImagesCommand, "@ImageType"); - _saveImagesCommand.Parameters.Add(_saveImagesCommand, "@Path"); - _saveImagesCommand.Parameters.Add(_saveImagesCommand, "@DateModified"); - _saveImagesCommand.Parameters.Add(_saveImagesCommand, "@IsPlaceHolder"); - _saveImagesCommand.Parameters.Add(_saveImagesCommand, "@SortOrder"); - } - /// /// Save a standard item in the repo /// @@ -626,314 +390,408 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); - await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); - - IDbTransaction transaction = null; - - try + using (var connection = await CreateConnection().ConfigureAwait(false)) { - transaction = _connection.BeginTransaction(); + IDbTransaction transaction = null; - foreach (var item in items) + try { - cancellationToken.ThrowIfCancellationRequested(); + transaction = connection.BeginTransaction(); - var index = 0; - - _saveItemCommand.GetParameter(index++).Value = item.Id; - _saveItemCommand.GetParameter(index++).Value = item.GetType().FullName; - _saveItemCommand.GetParameter(index++).Value = _jsonSerializer.SerializeToBytes(item); - - _saveItemCommand.GetParameter(index++).Value = item.Path; - - var hasStartDate = item as IHasStartDate; - if (hasStartDate != null) + using (var saveItemCommand = connection.CreateCommand()) { - _saveItemCommand.GetParameter(index++).Value = hasStartDate.StartDate; - } - else - { - _saveItemCommand.GetParameter(index++).Value = null; + var saveColumns = new List + { + "guid", + "type", + "data", + "Path", + "StartDate", + "EndDate", + "ChannelId", + "IsKids", + "IsMovie", + "IsSports", + "IsSeries", + "IsLive", + "IsNews", + "IsPremiere", + "EpisodeTitle", + "IsRepeat", + "CommunityRating", + "CustomRating", + "IndexNumber", + "IsLocked", + "Name", + "OfficialRating", + "MediaType", + "Overview", + "ParentIndexNumber", + "PremiereDate", + "ProductionYear", + "ParentId", + "Genres", + "ParentalRatingValue", + "InheritedParentalRatingValue", + "SchemaVersion", + "SortName", + "RunTimeTicks", + "OfficialRatingDescription", + "HomePageUrl", + "VoteCount", + "DisplayMediaType", + "DateCreated", + "DateModified", + "ForcedSortName", + "IsOffline", + "LocationType", + "PreferredMetadataLanguage", + "PreferredMetadataCountryCode", + "IsHD", + "ExternalEtag", + "DateLastRefreshed", + "DateLastSaved", + "IsInMixedFolder", + "LockedFields", + "Studios", + "Audio", + "ExternalServiceId", + "Tags", + "IsFolder", + "UnratedType", + "TopParentId", + "IsItemByName", + "SourceType", + "TrailerTypes", + "CriticRating", + "CriticRatingSummary", + "DateModifiedDuringLastRefresh", + "InheritedTags", + "CleanName", + "PresentationUniqueKey", + "SlugName", + "OriginalTitle", + "PrimaryVersionId", + "DateLastMediaAdded", + "Album", + "IsVirtualItem", + "SeriesName" + }; + + saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values ("; + + for (var i = 1; i <= saveColumns.Count; i++) + { + if (i > 1) + { + saveItemCommand.CommandText += ","; + } + saveItemCommand.CommandText += "@" + i.ToString(CultureInfo.InvariantCulture); + + saveItemCommand.Parameters.Add(saveItemCommand, "@" + i.ToString(CultureInfo.InvariantCulture)); + } + saveItemCommand.CommandText += ")"; + + foreach (var item in items) + { + cancellationToken.ThrowIfCancellationRequested(); + + var index = 0; + + saveItemCommand.GetParameter(index++).Value = item.Id; + saveItemCommand.GetParameter(index++).Value = item.GetType().FullName; + saveItemCommand.GetParameter(index++).Value = _jsonSerializer.SerializeToBytes(item); + + saveItemCommand.GetParameter(index++).Value = item.Path; + + var hasStartDate = item as IHasStartDate; + if (hasStartDate != null) + { + saveItemCommand.GetParameter(index++).Value = hasStartDate.StartDate; + } + else + { + saveItemCommand.GetParameter(index++).Value = null; + } + + saveItemCommand.GetParameter(index++).Value = item.EndDate; + saveItemCommand.GetParameter(index++).Value = item.ChannelId; + + var hasProgramAttributes = item as IHasProgramAttributes; + if (hasProgramAttributes != null) + { + saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsKids; + saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsMovie; + saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsSports; + saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsSeries; + saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsLive; + saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsNews; + saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsPremiere; + saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.EpisodeTitle; + saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsRepeat; + } + else + { + saveItemCommand.GetParameter(index++).Value = null; + saveItemCommand.GetParameter(index++).Value = null; + saveItemCommand.GetParameter(index++).Value = null; + saveItemCommand.GetParameter(index++).Value = null; + saveItemCommand.GetParameter(index++).Value = null; + saveItemCommand.GetParameter(index++).Value = null; + saveItemCommand.GetParameter(index++).Value = null; + saveItemCommand.GetParameter(index++).Value = null; + saveItemCommand.GetParameter(index++).Value = null; + } + + saveItemCommand.GetParameter(index++).Value = item.CommunityRating; + saveItemCommand.GetParameter(index++).Value = item.CustomRating; + + saveItemCommand.GetParameter(index++).Value = item.IndexNumber; + saveItemCommand.GetParameter(index++).Value = item.IsLocked; + + saveItemCommand.GetParameter(index++).Value = item.Name; + saveItemCommand.GetParameter(index++).Value = item.OfficialRating; + + saveItemCommand.GetParameter(index++).Value = item.MediaType; + saveItemCommand.GetParameter(index++).Value = item.Overview; + saveItemCommand.GetParameter(index++).Value = item.ParentIndexNumber; + saveItemCommand.GetParameter(index++).Value = item.PremiereDate; + saveItemCommand.GetParameter(index++).Value = item.ProductionYear; + + if (item.ParentId == Guid.Empty) + { + saveItemCommand.GetParameter(index++).Value = null; + } + else + { + saveItemCommand.GetParameter(index++).Value = item.ParentId; + } + + saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Genres.ToArray()); + saveItemCommand.GetParameter(index++).Value = item.GetParentalRatingValue() ?? 0; + saveItemCommand.GetParameter(index++).Value = item.GetInheritedParentalRatingValue() ?? 0; + + saveItemCommand.GetParameter(index++).Value = LatestSchemaVersion; + saveItemCommand.GetParameter(index++).Value = item.SortName; + saveItemCommand.GetParameter(index++).Value = item.RunTimeTicks; + + saveItemCommand.GetParameter(index++).Value = item.OfficialRatingDescription; + saveItemCommand.GetParameter(index++).Value = item.HomePageUrl; + saveItemCommand.GetParameter(index++).Value = item.VoteCount; + saveItemCommand.GetParameter(index++).Value = item.DisplayMediaType; + saveItemCommand.GetParameter(index++).Value = item.DateCreated; + saveItemCommand.GetParameter(index++).Value = item.DateModified; + + saveItemCommand.GetParameter(index++).Value = item.ForcedSortName; + saveItemCommand.GetParameter(index++).Value = item.IsOffline; + saveItemCommand.GetParameter(index++).Value = item.LocationType.ToString(); + + saveItemCommand.GetParameter(index++).Value = item.PreferredMetadataLanguage; + saveItemCommand.GetParameter(index++).Value = item.PreferredMetadataCountryCode; + saveItemCommand.GetParameter(index++).Value = item.IsHD; + saveItemCommand.GetParameter(index++).Value = item.ExternalEtag; + + if (item.DateLastRefreshed == default(DateTime)) + { + saveItemCommand.GetParameter(index++).Value = null; + } + else + { + saveItemCommand.GetParameter(index++).Value = item.DateLastRefreshed; + } + + if (item.DateLastSaved == default(DateTime)) + { + saveItemCommand.GetParameter(index++).Value = null; + } + else + { + saveItemCommand.GetParameter(index++).Value = item.DateLastSaved; + } + + saveItemCommand.GetParameter(index++).Value = item.IsInMixedFolder; + saveItemCommand.GetParameter(index++).Value = string.Join("|", item.LockedFields.Select(i => i.ToString()).ToArray()); + saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Studios.ToArray()); + + if (item.Audio.HasValue) + { + saveItemCommand.GetParameter(index++).Value = item.Audio.Value.ToString(); + } + else + { + saveItemCommand.GetParameter(index++).Value = null; + } + + saveItemCommand.GetParameter(index++).Value = item.ServiceName; + + if (item.Tags.Count > 0) + { + saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Tags.ToArray()); + } + else + { + saveItemCommand.GetParameter(index++).Value = null; + } + + saveItemCommand.GetParameter(index++).Value = item.IsFolder; + + saveItemCommand.GetParameter(index++).Value = item.GetBlockUnratedType().ToString(); + + var topParent = item.GetTopParent(); + if (topParent != null) + { + //Logger.Debug("Item {0} has top parent {1}", item.Id, topParent.Id); + saveItemCommand.GetParameter(index++).Value = topParent.Id.ToString("N"); + } + else + { + //Logger.Debug("Item {0} has null top parent", item.Id); + saveItemCommand.GetParameter(index++).Value = null; + } + + var isByName = false; + var byName = item as IItemByName; + if (byName != null) + { + var dualAccess = item as IHasDualAccess; + isByName = dualAccess == null || dualAccess.IsAccessedByName; + } + saveItemCommand.GetParameter(index++).Value = isByName; + + saveItemCommand.GetParameter(index++).Value = item.SourceType.ToString(); + + var trailer = item as Trailer; + if (trailer != null && trailer.TrailerTypes.Count > 0) + { + saveItemCommand.GetParameter(index++).Value = string.Join("|", trailer.TrailerTypes.Select(i => i.ToString()).ToArray()); + } + else + { + saveItemCommand.GetParameter(index++).Value = null; + } + + saveItemCommand.GetParameter(index++).Value = item.CriticRating; + saveItemCommand.GetParameter(index++).Value = item.CriticRatingSummary; + + if (!item.DateModifiedDuringLastRefresh.HasValue || item.DateModifiedDuringLastRefresh.Value == default(DateTime)) + { + saveItemCommand.GetParameter(index++).Value = null; + } + else + { + saveItemCommand.GetParameter(index++).Value = item.DateModifiedDuringLastRefresh.Value; + } + + var inheritedTags = item.GetInheritedTags(); + if (inheritedTags.Count > 0) + { + saveItemCommand.GetParameter(index++).Value = string.Join("|", inheritedTags.ToArray()); + } + else + { + saveItemCommand.GetParameter(index++).Value = null; + } + + if (string.IsNullOrWhiteSpace(item.Name)) + { + saveItemCommand.GetParameter(index++).Value = null; + } + else + { + saveItemCommand.GetParameter(index++).Value = item.Name.RemoveDiacritics(); + } + + saveItemCommand.GetParameter(index++).Value = item.PresentationUniqueKey; + saveItemCommand.GetParameter(index++).Value = item.SlugName; + saveItemCommand.GetParameter(index++).Value = item.OriginalTitle; + + var video = item as Video; + if (video != null) + { + saveItemCommand.GetParameter(index++).Value = video.PrimaryVersionId; + } + else + { + saveItemCommand.GetParameter(index++).Value = null; + } + + var folder = item as Folder; + if (folder != null && folder.DateLastMediaAdded.HasValue) + { + saveItemCommand.GetParameter(index++).Value = folder.DateLastMediaAdded.Value; + } + else + { + saveItemCommand.GetParameter(index++).Value = null; + } + + saveItemCommand.GetParameter(index++).Value = item.Album; + + var season = item as Season; + if (season != null && season.IsVirtualItem.HasValue) + { + saveItemCommand.GetParameter(index++).Value = season.IsVirtualItem.Value; + } + else + { + saveItemCommand.GetParameter(index++).Value = null; + } + + var hasSeries = item as IHasSeries; + if (hasSeries != null) + { + saveItemCommand.GetParameter(index++).Value = hasSeries.SeriesName; + } + else + { + saveItemCommand.GetParameter(index++).Value = null; + } + + saveItemCommand.Transaction = transaction; + + saveItemCommand.ExecuteNonQuery(); + + if (item.SupportsAncestors) + { + UpdateAncestors(item.Id, item.GetAncestorIds().Distinct().ToList(), connection, transaction); + } + + UpdateUserDataKeys(item.Id, item.GetUserDataKeys().Distinct(StringComparer.OrdinalIgnoreCase).ToList(), connection, transaction); + UpdateImages(item.Id, item.ImageInfos, connection, transaction); + UpdateProviderIds(item.Id, item.ProviderIds, connection, transaction); + UpdateItemValues(item.Id, GetItemValues(item), connection, transaction); + } } - _saveItemCommand.GetParameter(index++).Value = item.EndDate; - _saveItemCommand.GetParameter(index++).Value = item.ChannelId; - - var hasProgramAttributes = item as IHasProgramAttributes; - if (hasProgramAttributes != null) - { - _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsKids; - _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsMovie; - _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsSports; - _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsSeries; - _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsLive; - _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsNews; - _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsPremiere; - _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.EpisodeTitle; - _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsRepeat; - } - else - { - _saveItemCommand.GetParameter(index++).Value = null; - _saveItemCommand.GetParameter(index++).Value = null; - _saveItemCommand.GetParameter(index++).Value = null; - _saveItemCommand.GetParameter(index++).Value = null; - _saveItemCommand.GetParameter(index++).Value = null; - _saveItemCommand.GetParameter(index++).Value = null; - _saveItemCommand.GetParameter(index++).Value = null; - _saveItemCommand.GetParameter(index++).Value = null; - _saveItemCommand.GetParameter(index++).Value = null; - } - - _saveItemCommand.GetParameter(index++).Value = item.CommunityRating; - _saveItemCommand.GetParameter(index++).Value = item.CustomRating; - - _saveItemCommand.GetParameter(index++).Value = item.IndexNumber; - _saveItemCommand.GetParameter(index++).Value = item.IsLocked; - - _saveItemCommand.GetParameter(index++).Value = item.Name; - _saveItemCommand.GetParameter(index++).Value = item.OfficialRating; - - _saveItemCommand.GetParameter(index++).Value = item.MediaType; - _saveItemCommand.GetParameter(index++).Value = item.Overview; - _saveItemCommand.GetParameter(index++).Value = item.ParentIndexNumber; - _saveItemCommand.GetParameter(index++).Value = item.PremiereDate; - _saveItemCommand.GetParameter(index++).Value = item.ProductionYear; - - if (item.ParentId == Guid.Empty) - { - _saveItemCommand.GetParameter(index++).Value = null; - } - else - { - _saveItemCommand.GetParameter(index++).Value = item.ParentId; - } - - _saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Genres.ToArray()); - _saveItemCommand.GetParameter(index++).Value = item.GetParentalRatingValue() ?? 0; - _saveItemCommand.GetParameter(index++).Value = item.GetInheritedParentalRatingValue() ?? 0; - - _saveItemCommand.GetParameter(index++).Value = LatestSchemaVersion; - _saveItemCommand.GetParameter(index++).Value = item.SortName; - _saveItemCommand.GetParameter(index++).Value = item.RunTimeTicks; - - _saveItemCommand.GetParameter(index++).Value = item.OfficialRatingDescription; - _saveItemCommand.GetParameter(index++).Value = item.HomePageUrl; - _saveItemCommand.GetParameter(index++).Value = item.VoteCount; - _saveItemCommand.GetParameter(index++).Value = item.DisplayMediaType; - _saveItemCommand.GetParameter(index++).Value = item.DateCreated; - _saveItemCommand.GetParameter(index++).Value = item.DateModified; - - _saveItemCommand.GetParameter(index++).Value = item.ForcedSortName; - _saveItemCommand.GetParameter(index++).Value = item.IsOffline; - _saveItemCommand.GetParameter(index++).Value = item.LocationType.ToString(); - - _saveItemCommand.GetParameter(index++).Value = item.PreferredMetadataLanguage; - _saveItemCommand.GetParameter(index++).Value = item.PreferredMetadataCountryCode; - _saveItemCommand.GetParameter(index++).Value = item.IsHD; - _saveItemCommand.GetParameter(index++).Value = item.ExternalEtag; - - if (item.DateLastRefreshed == default(DateTime)) - { - _saveItemCommand.GetParameter(index++).Value = null; - } - else - { - _saveItemCommand.GetParameter(index++).Value = item.DateLastRefreshed; - } - - if (item.DateLastSaved == default(DateTime)) - { - _saveItemCommand.GetParameter(index++).Value = null; - } - else - { - _saveItemCommand.GetParameter(index++).Value = item.DateLastSaved; - } - - _saveItemCommand.GetParameter(index++).Value = item.IsInMixedFolder; - _saveItemCommand.GetParameter(index++).Value = string.Join("|", item.LockedFields.Select(i => i.ToString()).ToArray()); - _saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Studios.ToArray()); - - if (item.Audio.HasValue) - { - _saveItemCommand.GetParameter(index++).Value = item.Audio.Value.ToString(); - } - else - { - _saveItemCommand.GetParameter(index++).Value = null; - } - - _saveItemCommand.GetParameter(index++).Value = item.ServiceName; - - if (item.Tags.Count > 0) - { - _saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Tags.ToArray()); - } - else - { - _saveItemCommand.GetParameter(index++).Value = null; - } - - _saveItemCommand.GetParameter(index++).Value = item.IsFolder; - - _saveItemCommand.GetParameter(index++).Value = item.GetBlockUnratedType().ToString(); - - var topParent = item.GetTopParent(); - if (topParent != null) - { - //Logger.Debug("Item {0} has top parent {1}", item.Id, topParent.Id); - _saveItemCommand.GetParameter(index++).Value = topParent.Id.ToString("N"); - } - else - { - //Logger.Debug("Item {0} has null top parent", item.Id); - _saveItemCommand.GetParameter(index++).Value = null; - } - - var isByName = false; - var byName = item as IItemByName; - if (byName != null) - { - var dualAccess = item as IHasDualAccess; - isByName = dualAccess == null || dualAccess.IsAccessedByName; - } - _saveItemCommand.GetParameter(index++).Value = isByName; - - _saveItemCommand.GetParameter(index++).Value = item.SourceType.ToString(); - - var trailer = item as Trailer; - if (trailer != null && trailer.TrailerTypes.Count > 0) - { - _saveItemCommand.GetParameter(index++).Value = string.Join("|", trailer.TrailerTypes.Select(i => i.ToString()).ToArray()); - } - else - { - _saveItemCommand.GetParameter(index++).Value = null; - } - - _saveItemCommand.GetParameter(index++).Value = item.CriticRating; - _saveItemCommand.GetParameter(index++).Value = item.CriticRatingSummary; - - if (!item.DateModifiedDuringLastRefresh.HasValue || item.DateModifiedDuringLastRefresh.Value == default(DateTime)) - { - _saveItemCommand.GetParameter(index++).Value = null; - } - else - { - _saveItemCommand.GetParameter(index++).Value = item.DateModifiedDuringLastRefresh.Value; - } - - var inheritedTags = item.GetInheritedTags(); - if (inheritedTags.Count > 0) - { - _saveItemCommand.GetParameter(index++).Value = string.Join("|", inheritedTags.ToArray()); - } - else - { - _saveItemCommand.GetParameter(index++).Value = null; - } - - if (string.IsNullOrWhiteSpace(item.Name)) - { - _saveItemCommand.GetParameter(index++).Value = null; - } - else - { - _saveItemCommand.GetParameter(index++).Value = item.Name.RemoveDiacritics(); - } - - _saveItemCommand.GetParameter(index++).Value = item.PresentationUniqueKey; - _saveItemCommand.GetParameter(index++).Value = item.SlugName; - _saveItemCommand.GetParameter(index++).Value = item.OriginalTitle; - - var video = item as Video; - if (video != null) - { - _saveItemCommand.GetParameter(index++).Value = video.PrimaryVersionId; - } - else - { - _saveItemCommand.GetParameter(index++).Value = null; - } - - var folder = item as Folder; - if (folder != null && folder.DateLastMediaAdded.HasValue) - { - _saveItemCommand.GetParameter(index++).Value = folder.DateLastMediaAdded.Value; - } - else - { - _saveItemCommand.GetParameter(index++).Value = null; - } - - _saveItemCommand.GetParameter(index++).Value = item.Album; - - var season = item as Season; - if (season != null && season.IsVirtualItem.HasValue) - { - _saveItemCommand.GetParameter(index++).Value = season.IsVirtualItem.Value; - } - else - { - _saveItemCommand.GetParameter(index++).Value = null; - } - - var hasSeries = item as IHasSeries; - if (hasSeries != null) - { - _saveItemCommand.GetParameter(index++).Value = hasSeries.SeriesName; - } - else - { - _saveItemCommand.GetParameter(index++).Value = null; - } - - _saveItemCommand.Transaction = transaction; - - _saveItemCommand.ExecuteNonQuery(); - - if (item.SupportsAncestors) - { - UpdateAncestors(item.Id, item.GetAncestorIds().Distinct().ToList(), transaction); - } - - UpdateUserDataKeys(item.Id, item.GetUserDataKeys().Distinct(StringComparer.OrdinalIgnoreCase).ToList(), transaction); - UpdateImages(item.Id, item.ImageInfos, transaction); - UpdateProviderIds(item.Id, item.ProviderIds, transaction); - UpdateItemValues(item.Id, GetItemValues(item), transaction); + transaction.Commit(); } - - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + catch (OperationCanceledException) { - transaction.Rollback(); + if (transaction != null) + { + transaction.Rollback(); + } + + throw; } - - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save items:", e); - - if (transaction != null) + catch (Exception e) { - transaction.Rollback(); - } + Logger.ErrorException("Failed to save items:", e); - throw; - } - finally - { - if (transaction != null) + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally { - transaction.Dispose(); + if (transaction != null) + { + transaction.Dispose(); + } } - - WriteLock.Release(); } } @@ -953,19 +811,22 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems where guid = @guid"; - cmd.Parameters.Add(cmd, "@guid", DbType.Guid).Value = id; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) + using (var cmd = connection.CreateCommand()) { - if (reader.Read()) + cmd.CommandText = "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems where guid = @guid"; + cmd.Parameters.Add(cmd, "@guid", DbType.Guid).Value = id; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) { - return GetItem(reader); + if (reader.Read()) + { + return GetItem(reader); + } } + return null; } - return null; } } @@ -1371,22 +1232,25 @@ namespace MediaBrowser.Server.Implementations.Persistence } var list = new List(); - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = "select StartPositionTicks,Name,ImagePath from " + ChaptersTableName + " where ItemId = @ItemId order by ChapterIndex asc"; - - cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = id; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + using (var cmd = connection.CreateCommand()) { - while (reader.Read()) + cmd.CommandText = "select StartPositionTicks,Name,ImagePath from " + ChaptersTableName + " where ItemId = @ItemId order by ChapterIndex asc"; + + cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = id; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) { - list.Add(GetChapter(reader)); + while (reader.Read()) + { + list.Add(GetChapter(reader)); + } } } - } - return list; + return list; + } } /// @@ -1404,21 +1268,24 @@ namespace MediaBrowser.Server.Implementations.Persistence throw new ArgumentNullException("id"); } - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = "select StartPositionTicks,Name,ImagePath from " + ChaptersTableName + " where ItemId = @ItemId and ChapterIndex=@ChapterIndex"; - - cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = id; - cmd.Parameters.Add(cmd, "@ChapterIndex", DbType.Int32).Value = index; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) + using (var cmd = connection.CreateCommand()) { - if (reader.Read()) + cmd.CommandText = "select StartPositionTicks,Name,ImagePath from " + ChaptersTableName + " where ItemId = @ItemId and ChapterIndex=@ChapterIndex"; + + cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = id; + cmd.Parameters.Add(cmd, "@ChapterIndex", DbType.Int32).Value = index; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) { - return GetChapter(reader); + if (reader.Read()) + { + return GetChapter(reader); + } } + return null; } - return null; } } @@ -1447,6 +1314,21 @@ namespace MediaBrowser.Server.Implementations.Persistence return chapter; } + private void DeleteChapters(IDbConnection connection, IDbTransaction transaction, Guid id) + { + using (var deleteChaptersCommand = connection.CreateCommand()) + { + deleteChaptersCommand.CommandText = "delete from " + ChaptersTableName + " where ItemId=@ItemId"; + deleteChaptersCommand.Parameters.Add(deleteChaptersCommand, "@ItemId"); + + deleteChaptersCommand.GetParameter(0).Value = id; + + deleteChaptersCommand.Transaction = transaction; + + deleteChaptersCommand.ExecuteNonQuery(); + } + } + /// /// Saves the chapters. /// @@ -1461,7 +1343,7 @@ namespace MediaBrowser.Server.Implementations.Persistence /// or /// cancellationToken /// - public async Task SaveChapters(Guid id, IEnumerable chapters, CancellationToken cancellationToken) + public async Task SaveChapters(Guid id, List chapters, CancellationToken cancellationToken) { CheckDisposed(); @@ -1477,84 +1359,83 @@ namespace MediaBrowser.Server.Implementations.Persistence cancellationToken.ThrowIfCancellationRequested(); - await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); - - IDbTransaction transaction = null; - - try + using (var connection = await CreateConnection().ConfigureAwait(false)) { - transaction = _connection.BeginTransaction(); + IDbTransaction transaction = null; - // First delete chapters - _deleteChaptersCommand.GetParameter(0).Value = id; - - _deleteChaptersCommand.Transaction = transaction; - - _deleteChaptersCommand.ExecuteNonQuery(); - - var index = 0; - - foreach (var chapter in chapters) + try { - cancellationToken.ThrowIfCancellationRequested(); + transaction = connection.BeginTransaction(); - _saveChapterCommand.GetParameter(0).Value = id; - _saveChapterCommand.GetParameter(1).Value = index; - _saveChapterCommand.GetParameter(2).Value = chapter.StartPositionTicks; - _saveChapterCommand.GetParameter(3).Value = chapter.Name; - _saveChapterCommand.GetParameter(4).Value = chapter.ImagePath; + // First delete chapters + DeleteChapters(connection, transaction, id); - _saveChapterCommand.Transaction = transaction; + var index = 0; - _saveChapterCommand.ExecuteNonQuery(); + if (chapters.Count > 0) + { + using (var saveChapterCommand = connection.CreateCommand()) + { + saveChapterCommand.CommandText = "replace into " + ChaptersTableName + " (ItemId, ChapterIndex, StartPositionTicks, Name, ImagePath) values (@ItemId, @ChapterIndex, @StartPositionTicks, @Name, @ImagePath)"; + saveChapterCommand.Parameters.Add(saveChapterCommand, "@ItemId"); + saveChapterCommand.Parameters.Add(saveChapterCommand, "@ChapterIndex"); + saveChapterCommand.Parameters.Add(saveChapterCommand, "@StartPositionTicks"); + saveChapterCommand.Parameters.Add(saveChapterCommand, "@Name"); + saveChapterCommand.Parameters.Add(saveChapterCommand, "@ImagePath"); - index++; + if (chapters.Count > 1) + { + saveChapterCommand.Prepare(); + } + + foreach (var chapter in chapters) + { + cancellationToken.ThrowIfCancellationRequested(); + + saveChapterCommand.GetParameter(0).Value = id; + saveChapterCommand.GetParameter(1).Value = index; + saveChapterCommand.GetParameter(2).Value = chapter.StartPositionTicks; + saveChapterCommand.GetParameter(3).Value = chapter.Name; + saveChapterCommand.GetParameter(4).Value = chapter.ImagePath; + + saveChapterCommand.Transaction = transaction; + + saveChapterCommand.ExecuteNonQuery(); + + index++; + } + } + } + + transaction.Commit(); } - - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + catch (OperationCanceledException) { - transaction.Rollback(); + if (transaction != null) + { + transaction.Rollback(); + } + + throw; } - - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save chapters:", e); - - if (transaction != null) + catch (Exception e) { - transaction.Rollback(); - } + Logger.ErrorException("Failed to save chapters:", e); - throw; - } - finally - { - if (transaction != null) + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally { - transaction.Dispose(); + if (transaction != null) + { + transaction.Dispose(); + } } - - WriteLock.Release(); - } - } - - protected override void CloseConnection() - { - if (_connection != null) - { - if (_connection.IsOpen()) - { - _connection.Close(); - } - - _connection.Dispose(); - _connection = null; } } @@ -1628,13 +1509,13 @@ namespace MediaBrowser.Server.Implementations.Persistence if (EnableJoinUserData(query)) { - list.Add("UserDataDb.UserData.UserId"); - list.Add("UserDataDb.UserData.lastPlayedDate"); - list.Add("UserDataDb.UserData.playbackPositionTicks"); - list.Add("UserDataDb.UserData.playcount"); - list.Add("UserDataDb.UserData.isFavorite"); - list.Add("UserDataDb.UserData.played"); - list.Add("UserDataDb.UserData.rating"); + list.Add("UserData.UserId"); + list.Add("UserData.lastPlayedDate"); + list.Add("UserData.playbackPositionTicks"); + list.Add("UserData.playcount"); + list.Add("UserData.isFavorite"); + list.Add("UserData.played"); + list.Add("UserData.rating"); } if (query.SimilarTo != null) @@ -1688,7 +1569,7 @@ namespace MediaBrowser.Server.Implementations.Persistence return string.Empty; } - return " left join UserDataDb.UserData on (select UserDataKey from UserDataKeys where ItemId=Guid order by Priority LIMIT 1)=UserDataDb.UserData.Key"; + return " left join UserData on (select UserDataKey from UserDataKeys where ItemId=Guid order by Priority LIMIT 1)=UserData.Key"; } public IEnumerable GetItemList(InternalItemsQuery query) @@ -1702,53 +1583,61 @@ namespace MediaBrowser.Server.Implementations.Persistence var now = DateTime.UtcNow; - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns, cmd)) + " from TypedBaseItems"; - cmd.CommandText += GetJoinUserDataText(query); - if (EnableJoinUserData(query)) { - cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; + AttachUserDataDb(connection); } - var whereClauses = GetWhereClauses(query, cmd); - - var whereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); - - cmd.CommandText += whereText; - - if (EnableGroupByPresentationUniqueKey(query)) + using (var cmd = connection.CreateCommand()) { - cmd.CommandText += " Group by PresentationUniqueKey"; - } + cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns, cmd)) + " from TypedBaseItems"; + cmd.CommandText += GetJoinUserDataText(query); - cmd.CommandText += GetOrderByText(query); - - if (query.Limit.HasValue || query.StartIndex.HasValue) - { - var limit = query.Limit ?? int.MaxValue; - - cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); - - if (query.StartIndex.HasValue) + if (EnableJoinUserData(query)) { - cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; } - } - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) - { - LogQueryTime("GetItemList", cmd, now); + var whereClauses = GetWhereClauses(query, cmd); - while (reader.Read()) + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); + + cmd.CommandText += whereText; + + if (EnableGroupByPresentationUniqueKey(query)) { - var item = GetItem(reader); - if (item != null) + cmd.CommandText += " Group by PresentationUniqueKey"; + } + + cmd.CommandText += GetOrderByText(query); + + if (query.Limit.HasValue || query.StartIndex.HasValue) + { + var limit = query.Limit ?? int.MaxValue; + + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + + if (query.StartIndex.HasValue) { - yield return item; + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + } + } + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + LogQueryTime("GetItemList", cmd, now); + + while (reader.Read()) + { + var item = GetItem(reader); + if (item != null) + { + yield return item; + } } } } @@ -1792,86 +1681,94 @@ namespace MediaBrowser.Server.Implementations.Persistence var now = DateTime.UtcNow; - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns, cmd)) + " from TypedBaseItems"; - cmd.CommandText += GetJoinUserDataText(query); - if (EnableJoinUserData(query)) { - cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; + AttachUserDataDb(connection); } - var whereClauses = GetWhereClauses(query, cmd); - - var whereTextWithoutPaging = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); - - var whereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); - - cmd.CommandText += whereText; - - if (EnableGroupByPresentationUniqueKey(query)) + using (var cmd = connection.CreateCommand()) { - cmd.CommandText += " Group by PresentationUniqueKey"; - } + cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns, cmd)) + " from TypedBaseItems"; + cmd.CommandText += GetJoinUserDataText(query); - cmd.CommandText += GetOrderByText(query); - - if (query.Limit.HasValue || query.StartIndex.HasValue) - { - var limit = query.Limit ?? int.MaxValue; - - cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); - - if (query.StartIndex.HasValue) + if (EnableJoinUserData(query)) { - cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; } - } - if (EnableGroupByPresentationUniqueKey(query)) - { - cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems"; - } - else - { - cmd.CommandText += "; select count (guid) from TypedBaseItems"; - } + var whereClauses = GetWhereClauses(query, cmd); - cmd.CommandText += GetJoinUserDataText(query); - cmd.CommandText += whereTextWithoutPaging; + var whereTextWithoutPaging = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); - var list = new List(); - var count = 0; + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) - { - LogQueryTime("GetItems", cmd, now); + cmd.CommandText += whereText; - while (reader.Read()) + if (EnableGroupByPresentationUniqueKey(query)) { - var item = GetItem(reader); - if (item != null) + cmd.CommandText += " Group by PresentationUniqueKey"; + } + + cmd.CommandText += GetOrderByText(query); + + if (query.Limit.HasValue || query.StartIndex.HasValue) + { + var limit = query.Limit ?? int.MaxValue; + + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + + if (query.StartIndex.HasValue) { - list.Add(item); + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); } } - if (reader.NextResult() && reader.Read()) + if (EnableGroupByPresentationUniqueKey(query)) { - count = reader.GetInt32(0); + cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems"; + } + else + { + cmd.CommandText += "; select count (guid) from TypedBaseItems"; } - } - return new QueryResult() - { - Items = list.ToArray(), - TotalRecordCount = count - }; + cmd.CommandText += GetJoinUserDataText(query); + cmd.CommandText += whereTextWithoutPaging; + + var list = new List(); + var count = 0; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) + { + LogQueryTime("GetItems", cmd, now); + + while (reader.Read()) + { + var item = GetItem(reader); + if (item != null) + { + list.Add(item); + } + } + + if (reader.NextResult() && reader.Read()) + { + count = reader.GetInt32(0); + } + } + + return new QueryResult() + { + Items = list.ToArray(), + TotalRecordCount = count + }; + } } } @@ -1989,56 +1886,64 @@ namespace MediaBrowser.Server.Implementations.Persistence var now = DateTime.UtcNow; - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" }, cmd)) + " from TypedBaseItems"; - cmd.CommandText += GetJoinUserDataText(query); - if (EnableJoinUserData(query)) { - cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; + AttachUserDataDb(connection); } - var whereClauses = GetWhereClauses(query, cmd); - - var whereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); - - cmd.CommandText += whereText; - - if (EnableGroupByPresentationUniqueKey(query)) + using (var cmd = connection.CreateCommand()) { - cmd.CommandText += " Group by PresentationUniqueKey"; - } + cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" }, cmd)) + " from TypedBaseItems"; + cmd.CommandText += GetJoinUserDataText(query); - cmd.CommandText += GetOrderByText(query); - - if (query.Limit.HasValue || query.StartIndex.HasValue) - { - var limit = query.Limit ?? int.MaxValue; - - cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); - - if (query.StartIndex.HasValue) + if (EnableJoinUserData(query)) { - cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; } - } - var list = new List(); + var whereClauses = GetWhereClauses(query, cmd); - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) - { - LogQueryTime("GetItemIdsList", cmd, now); + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); - while (reader.Read()) + cmd.CommandText += whereText; + + if (EnableGroupByPresentationUniqueKey(query)) { - list.Add(reader.GetGuid(0)); + cmd.CommandText += " Group by PresentationUniqueKey"; } - } - return list; + cmd.CommandText += GetOrderByText(query); + + if (query.Limit.HasValue || query.StartIndex.HasValue) + { + var limit = query.Limit ?? int.MaxValue; + + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + + if (query.StartIndex.HasValue) + { + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + } + } + + var list = new List(); + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + LogQueryTime("GetItemIdsList", cmd, now); + + while (reader.Read()) + { + list.Add(reader.GetGuid(0)); + } + } + + return list; + } } } @@ -2051,73 +1956,76 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = "select guid,path from TypedBaseItems"; - - var whereClauses = GetWhereClauses(query, cmd); - - var whereTextWithoutPaging = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); - - var whereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); - - cmd.CommandText += whereText; - - if (EnableGroupByPresentationUniqueKey(query)) + using (var cmd = connection.CreateCommand()) { - cmd.CommandText += " Group by PresentationUniqueKey"; - } + cmd.CommandText = "select guid,path from TypedBaseItems"; - cmd.CommandText += GetOrderByText(query); + var whereClauses = GetWhereClauses(query, cmd); - if (query.Limit.HasValue || query.StartIndex.HasValue) - { - var limit = query.Limit ?? int.MaxValue; + var whereTextWithoutPaging = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); - cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); - if (query.StartIndex.HasValue) + cmd.CommandText += whereText; + + if (EnableGroupByPresentationUniqueKey(query)) { - cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + cmd.CommandText += " Group by PresentationUniqueKey"; } - } - cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging; + cmd.CommandText += GetOrderByText(query); - var list = new List>(); - var count = 0; - - Logger.Debug(cmd.CommandText); - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) - { - while (reader.Read()) + if (query.Limit.HasValue || query.StartIndex.HasValue) { - var id = reader.GetGuid(0); - string path = null; + var limit = query.Limit ?? int.MaxValue; - if (!reader.IsDBNull(1)) + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + + if (query.StartIndex.HasValue) { - path = reader.GetString(1); + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); } - list.Add(new Tuple(id, path)); } - if (reader.NextResult() && reader.Read()) + cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging; + + var list = new List>(); + var count = 0; + + Logger.Debug(cmd.CommandText); + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) { - count = reader.GetInt32(0); - } - } + while (reader.Read()) + { + var id = reader.GetGuid(0); + string path = null; - return new QueryResult>() - { - Items = list.ToArray(), - TotalRecordCount = count - }; + if (!reader.IsDBNull(1)) + { + path = reader.GetString(1); + } + list.Add(new Tuple(id, path)); + } + + if (reader.NextResult() && reader.Read()) + { + count = reader.GetInt32(0); + } + } + + return new QueryResult>() + { + Items = list.ToArray(), + TotalRecordCount = count + }; + } } } @@ -2132,78 +2040,86 @@ namespace MediaBrowser.Server.Implementations.Persistence var now = DateTime.UtcNow; - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" }, cmd)) + " from TypedBaseItems"; - - var whereClauses = GetWhereClauses(query, cmd); - cmd.CommandText += GetJoinUserDataText(query); - if (EnableJoinUserData(query)) { - cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; + AttachUserDataDb(connection); } - var whereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); - - cmd.CommandText += whereText; - - if (EnableGroupByPresentationUniqueKey(query)) + using (var cmd = connection.CreateCommand()) { - cmd.CommandText += " Group by PresentationUniqueKey"; - } + cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" }, cmd)) + " from TypedBaseItems"; - cmd.CommandText += GetOrderByText(query); + var whereClauses = GetWhereClauses(query, cmd); + cmd.CommandText += GetJoinUserDataText(query); - if (query.Limit.HasValue || query.StartIndex.HasValue) - { - var limit = query.Limit ?? int.MaxValue; - - cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); - - if (query.StartIndex.HasValue) + if (EnableJoinUserData(query)) { - cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); - } - } - - if (EnableGroupByPresentationUniqueKey(query)) - { - cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems"; - } - else - { - cmd.CommandText += "; select count (guid) from TypedBaseItems"; - } - - cmd.CommandText += GetJoinUserDataText(query); - cmd.CommandText += whereText; - - var list = new List(); - var count = 0; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) - { - LogQueryTime("GetItemIds", cmd, now); - - while (reader.Read()) - { - list.Add(reader.GetGuid(0)); + cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; } - if (reader.NextResult() && reader.Read()) - { - count = reader.GetInt32(0); - } - } + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); - return new QueryResult() - { - Items = list.ToArray(), - TotalRecordCount = count - }; + cmd.CommandText += whereText; + + if (EnableGroupByPresentationUniqueKey(query)) + { + cmd.CommandText += " Group by PresentationUniqueKey"; + } + + cmd.CommandText += GetOrderByText(query); + + if (query.Limit.HasValue || query.StartIndex.HasValue) + { + var limit = query.Limit ?? int.MaxValue; + + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + + if (query.StartIndex.HasValue) + { + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + } + } + + if (EnableGroupByPresentationUniqueKey(query)) + { + cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems"; + } + else + { + cmd.CommandText += "; select count (guid) from TypedBaseItems"; + } + + cmd.CommandText += GetJoinUserDataText(query); + cmd.CommandText += whereText; + + var list = new List(); + var count = 0; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) + { + LogQueryTime("GetItemIds", cmd, now); + + while (reader.Read()) + { + list.Add(reader.GetGuid(0)); + } + + if (reader.NextResult() && reader.Read()) + { + count = reader.GetInt32(0); + } + } + + return new QueryResult() + { + Items = list.ToArray(), + TotalRecordCount = count + }; + } } } @@ -2987,77 +2903,88 @@ namespace MediaBrowser.Server.Implementations.Persistence private async Task UpdateInheritedTags(CancellationToken cancellationToken) { - var newValues = new List>(); - - using (var cmd = _connection.CreateCommand()) + using (var connection = await CreateConnection().ConfigureAwait(false)) { - cmd.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"; + var newValues = new List>(); - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + using (var cmd = connection.CreateCommand()) { - while (reader.Read()) - { - var id = reader.GetGuid(0); - string value = reader.IsDBNull(2) ? null : reader.GetString(2); + cmd.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"; - newValues.Add(new Tuple(id, value)); + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) + { + var id = reader.GetGuid(0); + string value = reader.IsDBNull(2) ? null : reader.GetString(2); + + newValues.Add(new Tuple(id, value)); + } } } - } - Logger.Debug("UpdateInheritedTags - {0} rows", newValues.Count); - if (newValues.Count == 0) - { - return; - } - - await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); - - IDbTransaction transaction = null; - - try - { - transaction = _connection.BeginTransaction(); - - foreach (var item in newValues) + Logger.Debug("UpdateInheritedTags - {0} rows", newValues.Count); + if (newValues.Count == 0) { - _updateInheritedTagsCommand.GetParameter(0).Value = item.Item1; - _updateInheritedTagsCommand.GetParameter(1).Value = item.Item2; - - _updateInheritedTagsCommand.Transaction = transaction; - _updateInheritedTagsCommand.ExecuteNonQuery(); + return; } - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + IDbTransaction transaction = null; + + try { - transaction.Rollback(); + transaction = connection.BeginTransaction(); + + using (var updateInheritedTagsCommand = connection.CreateCommand()) + { + updateInheritedTagsCommand.CommandText = "Update TypedBaseItems set InheritedTags=@InheritedTags where Guid=@Guid"; + updateInheritedTagsCommand.Parameters.Add(updateInheritedTagsCommand, "@Guid"); + updateInheritedTagsCommand.Parameters.Add(updateInheritedTagsCommand, "@InheritedTags"); + + if (newValues.Count > 1) + { + updateInheritedTagsCommand.Prepare(); + } + + foreach (var item in newValues) + { + updateInheritedTagsCommand.GetParameter(0).Value = item.Item1; + updateInheritedTagsCommand.GetParameter(1).Value = item.Item2; + + updateInheritedTagsCommand.Transaction = transaction; + updateInheritedTagsCommand.ExecuteNonQuery(); + } + } + + transaction.Commit(); } - - throw; - } - catch (Exception e) - { - Logger.ErrorException("Error running query:", e); - - if (transaction != null) + catch (OperationCanceledException) { - transaction.Rollback(); - } + if (transaction != null) + { + transaction.Rollback(); + } - throw; - } - finally - { - if (transaction != null) + throw; + } + catch (Exception e) { - transaction.Dispose(); - } + Logger.ErrorException("Error running query:", e); - WriteLock.Release(); + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + } } } @@ -3065,75 +2992,82 @@ namespace MediaBrowser.Server.Implementations.Persistence { var newValues = new List>(); - using (var cmd = _connection.CreateCommand()) + using (var connection = await CreateConnection().ConfigureAwait(false)) { - cmd.CommandText = "select Guid,InheritedParentalRatingValue,(select Max(ParentalRatingValue, (select COALESCE(MAX(ParentalRatingValue),0) from TypedBaseItems where guid in (Select AncestorId from AncestorIds where ItemId=Outer.guid)))) as NewInheritedParentalRatingValue from typedbaseitems as Outer where InheritedParentalRatingValue <> NewInheritedParentalRatingValue"; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + using (var cmd = connection.CreateCommand()) { - while (reader.Read()) - { - var id = reader.GetGuid(0); - var newValue = reader.GetInt32(2); + cmd.CommandText = "select Guid,InheritedParentalRatingValue,(select Max(ParentalRatingValue, (select COALESCE(MAX(ParentalRatingValue),0) from TypedBaseItems where guid in (Select AncestorId from AncestorIds where ItemId=Outer.guid)))) as NewInheritedParentalRatingValue from typedbaseitems as Outer where InheritedParentalRatingValue <> NewInheritedParentalRatingValue"; - newValues.Add(new Tuple(id, newValue)); + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) + { + var id = reader.GetGuid(0); + var newValue = reader.GetInt32(2); + + newValues.Add(new Tuple(id, newValue)); + } } } - } - Logger.Debug("UpdateInheritedParentalRatings - {0} rows", newValues.Count); - if (newValues.Count == 0) - { - return; - } - - await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); - - IDbTransaction transaction = null; - - try - { - transaction = _connection.BeginTransaction(); - - foreach (var item in newValues) + Logger.Debug("UpdateInheritedParentalRatings - {0} rows", newValues.Count); + if (newValues.Count == 0) { - _updateInheritedRatingCommand.GetParameter(0).Value = item.Item1; - _updateInheritedRatingCommand.GetParameter(1).Value = item.Item2; - - _updateInheritedRatingCommand.Transaction = transaction; - _updateInheritedRatingCommand.ExecuteNonQuery(); + return; } - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + using (var updateInheritedRatingCommand = connection.CreateCommand()) { - transaction.Rollback(); + updateInheritedRatingCommand.CommandText = "Update TypedBaseItems set InheritedParentalRatingValue=@InheritedParentalRatingValue where Guid=@Guid"; + updateInheritedRatingCommand.Parameters.Add(updateInheritedRatingCommand, "@Guid"); + updateInheritedRatingCommand.Parameters.Add(updateInheritedRatingCommand, "@InheritedParentalRatingValue"); + updateInheritedRatingCommand.Prepare(); + + IDbTransaction transaction = null; + + try + { + transaction = connection.BeginTransaction(); + + foreach (var item in newValues) + { + updateInheritedRatingCommand.GetParameter(0).Value = item.Item1; + updateInheritedRatingCommand.GetParameter(1).Value = item.Item2; + + updateInheritedRatingCommand.Transaction = transaction; + updateInheritedRatingCommand.ExecuteNonQuery(); + } + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + catch (Exception e) + { + Logger.ErrorException("Error running query:", e); + + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + } } - - throw; - } - catch (Exception e) - { - Logger.ErrorException("Error running query:", e); - - if (transaction != null) - { - transaction.Rollback(); - } - - throw; - } - finally - { - if (transaction != null) - { - transaction.Dispose(); - } - - WriteLock.Release(); } } @@ -3176,89 +3110,73 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); - await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); - - IDbTransaction transaction = null; - - try + using (var connection = await CreateConnection().ConfigureAwait(false)) { - transaction = _connection.BeginTransaction(); + IDbTransaction transaction = null; - // Delete people - _deletePeopleCommand.GetParameter(0).Value = id; - _deletePeopleCommand.Transaction = transaction; - _deletePeopleCommand.ExecuteNonQuery(); - - // Delete chapters - _deleteChaptersCommand.GetParameter(0).Value = id; - _deleteChaptersCommand.Transaction = transaction; - _deleteChaptersCommand.ExecuteNonQuery(); - - // Delete media streams - _deleteStreamsCommand.GetParameter(0).Value = id; - _deleteStreamsCommand.Transaction = transaction; - _deleteStreamsCommand.ExecuteNonQuery(); - - // Delete ancestors - _deleteAncestorsCommand.GetParameter(0).Value = id; - _deleteAncestorsCommand.Transaction = transaction; - _deleteAncestorsCommand.ExecuteNonQuery(); - - // Delete user data keys - _deleteUserDataKeysCommand.GetParameter(0).Value = id; - _deleteUserDataKeysCommand.Transaction = transaction; - _deleteUserDataKeysCommand.ExecuteNonQuery(); - - // Delete item values - _deleteItemValuesCommand.GetParameter(0).Value = id; - _deleteItemValuesCommand.Transaction = transaction; - _deleteItemValuesCommand.ExecuteNonQuery(); - - // Delete provider ids - _deleteProviderIdsCommand.GetParameter(0).Value = id; - _deleteProviderIdsCommand.Transaction = transaction; - _deleteProviderIdsCommand.ExecuteNonQuery(); - - // Delete images - _deleteImagesCommand.GetParameter(0).Value = id; - _deleteImagesCommand.Transaction = transaction; - _deleteImagesCommand.ExecuteNonQuery(); - - // Delete the item - _deleteItemCommand.GetParameter(0).Value = id; - _deleteItemCommand.Transaction = transaction; - _deleteItemCommand.ExecuteNonQuery(); - - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + try { - transaction.Rollback(); + transaction = connection.BeginTransaction(); + + // Delete people + DeletePeople(connection, transaction, id); + DeleteChapters(connection, transaction, id); + DeleteMediaStreams(connection, transaction, id); + + // Delete ancestors + DeleteAncestors(connection, transaction, id); + + // Delete user data keys + DeleteUserDataKeys(connection, transaction, id); + + // Delete item values + DeleteItemValues(connection, transaction, id); + + // Delete provider ids + DeleteProviderIds(connection, transaction, id); + + DeleteImages(connection, transaction, id); + + // Delete the item + using (var deleteItemCommand = connection.CreateCommand()) + { + deleteItemCommand.CommandText = "delete from TypedBaseItems where guid=@Id"; + deleteItemCommand.Parameters.Add(deleteItemCommand, "@Id"); + + deleteItemCommand.GetParameter(0).Value = id; + deleteItemCommand.Transaction = transaction; + deleteItemCommand.ExecuteNonQuery(); + } + + transaction.Commit(); } - - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save children:", e); - - if (transaction != null) + catch (OperationCanceledException) { - transaction.Rollback(); - } + if (transaction != null) + { + transaction.Rollback(); + } - throw; - } - finally - { - if (transaction != null) + throw; + } + catch (Exception e) { - transaction.Dispose(); - } + Logger.ErrorException("Failed to save children:", e); - WriteLock.Release(); + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + } } } @@ -3271,30 +3189,33 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = "select Distinct Name from People"; - - var whereClauses = GetPeopleWhereClauses(query, cmd); - - if (whereClauses.Count > 0) + using (var cmd = connection.CreateCommand()) { - cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); - } + cmd.CommandText = "select Distinct Name from People"; - cmd.CommandText += " order by ListOrder"; + var whereClauses = GetPeopleWhereClauses(query, cmd); - var list = new List(); - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) - { - while (reader.Read()) + if (whereClauses.Count > 0) { - list.Add(reader.GetString(0)); + cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); } - } - return list; + cmd.CommandText += " order by ListOrder"; + + var list = new List(); + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) + { + list.Add(reader.GetString(0)); + } + } + + return list; + } } } @@ -3307,30 +3228,33 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = "select ItemId, Name, Role, PersonType, SortOrder from People"; - - var whereClauses = GetPeopleWhereClauses(query, cmd); - - if (whereClauses.Count > 0) + using (var cmd = connection.CreateCommand()) { - cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); - } + cmd.CommandText = "select ItemId, Name, Role, PersonType, SortOrder from People"; - cmd.CommandText += " order by ListOrder"; + var whereClauses = GetPeopleWhereClauses(query, cmd); - var list = new List(); - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) - { - while (reader.Read()) + if (whereClauses.Count > 0) { - list.Add(GetPerson(reader)); + cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); } - } - return list; + cmd.CommandText += " order by ListOrder"; + + var list = new List(); + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) + { + list.Add(GetPerson(reader)); + } + } + + return list; + } } } @@ -3384,7 +3308,21 @@ namespace MediaBrowser.Server.Implementations.Persistence return whereClauses; } - private void UpdateAncestors(Guid itemId, List ancestorIds, IDbTransaction transaction) + private void DeleteAncestors(IDbConnection connection, IDbTransaction transaction, Guid id) + { + using (var deleteAncestorsCommand = connection.CreateCommand()) + { + deleteAncestorsCommand.CommandText = "delete from AncestorIds where ItemId=@Id"; + deleteAncestorsCommand.Parameters.Add(deleteAncestorsCommand, "@Id"); + + deleteAncestorsCommand.GetParameter(0).Value = id; + deleteAncestorsCommand.Transaction = transaction; + + deleteAncestorsCommand.ExecuteNonQuery(); + } + } + + private void UpdateAncestors(Guid itemId, List ancestorIds, IDbConnection connection, IDbTransaction transaction) { if (itemId == Guid.Empty) { @@ -3399,20 +3337,33 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); // First delete - _deleteAncestorsCommand.GetParameter(0).Value = itemId; - _deleteAncestorsCommand.Transaction = transaction; + DeleteAncestors(connection, transaction, itemId); - _deleteAncestorsCommand.ExecuteNonQuery(); - - foreach (var ancestorId in ancestorIds) + if (ancestorIds.Count > 0) { - _saveAncestorCommand.GetParameter(0).Value = itemId; - _saveAncestorCommand.GetParameter(1).Value = ancestorId; - _saveAncestorCommand.GetParameter(2).Value = ancestorId.ToString("N"); + using (var saveAncestorCommand = connection.CreateCommand()) + { + saveAncestorCommand.CommandText = "insert into AncestorIds (ItemId, AncestorId, AncestorIdText) values (@ItemId, @AncestorId, @AncestorIdText)"; + saveAncestorCommand.Parameters.Add(saveAncestorCommand, "@ItemId"); + saveAncestorCommand.Parameters.Add(saveAncestorCommand, "@AncestorId"); + saveAncestorCommand.Parameters.Add(saveAncestorCommand, "@AncestorIdText"); - _saveAncestorCommand.Transaction = transaction; + if (ancestorIds.Count > 1) + { + saveAncestorCommand.Prepare(); + } - _saveAncestorCommand.ExecuteNonQuery(); + foreach (var ancestorId in ancestorIds) + { + saveAncestorCommand.GetParameter(0).Value = itemId; + saveAncestorCommand.GetParameter(1).Value = ancestorId; + saveAncestorCommand.GetParameter(2).Value = ancestorId.ToString("N"); + + saveAncestorCommand.Transaction = transaction; + + saveAncestorCommand.ExecuteNonQuery(); + } + } } } @@ -3440,7 +3391,20 @@ namespace MediaBrowser.Server.Implementations.Persistence return list; } - private void UpdateImages(Guid itemId, List images, IDbTransaction transaction) + private void DeleteImages(IDbConnection connection, IDbTransaction transaction, Guid id) + { + using (var deleteImagesCommand = connection.CreateCommand()) + { + deleteImagesCommand.CommandText = "delete from Images where ItemId=@Id"; + deleteImagesCommand.Parameters.Add(deleteImagesCommand, "@Id"); + + deleteImagesCommand.GetParameter(0).Value = id; + deleteImagesCommand.Transaction = transaction; + deleteImagesCommand.ExecuteNonQuery(); + } + } + + private void UpdateImages(Guid itemId, List images, IDbConnection connection, IDbTransaction transaction) { if (itemId == Guid.Empty) { @@ -3455,38 +3419,70 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); // First delete - _deleteImagesCommand.GetParameter(0).Value = itemId; - _deleteImagesCommand.Transaction = transaction; + DeleteImages(connection, transaction, itemId); - _deleteImagesCommand.ExecuteNonQuery(); - - var index = 0; - foreach (var image in images) + if (images.Count > 0) { - _saveImagesCommand.GetParameter(0).Value = itemId; - _saveImagesCommand.GetParameter(1).Value = image.Type; - _saveImagesCommand.GetParameter(2).Value = image.Path; - - if (image.DateModified == default(DateTime)) + using (var saveImagesCommand = connection.CreateCommand()) { - _saveImagesCommand.GetParameter(3).Value = null; + var index = 0; + + saveImagesCommand.CommandText = "insert into Images (ItemId, ImageType, Path, DateModified, IsPlaceHolder, SortOrder) values (@ItemId, @ImageType, @Path, @DateModified, @IsPlaceHolder, @SortOrder)"; + saveImagesCommand.Parameters.Add(saveImagesCommand, "@ItemId"); + saveImagesCommand.Parameters.Add(saveImagesCommand, "@ImageType"); + saveImagesCommand.Parameters.Add(saveImagesCommand, "@Path"); + saveImagesCommand.Parameters.Add(saveImagesCommand, "@DateModified"); + saveImagesCommand.Parameters.Add(saveImagesCommand, "@IsPlaceHolder"); + saveImagesCommand.Parameters.Add(saveImagesCommand, "@SortOrder"); + + if (images.Count > 1) + { + saveImagesCommand.Prepare(); + } + + foreach (var image in images) + { + saveImagesCommand.GetParameter(0).Value = itemId; + saveImagesCommand.GetParameter(1).Value = image.Type; + saveImagesCommand.GetParameter(2).Value = image.Path; + + if (image.DateModified == default(DateTime)) + { + saveImagesCommand.GetParameter(3).Value = null; + } + else + { + saveImagesCommand.GetParameter(3).Value = image.DateModified; + } + + saveImagesCommand.GetParameter(4).Value = image.IsPlaceholder; + saveImagesCommand.GetParameter(5).Value = index; + + saveImagesCommand.Transaction = transaction; + + saveImagesCommand.ExecuteNonQuery(); + index++; + } } - else - { - _saveImagesCommand.GetParameter(3).Value = image.DateModified; - } - - _saveImagesCommand.GetParameter(4).Value = image.IsPlaceholder; - _saveImagesCommand.GetParameter(5).Value = index; - - _saveImagesCommand.Transaction = transaction; - - _saveImagesCommand.ExecuteNonQuery(); - index++; } } - private void UpdateProviderIds(Guid itemId, Dictionary values, IDbTransaction transaction) + private void DeleteProviderIds(IDbConnection connection, IDbTransaction transaction, Guid itemId) + { + using (var deleteProviderIdsCommand = connection.CreateCommand()) + { + // provider ids + deleteProviderIdsCommand.CommandText = "delete from ProviderIds where ItemId=@Id"; + deleteProviderIdsCommand.Parameters.Add(deleteProviderIdsCommand, "@Id"); + + deleteProviderIdsCommand.GetParameter(0).Value = itemId; + deleteProviderIdsCommand.Transaction = transaction; + + deleteProviderIdsCommand.ExecuteNonQuery(); + } + } + + private void UpdateProviderIds(Guid itemId, Dictionary values, IDbConnection connection, IDbTransaction transaction) { if (itemId == Guid.Empty) { @@ -3501,23 +3497,51 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); // First delete - _deleteProviderIdsCommand.GetParameter(0).Value = itemId; - _deleteProviderIdsCommand.Transaction = transaction; + DeleteProviderIds(connection, transaction, itemId); - _deleteProviderIdsCommand.ExecuteNonQuery(); - - foreach (var pair in values) + if (values.Count > 0) { - _saveProviderIdsCommand.GetParameter(0).Value = itemId; - _saveProviderIdsCommand.GetParameter(1).Value = pair.Key; - _saveProviderIdsCommand.GetParameter(2).Value = pair.Value; - _saveProviderIdsCommand.Transaction = transaction; + using (var saveProviderIdsCommand = connection.CreateCommand()) + { + saveProviderIdsCommand.CommandText = "insert into ProviderIds (ItemId, Name, Value) values (@ItemId, @Name, @Value)"; + saveProviderIdsCommand.Parameters.Add(saveProviderIdsCommand, "@ItemId"); + saveProviderIdsCommand.Parameters.Add(saveProviderIdsCommand, "@Name"); + saveProviderIdsCommand.Parameters.Add(saveProviderIdsCommand, "@Value"); - _saveProviderIdsCommand.ExecuteNonQuery(); + if (values.Count > 1) + { + saveProviderIdsCommand.Prepare(); + } + + foreach (var pair in values) + { + saveProviderIdsCommand.GetParameter(0).Value = itemId; + saveProviderIdsCommand.GetParameter(1).Value = pair.Key; + saveProviderIdsCommand.GetParameter(2).Value = pair.Value; + saveProviderIdsCommand.Transaction = transaction; + + saveProviderIdsCommand.ExecuteNonQuery(); + } + } } } - private void UpdateItemValues(Guid itemId, List> values, IDbTransaction transaction) + private void DeleteItemValues(IDbConnection connection, IDbTransaction transaction, Guid itemId) + { + using (var deleteItemValuesCommand = connection.CreateCommand()) + { + deleteItemValuesCommand.CommandText = "delete from ItemValues where ItemId=@Id"; + deleteItemValuesCommand.Parameters.Add(deleteItemValuesCommand, "@Id"); + + // First delete + deleteItemValuesCommand.GetParameter(0).Value = itemId; + deleteItemValuesCommand.Transaction = transaction; + + deleteItemValuesCommand.ExecuteNonQuery(); + } + } + + private void UpdateItemValues(Guid itemId, List> values, IDbConnection connection, IDbTransaction transaction) { if (itemId == Guid.Empty) { @@ -3532,23 +3556,51 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); // First delete - _deleteItemValuesCommand.GetParameter(0).Value = itemId; - _deleteItemValuesCommand.Transaction = transaction; + DeleteItemValues(connection, transaction, itemId); - _deleteItemValuesCommand.ExecuteNonQuery(); - - foreach (var pair in values) + if (values.Count > 0) { - _saveItemValuesCommand.GetParameter(0).Value = itemId; - _saveItemValuesCommand.GetParameter(1).Value = pair.Item1; - _saveItemValuesCommand.GetParameter(2).Value = pair.Item2; - _saveItemValuesCommand.Transaction = transaction; + using (var saveItemValuesCommand = connection.CreateCommand()) + { + saveItemValuesCommand.CommandText = "insert into ItemValues (ItemId, Type, Value) values (@ItemId, @Type, @Value)"; + saveItemValuesCommand.Parameters.Add(saveItemValuesCommand, "@ItemId"); + saveItemValuesCommand.Parameters.Add(saveItemValuesCommand, "@Type"); + saveItemValuesCommand.Parameters.Add(saveItemValuesCommand, "@Value"); - _saveItemValuesCommand.ExecuteNonQuery(); + if (values.Count > 1) + { + saveItemValuesCommand.Prepare(); + } + + foreach (var pair in values) + { + saveItemValuesCommand.GetParameter(0).Value = itemId; + saveItemValuesCommand.GetParameter(1).Value = pair.Item1; + saveItemValuesCommand.GetParameter(2).Value = pair.Item2; + saveItemValuesCommand.Transaction = transaction; + + saveItemValuesCommand.ExecuteNonQuery(); + } + } } } - private void UpdateUserDataKeys(Guid itemId, List keys, IDbTransaction transaction) + private void DeleteUserDataKeys(IDbConnection connection, IDbTransaction transaction, Guid itemId) + { + using (var deleteUserDataKeysCommand = connection.CreateCommand()) + { + // user data + deleteUserDataKeysCommand.CommandText = "delete from UserDataKeys where ItemId=@Id"; + deleteUserDataKeysCommand.Parameters.Add(deleteUserDataKeysCommand, "@Id"); + + deleteUserDataKeysCommand.GetParameter(0).Value = itemId; + deleteUserDataKeysCommand.Transaction = transaction; + + deleteUserDataKeysCommand.ExecuteNonQuery(); + } + } + + private void UpdateUserDataKeys(Guid itemId, List keys, IDbConnection connection, IDbTransaction transaction) { if (itemId == Guid.Empty) { @@ -3563,21 +3615,50 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); // First delete - _deleteUserDataKeysCommand.GetParameter(0).Value = itemId; - _deleteUserDataKeysCommand.Transaction = transaction; + DeleteUserDataKeys(connection, transaction, itemId); - _deleteUserDataKeysCommand.ExecuteNonQuery(); var index = 0; - foreach (var key in keys) + if (keys.Count > 0) { - _saveUserDataKeysCommand.GetParameter(0).Value = itemId; - _saveUserDataKeysCommand.GetParameter(1).Value = key; - _saveUserDataKeysCommand.GetParameter(2).Value = index; - index++; - _saveUserDataKeysCommand.Transaction = transaction; + using (var saveUserDataKeysCommand = connection.CreateCommand()) + { + saveUserDataKeysCommand.CommandText = "insert into UserDataKeys (ItemId, UserDataKey, Priority) values (@ItemId, @UserDataKey, @Priority)"; + saveUserDataKeysCommand.Parameters.Add(saveUserDataKeysCommand, "@ItemId"); + saveUserDataKeysCommand.Parameters.Add(saveUserDataKeysCommand, "@UserDataKey"); + saveUserDataKeysCommand.Parameters.Add(saveUserDataKeysCommand, "@Priority"); - _saveUserDataKeysCommand.ExecuteNonQuery(); + if (keys.Count > 1) + { + saveUserDataKeysCommand.Prepare(); + } + + foreach (var key in keys) + { + saveUserDataKeysCommand.GetParameter(0).Value = itemId; + saveUserDataKeysCommand.GetParameter(1).Value = key; + saveUserDataKeysCommand.GetParameter(2).Value = index; + index++; + saveUserDataKeysCommand.Transaction = transaction; + + saveUserDataKeysCommand.ExecuteNonQuery(); + } + } + } + } + + private void DeletePeople(IDbConnection connection, IDbTransaction transaction, Guid id) + { + using (var deletePeopleCommand = connection.CreateCommand()) + { + deletePeopleCommand.CommandText = "delete from People where ItemId=@Id"; + deletePeopleCommand.Parameters.Add(deletePeopleCommand, "@Id"); + + + deletePeopleCommand.GetParameter(0).Value = id; + deletePeopleCommand.Transaction = transaction; + + deletePeopleCommand.ExecuteNonQuery(); } } @@ -3597,69 +3678,85 @@ namespace MediaBrowser.Server.Implementations.Persistence var cancellationToken = CancellationToken.None; - await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); - - IDbTransaction transaction = null; - - try + using (var connection = await CreateConnection().ConfigureAwait(false)) { - transaction = _connection.BeginTransaction(); + IDbTransaction transaction = null; - // First delete - _deletePeopleCommand.GetParameter(0).Value = itemId; - _deletePeopleCommand.Transaction = transaction; - - _deletePeopleCommand.ExecuteNonQuery(); - - var listIndex = 0; - - foreach (var person in people) + try { - cancellationToken.ThrowIfCancellationRequested(); + transaction = connection.BeginTransaction(); - _savePersonCommand.GetParameter(0).Value = itemId; - _savePersonCommand.GetParameter(1).Value = person.Name; - _savePersonCommand.GetParameter(2).Value = person.Role; - _savePersonCommand.GetParameter(3).Value = person.Type; - _savePersonCommand.GetParameter(4).Value = person.SortOrder; - _savePersonCommand.GetParameter(5).Value = listIndex; + // First delete + DeletePeople(connection, transaction, itemId); - _savePersonCommand.Transaction = transaction; + var listIndex = 0; + + if (people.Count > 0) + { + using (var savePersonCommand = connection.CreateCommand()) + { + savePersonCommand.CommandText = "insert into People (ItemId, Name, Role, PersonType, SortOrder, ListOrder) values (@ItemId, @Name, @Role, @PersonType, @SortOrder, @ListOrder)"; + savePersonCommand.Parameters.Add(savePersonCommand, "@ItemId"); + savePersonCommand.Parameters.Add(savePersonCommand, "@Name"); + savePersonCommand.Parameters.Add(savePersonCommand, "@Role"); + savePersonCommand.Parameters.Add(savePersonCommand, "@PersonType"); + savePersonCommand.Parameters.Add(savePersonCommand, "@SortOrder"); + savePersonCommand.Parameters.Add(savePersonCommand, "@ListOrder"); + + if (people.Count > 1) + { + savePersonCommand.Prepare(); + } + + foreach (var person in people) + { + cancellationToken.ThrowIfCancellationRequested(); + + savePersonCommand.GetParameter(0).Value = itemId; + savePersonCommand.GetParameter(1).Value = person.Name; + savePersonCommand.GetParameter(2).Value = person.Role; + savePersonCommand.GetParameter(3).Value = person.Type; + savePersonCommand.GetParameter(4).Value = person.SortOrder; + savePersonCommand.GetParameter(5).Value = listIndex; + + savePersonCommand.Transaction = transaction; + + savePersonCommand.ExecuteNonQuery(); + listIndex++; + } + } + } + + transaction.Commit(); - _savePersonCommand.ExecuteNonQuery(); - listIndex++; } - - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + catch (OperationCanceledException) { - transaction.Rollback(); + if (transaction != null) + { + transaction.Rollback(); + } + + throw; } - - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save people:", e); - - if (transaction != null) + catch (Exception e) { - transaction.Rollback(); - } + Logger.ErrorException("Failed to save people:", e); - throw; - } - finally - { - if (transaction != null) + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally { - transaction.Dispose(); + if (transaction != null) + { + transaction.Dispose(); + } } - - WriteLock.Release(); } } @@ -3699,42 +3796,61 @@ namespace MediaBrowser.Server.Implementations.Persistence var list = new List(); - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - var cmdText = "select " + string.Join(",", _mediaStreamSaveColumns) + " from mediastreams where"; - - cmdText += " ItemId=@ItemId"; - cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = query.ItemId; - - if (query.Type.HasValue) + using (var cmd = connection.CreateCommand()) { - cmdText += " AND StreamType=@StreamType"; - cmd.Parameters.Add(cmd, "@StreamType", DbType.String).Value = query.Type.Value.ToString(); - } + var cmdText = "select " + string.Join(",", _mediaStreamSaveColumns) + " from mediastreams where"; - if (query.Index.HasValue) - { - cmdText += " AND StreamIndex=@StreamIndex"; - cmd.Parameters.Add(cmd, "@StreamIndex", DbType.Int32).Value = query.Index.Value; - } + cmdText += " ItemId=@ItemId"; + cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = query.ItemId; - cmdText += " order by StreamIndex ASC"; - - cmd.CommandText = cmdText; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) - { - while (reader.Read()) + if (query.Type.HasValue) { - list.Add(GetMediaStream(reader)); + cmdText += " AND StreamType=@StreamType"; + cmd.Parameters.Add(cmd, "@StreamType", DbType.String).Value = query.Type.Value.ToString(); + } + + if (query.Index.HasValue) + { + cmdText += " AND StreamIndex=@StreamIndex"; + cmd.Parameters.Add(cmd, "@StreamIndex", DbType.Int32).Value = query.Index.Value; + } + + cmdText += " order by StreamIndex ASC"; + + cmd.CommandText = cmdText; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) + { + list.Add(GetMediaStream(reader)); + } } } - } - return list; + return list; + } } - public async Task SaveMediaStreams(Guid id, IEnumerable streams, CancellationToken cancellationToken) + private void DeleteMediaStreams(IDbConnection connection, IDbTransaction transaction, Guid id) + { + using (var deleteStreamsCommand = connection.CreateCommand()) + { + // MediaStreams + deleteStreamsCommand.CommandText = "delete from mediastreams where ItemId=@ItemId"; + deleteStreamsCommand.Parameters.Add(deleteStreamsCommand, "@ItemId"); + + deleteStreamsCommand.GetParameter(0).Value = id; + + deleteStreamsCommand.Transaction = transaction; + + deleteStreamsCommand.ExecuteNonQuery(); + } + } + + public async Task SaveMediaStreams(Guid id, List streams, CancellationToken cancellationToken) { CheckDisposed(); @@ -3750,100 +3866,115 @@ namespace MediaBrowser.Server.Implementations.Persistence cancellationToken.ThrowIfCancellationRequested(); - await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); - - IDbTransaction transaction = null; - - try + using (var connection = await CreateConnection().ConfigureAwait(false)) { - transaction = _connection.BeginTransaction(); + IDbTransaction transaction = null; - // First delete chapters - _deleteStreamsCommand.GetParameter(0).Value = id; - - _deleteStreamsCommand.Transaction = transaction; - - _deleteStreamsCommand.ExecuteNonQuery(); - - foreach (var stream in streams) + try { - cancellationToken.ThrowIfCancellationRequested(); + transaction = connection.BeginTransaction(); - var index = 0; + // First delete + DeleteMediaStreams(connection, transaction, id); - _saveStreamCommand.GetParameter(index++).Value = id; - _saveStreamCommand.GetParameter(index++).Value = stream.Index; - _saveStreamCommand.GetParameter(index++).Value = stream.Type.ToString(); - _saveStreamCommand.GetParameter(index++).Value = stream.Codec; - _saveStreamCommand.GetParameter(index++).Value = stream.Language; - _saveStreamCommand.GetParameter(index++).Value = stream.ChannelLayout; - _saveStreamCommand.GetParameter(index++).Value = stream.Profile; - _saveStreamCommand.GetParameter(index++).Value = stream.AspectRatio; - _saveStreamCommand.GetParameter(index++).Value = stream.Path; + if (streams.Count > 0) + { + using (var saveStreamCommand = connection.CreateCommand()) + { + saveStreamCommand.CommandText = string.Format("replace into mediastreams ({0}) values ({1})", + string.Join(",", _mediaStreamSaveColumns), + string.Join(",", _mediaStreamSaveColumns.Select(i => "@" + i).ToArray())); - _saveStreamCommand.GetParameter(index++).Value = stream.IsInterlaced; + foreach (var col in _mediaStreamSaveColumns) + { + saveStreamCommand.Parameters.Add(saveStreamCommand, "@" + col); + } - _saveStreamCommand.GetParameter(index++).Value = stream.BitRate; - _saveStreamCommand.GetParameter(index++).Value = stream.Channels; - _saveStreamCommand.GetParameter(index++).Value = stream.SampleRate; + if (streams.Count > 1) + { + saveStreamCommand.Prepare(); + } - _saveStreamCommand.GetParameter(index++).Value = stream.IsDefault; - _saveStreamCommand.GetParameter(index++).Value = stream.IsForced; - _saveStreamCommand.GetParameter(index++).Value = stream.IsExternal; + foreach (var stream in streams) + { + cancellationToken.ThrowIfCancellationRequested(); - _saveStreamCommand.GetParameter(index++).Value = stream.Width; - _saveStreamCommand.GetParameter(index++).Value = stream.Height; - _saveStreamCommand.GetParameter(index++).Value = stream.AverageFrameRate; - _saveStreamCommand.GetParameter(index++).Value = stream.RealFrameRate; - _saveStreamCommand.GetParameter(index++).Value = stream.Level; - _saveStreamCommand.GetParameter(index++).Value = stream.PixelFormat; - _saveStreamCommand.GetParameter(index++).Value = stream.BitDepth; - _saveStreamCommand.GetParameter(index++).Value = stream.IsAnamorphic; - _saveStreamCommand.GetParameter(index++).Value = stream.RefFrames; + var index = 0; - _saveStreamCommand.GetParameter(index++).Value = stream.CodecTag; - _saveStreamCommand.GetParameter(index++).Value = stream.Comment; - _saveStreamCommand.GetParameter(index++).Value = stream.NalLengthSize; - _saveStreamCommand.GetParameter(index++).Value = stream.IsAVC; - _saveStreamCommand.GetParameter(index++).Value = stream.Title; + saveStreamCommand.GetParameter(index++).Value = id; + saveStreamCommand.GetParameter(index++).Value = stream.Index; + saveStreamCommand.GetParameter(index++).Value = stream.Type.ToString(); + saveStreamCommand.GetParameter(index++).Value = stream.Codec; + saveStreamCommand.GetParameter(index++).Value = stream.Language; + saveStreamCommand.GetParameter(index++).Value = stream.ChannelLayout; + saveStreamCommand.GetParameter(index++).Value = stream.Profile; + saveStreamCommand.GetParameter(index++).Value = stream.AspectRatio; + saveStreamCommand.GetParameter(index++).Value = stream.Path; - _saveStreamCommand.GetParameter(index++).Value = stream.TimeBase; - _saveStreamCommand.GetParameter(index++).Value = stream.CodecTimeBase; + saveStreamCommand.GetParameter(index++).Value = stream.IsInterlaced; - _saveStreamCommand.Transaction = transaction; - _saveStreamCommand.ExecuteNonQuery(); + saveStreamCommand.GetParameter(index++).Value = stream.BitRate; + saveStreamCommand.GetParameter(index++).Value = stream.Channels; + saveStreamCommand.GetParameter(index++).Value = stream.SampleRate; + + saveStreamCommand.GetParameter(index++).Value = stream.IsDefault; + saveStreamCommand.GetParameter(index++).Value = stream.IsForced; + saveStreamCommand.GetParameter(index++).Value = stream.IsExternal; + + saveStreamCommand.GetParameter(index++).Value = stream.Width; + saveStreamCommand.GetParameter(index++).Value = stream.Height; + saveStreamCommand.GetParameter(index++).Value = stream.AverageFrameRate; + saveStreamCommand.GetParameter(index++).Value = stream.RealFrameRate; + saveStreamCommand.GetParameter(index++).Value = stream.Level; + saveStreamCommand.GetParameter(index++).Value = stream.PixelFormat; + saveStreamCommand.GetParameter(index++).Value = stream.BitDepth; + saveStreamCommand.GetParameter(index++).Value = stream.IsAnamorphic; + saveStreamCommand.GetParameter(index++).Value = stream.RefFrames; + + saveStreamCommand.GetParameter(index++).Value = stream.CodecTag; + saveStreamCommand.GetParameter(index++).Value = stream.Comment; + saveStreamCommand.GetParameter(index++).Value = stream.NalLengthSize; + saveStreamCommand.GetParameter(index++).Value = stream.IsAVC; + saveStreamCommand.GetParameter(index++).Value = stream.Title; + + saveStreamCommand.GetParameter(index++).Value = stream.TimeBase; + saveStreamCommand.GetParameter(index++).Value = stream.CodecTimeBase; + + saveStreamCommand.Transaction = transaction; + saveStreamCommand.ExecuteNonQuery(); + } + } + } + + transaction.Commit(); } - - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + catch (OperationCanceledException) { - transaction.Rollback(); + if (transaction != null) + { + transaction.Rollback(); + } + + throw; } - - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save media streams:", e); - - if (transaction != null) + catch (Exception e) { - transaction.Rollback(); - } + Logger.ErrorException("Failed to save media streams:", e); - throw; - } - finally - { - if (transaction != null) + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally { - transaction.Dispose(); + if (transaction != null) + { + transaction.Dispose(); + } } - - WriteLock.Release(); } } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs index 0ce27fa5a2..da0f584d53 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs @@ -45,12 +45,7 @@ namespace MediaBrowser.Server.Implementations.Persistence "create table if not exists userdata (key nvarchar, userId GUID, rating float null, played bit, playCount int, isFavorite bit, playbackPositionTicks bigint, lastPlayedDate datetime null)", "create index if not exists idx_userdata on userdata(key)", - "create unique index if not exists userdataindex on userdata (key, userId)", - - //pragmas - "pragma temp_store = memory", - - "pragma shrink_memory" + "create unique index if not exists userdataindex on userdata (key, userId)" }; connection.RunQueries(queries, Logger); diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs index 4c07a60181..25ab60ca50 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs @@ -52,9 +52,6 @@ namespace MediaBrowser.Server.Implementations.Persistence "create index if not exists idx_users on users(guid)", "create table if not exists schema_version (table_name primary key, version)", - //pragmas - "pragma temp_store = memory", - "pragma shrink_memory" }; diff --git a/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs b/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs index 3013510de1..74a552dccc 100644 --- a/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs +++ b/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs @@ -32,12 +32,7 @@ namespace MediaBrowser.Server.Implementations.Security string[] queries = { "create table if not exists AccessTokens (Id GUID PRIMARY KEY, AccessToken TEXT NOT NULL, DeviceId TEXT, AppName TEXT, AppVersion TEXT, DeviceName TEXT, UserId TEXT, IsActive BIT, DateCreated DATETIME NOT NULL, DateRevoked DATETIME)", - "create index if not exists idx_AccessTokens on AccessTokens(Id)", - - //pragmas - "pragma temp_store = memory", - - "pragma shrink_memory" + "create index if not exists idx_AccessTokens on AccessTokens(Id)" }; connection.RunQueries(queries, Logger); diff --git a/MediaBrowser.Server.Implementations/Social/SharingRepository.cs b/MediaBrowser.Server.Implementations/Social/SharingRepository.cs index 8a895037e7..c4243c1a76 100644 --- a/MediaBrowser.Server.Implementations/Social/SharingRepository.cs +++ b/MediaBrowser.Server.Implementations/Social/SharingRepository.cs @@ -31,9 +31,6 @@ namespace MediaBrowser.Server.Implementations.Social "create table if not exists Shares (Id GUID, ItemId TEXT, UserId TEXT, ExpirationDate DateTime, PRIMARY KEY (Id))", "create index if not exists idx_Shares on Shares(Id)", - //pragmas - "pragma temp_store = memory", - "pragma shrink_memory" }; diff --git a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs index 5b623cf2ad..a1ed66a995 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs @@ -43,9 +43,6 @@ namespace MediaBrowser.Server.Implementations.Sync "create index if not exists idx_SyncJobItems1 on SyncJobItems(Id)", "create index if not exists idx_SyncJobItems2 on SyncJobItems(TargetId)", - //pragmas - "pragma temp_store = memory", - "pragma shrink_memory" }; From d7edd499d23c12252cf78e33e5ee2c96a952a6f6 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 11 Jun 2016 21:25:20 -0400 Subject: [PATCH 4/6] update organizer db --- .../Persistence/BaseSqliteRepository.cs | 25 - .../SqliteFileOrganizationRepository.cs | 465 +++++++++--------- .../ApplicationHost.cs | 2 +- 3 files changed, 224 insertions(+), 268 deletions(-) diff --git a/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs b/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs index c6e7952294..709971797f 100644 --- a/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs @@ -8,7 +8,6 @@ namespace MediaBrowser.Server.Implementations.Persistence { public abstract class BaseSqliteRepository : IDisposable { - protected readonly SemaphoreSlim WriteLock = new SemaphoreSlim(1, 1); protected readonly IDbConnector DbConnector; protected ILogger Logger; @@ -46,7 +45,6 @@ namespace MediaBrowser.Server.Implementations.Persistence { _disposed = true; Dispose(true); - GC.SuppressFinalize(this); } protected async Task Vacuum(IDbConnection connection) @@ -69,35 +67,12 @@ namespace MediaBrowser.Server.Implementations.Persistence } } - private readonly object _disposeLock = new object(); - /// /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool dispose) { - if (dispose) - { - try - { - lock (_disposeLock) - { - WriteLock.Wait(); - - CloseConnection(); - } - } - catch (Exception ex) - { - Logger.ErrorException("Error disposing database", ex); - } - } - } - - protected virtual void CloseConnection() - { - } } } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs index d7e8afdd4c..7a5e000905 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs @@ -16,69 +16,29 @@ namespace MediaBrowser.Server.Implementations.Persistence { public class SqliteFileOrganizationRepository : BaseSqliteRepository, IFileOrganizationRepository, IDisposable { - private IDbConnection _connection; - - private readonly IServerApplicationPaths _appPaths; - private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - private IDbCommand _saveResultCommand; - private IDbCommand _deleteResultCommand; - private IDbCommand _deleteAllCommand; - public SqliteFileOrganizationRepository(ILogManager logManager, IServerApplicationPaths appPaths, IDbConnector connector) : base(logManager, connector) { - _appPaths = appPaths; + DbFilePath = Path.Combine(appPaths.DataPath, "fileorganization.db"); } /// /// Opens the connection to the database /// /// Task. - public async Task Initialize(IDbConnector dbConnector) + public async Task Initialize() { - var dbFile = Path.Combine(_appPaths.DataPath, "fileorganization.db"); - - _connection = await dbConnector.Connect(dbFile, false).ConfigureAwait(false); - - string[] queries = { + using (var connection = await CreateConnection().ConfigureAwait(false)) + { + string[] queries = { "create table if not exists FileOrganizerResults (ResultId GUID PRIMARY KEY, OriginalPath TEXT, TargetPath TEXT, FileLength INT, OrganizationDate datetime, Status TEXT, OrganizationType TEXT, StatusMessage TEXT, ExtractedName TEXT, ExtractedYear int null, ExtractedSeasonNumber int null, ExtractedEpisodeNumber int null, ExtractedEndingEpisodeNumber, DuplicatePaths TEXT int null)", "create index if not exists idx_FileOrganizerResults on FileOrganizerResults(ResultId)" }; - _connection.RunQueries(queries, Logger); - - PrepareStatements(); - } - - private void PrepareStatements() - { - _saveResultCommand = _connection.CreateCommand(); - _saveResultCommand.CommandText = "replace into FileOrganizerResults (ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths) values (@ResultId, @OriginalPath, @TargetPath, @FileLength, @OrganizationDate, @Status, @OrganizationType, @StatusMessage, @ExtractedName, @ExtractedYear, @ExtractedSeasonNumber, @ExtractedEpisodeNumber, @ExtractedEndingEpisodeNumber, @DuplicatePaths)"; - - _saveResultCommand.Parameters.Add(_saveResultCommand, "@ResultId"); - _saveResultCommand.Parameters.Add(_saveResultCommand, "@OriginalPath"); - _saveResultCommand.Parameters.Add(_saveResultCommand, "@TargetPath"); - _saveResultCommand.Parameters.Add(_saveResultCommand, "@FileLength"); - _saveResultCommand.Parameters.Add(_saveResultCommand, "@OrganizationDate"); - _saveResultCommand.Parameters.Add(_saveResultCommand, "@Status"); - _saveResultCommand.Parameters.Add(_saveResultCommand, "@OrganizationType"); - _saveResultCommand.Parameters.Add(_saveResultCommand, "@StatusMessage"); - _saveResultCommand.Parameters.Add(_saveResultCommand, "@ExtractedName"); - _saveResultCommand.Parameters.Add(_saveResultCommand, "@ExtractedYear"); - _saveResultCommand.Parameters.Add(_saveResultCommand, "@ExtractedSeasonNumber"); - _saveResultCommand.Parameters.Add(_saveResultCommand, "@ExtractedEpisodeNumber"); - _saveResultCommand.Parameters.Add(_saveResultCommand, "@ExtractedEndingEpisodeNumber"); - _saveResultCommand.Parameters.Add(_saveResultCommand, "@DuplicatePaths"); - - _deleteResultCommand = _connection.CreateCommand(); - _deleteResultCommand.CommandText = "delete from FileOrganizerResults where ResultId = @ResultId"; - - _deleteResultCommand.Parameters.Add(_saveResultCommand, "@ResultId"); - - _deleteAllCommand = _connection.CreateCommand(); - _deleteAllCommand.CommandText = "delete from FileOrganizerResults"; + connection.RunQueries(queries, Logger); + } } public async Task SaveResult(FileOrganizationResult result, CancellationToken cancellationToken) @@ -90,65 +50,84 @@ namespace MediaBrowser.Server.Implementations.Persistence cancellationToken.ThrowIfCancellationRequested(); - await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); - - IDbTransaction transaction = null; - - try + using (var connection = await CreateConnection().ConfigureAwait(false)) { - transaction = _connection.BeginTransaction(); - - var index = 0; - - _saveResultCommand.GetParameter(index++).Value = new Guid(result.Id); - _saveResultCommand.GetParameter(index++).Value = result.OriginalPath; - _saveResultCommand.GetParameter(index++).Value = result.TargetPath; - _saveResultCommand.GetParameter(index++).Value = result.FileSize; - _saveResultCommand.GetParameter(index++).Value = result.Date; - _saveResultCommand.GetParameter(index++).Value = result.Status.ToString(); - _saveResultCommand.GetParameter(index++).Value = result.Type.ToString(); - _saveResultCommand.GetParameter(index++).Value = result.StatusMessage; - _saveResultCommand.GetParameter(index++).Value = result.ExtractedName; - _saveResultCommand.GetParameter(index++).Value = result.ExtractedYear; - _saveResultCommand.GetParameter(index++).Value = result.ExtractedSeasonNumber; - _saveResultCommand.GetParameter(index++).Value = result.ExtractedEpisodeNumber; - _saveResultCommand.GetParameter(index++).Value = result.ExtractedEndingEpisodeNumber; - _saveResultCommand.GetParameter(index).Value = string.Join("|", result.DuplicatePaths.ToArray()); - - _saveResultCommand.Transaction = transaction; - - _saveResultCommand.ExecuteNonQuery(); - - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + using (var saveResultCommand = connection.CreateCommand()) { - transaction.Rollback(); + saveResultCommand.CommandText = "replace into FileOrganizerResults (ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths) values (@ResultId, @OriginalPath, @TargetPath, @FileLength, @OrganizationDate, @Status, @OrganizationType, @StatusMessage, @ExtractedName, @ExtractedYear, @ExtractedSeasonNumber, @ExtractedEpisodeNumber, @ExtractedEndingEpisodeNumber, @DuplicatePaths)"; + + saveResultCommand.Parameters.Add(saveResultCommand, "@ResultId"); + saveResultCommand.Parameters.Add(saveResultCommand, "@OriginalPath"); + saveResultCommand.Parameters.Add(saveResultCommand, "@TargetPath"); + saveResultCommand.Parameters.Add(saveResultCommand, "@FileLength"); + saveResultCommand.Parameters.Add(saveResultCommand, "@OrganizationDate"); + saveResultCommand.Parameters.Add(saveResultCommand, "@Status"); + saveResultCommand.Parameters.Add(saveResultCommand, "@OrganizationType"); + saveResultCommand.Parameters.Add(saveResultCommand, "@StatusMessage"); + saveResultCommand.Parameters.Add(saveResultCommand, "@ExtractedName"); + saveResultCommand.Parameters.Add(saveResultCommand, "@ExtractedYear"); + saveResultCommand.Parameters.Add(saveResultCommand, "@ExtractedSeasonNumber"); + saveResultCommand.Parameters.Add(saveResultCommand, "@ExtractedEpisodeNumber"); + saveResultCommand.Parameters.Add(saveResultCommand, "@ExtractedEndingEpisodeNumber"); + saveResultCommand.Parameters.Add(saveResultCommand, "@DuplicatePaths"); + + IDbTransaction transaction = null; + + try + { + transaction = connection.BeginTransaction(); + + var index = 0; + + saveResultCommand.GetParameter(index++).Value = new Guid(result.Id); + saveResultCommand.GetParameter(index++).Value = result.OriginalPath; + saveResultCommand.GetParameter(index++).Value = result.TargetPath; + saveResultCommand.GetParameter(index++).Value = result.FileSize; + saveResultCommand.GetParameter(index++).Value = result.Date; + saveResultCommand.GetParameter(index++).Value = result.Status.ToString(); + saveResultCommand.GetParameter(index++).Value = result.Type.ToString(); + saveResultCommand.GetParameter(index++).Value = result.StatusMessage; + saveResultCommand.GetParameter(index++).Value = result.ExtractedName; + saveResultCommand.GetParameter(index++).Value = result.ExtractedYear; + saveResultCommand.GetParameter(index++).Value = result.ExtractedSeasonNumber; + saveResultCommand.GetParameter(index++).Value = result.ExtractedEpisodeNumber; + saveResultCommand.GetParameter(index++).Value = result.ExtractedEndingEpisodeNumber; + saveResultCommand.GetParameter(index).Value = string.Join("|", result.DuplicatePaths.ToArray()); + + saveResultCommand.Transaction = transaction; + + saveResultCommand.ExecuteNonQuery(); + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save FileOrganizationResult:", e); + + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + } } - - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save FileOrganizationResult:", e); - - if (transaction != null) - { - transaction.Rollback(); - } - - throw; - } - finally - { - if (transaction != null) - { - transaction.Dispose(); - } - - WriteLock.Release(); } } @@ -159,100 +138,110 @@ namespace MediaBrowser.Server.Implementations.Persistence throw new ArgumentNullException("id"); } - await WriteLock.WaitAsync().ConfigureAwait(false); - - IDbTransaction transaction = null; - - try + using (var connection = await CreateConnection().ConfigureAwait(false)) { - transaction = _connection.BeginTransaction(); - - _deleteResultCommand.GetParameter(0).Value = new Guid(id); - - _deleteResultCommand.Transaction = transaction; - - _deleteResultCommand.ExecuteNonQuery(); - - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + using (var deleteResultCommand = connection.CreateCommand()) { - transaction.Rollback(); + deleteResultCommand.CommandText = "delete from FileOrganizerResults where ResultId = @ResultId"; + + deleteResultCommand.Parameters.Add(deleteResultCommand, "@ResultId"); + + IDbTransaction transaction = null; + + try + { + transaction = connection.BeginTransaction(); + + deleteResultCommand.GetParameter(0).Value = new Guid(id); + + deleteResultCommand.Transaction = transaction; + + deleteResultCommand.ExecuteNonQuery(); + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to delete FileOrganizationResult:", e); + + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + } } - - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to delete FileOrganizationResult:", e); - - if (transaction != null) - { - transaction.Rollback(); - } - - throw; - } - finally - { - if (transaction != null) - { - transaction.Dispose(); - } - - WriteLock.Release(); } } public async Task DeleteAll() { - await WriteLock.WaitAsync().ConfigureAwait(false); - - IDbTransaction transaction = null; - - try + using (var connection = await CreateConnection().ConfigureAwait(false)) { - transaction = _connection.BeginTransaction(); - - _deleteAllCommand.Transaction = transaction; - - _deleteAllCommand.ExecuteNonQuery(); - - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + using (var cmd = connection.CreateCommand()) { - transaction.Rollback(); + cmd.CommandText = "delete from FileOrganizerResults"; + + IDbTransaction transaction = null; + + try + { + transaction = connection.BeginTransaction(); + + cmd.Transaction = transaction; + + cmd.ExecuteNonQuery(); + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to delete results", e); + + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + } } - - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to delete results", e); - - if (transaction != null) - { - transaction.Rollback(); - } - - throw; - } - finally - { - if (transaction != null) - { - transaction.Dispose(); - } - - WriteLock.Release(); } } - + public QueryResult GetResults(FileOrganizationResultQuery query) { if (query == null) @@ -260,46 +249,49 @@ namespace MediaBrowser.Server.Implementations.Persistence throw new ArgumentNullException("query"); } - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = "SELECT ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults"; - - if (query.StartIndex.HasValue && query.StartIndex.Value > 0) + using (var cmd = connection.CreateCommand()) { - cmd.CommandText += string.Format(" WHERE ResultId NOT IN (SELECT ResultId FROM FileOrganizerResults ORDER BY OrganizationDate desc LIMIT {0})", - query.StartIndex.Value.ToString(_usCulture)); - } + cmd.CommandText = "SELECT ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults"; - cmd.CommandText += " ORDER BY OrganizationDate desc"; - - if (query.Limit.HasValue) - { - cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture); - } - - cmd.CommandText += "; select count (ResultId) from FileOrganizerResults"; - - var list = new List(); - var count = 0; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) - { - while (reader.Read()) + if (query.StartIndex.HasValue && query.StartIndex.Value > 0) { - list.Add(GetResult(reader)); + cmd.CommandText += string.Format(" WHERE ResultId NOT IN (SELECT ResultId FROM FileOrganizerResults ORDER BY OrganizationDate desc LIMIT {0})", + query.StartIndex.Value.ToString(_usCulture)); } - if (reader.NextResult() && reader.Read()) - { - count = reader.GetInt32(0); - } - } + cmd.CommandText += " ORDER BY OrganizationDate desc"; - return new QueryResult() - { - Items = list.ToArray(), - TotalRecordCount = count - }; + if (query.Limit.HasValue) + { + cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture); + } + + cmd.CommandText += "; select count (ResultId) from FileOrganizerResults"; + + var list = new List(); + var count = 0; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) + { + while (reader.Read()) + { + list.Add(GetResult(reader)); + } + + if (reader.NextResult() && reader.Read()) + { + count = reader.GetInt32(0); + } + } + + return new QueryResult() + { + Items = list.ToArray(), + TotalRecordCount = count + }; + } } } @@ -310,24 +302,27 @@ namespace MediaBrowser.Server.Implementations.Persistence throw new ArgumentNullException("id"); } - var guid = new Guid(id); - - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = "select ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults where ResultId=@Id"; + var guid = new Guid(id); - cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) + using (var cmd = connection.CreateCommand()) { - if (reader.Read()) + cmd.CommandText = "select ResultId, OriginalPath, TargetPath, FileLength, OrganizationDate, Status, OrganizationType, StatusMessage, ExtractedName, ExtractedYear, ExtractedSeasonNumber, ExtractedEpisodeNumber, ExtractedEndingEpisodeNumber, DuplicatePaths from FileOrganizerResults where ResultId=@Id"; + + cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) { - return GetResult(reader); + if (reader.Read()) + { + return GetResult(reader); + } } } - } - return null; + return null; + } } public FileOrganizationResult GetResult(IDataReader reader) @@ -409,19 +404,5 @@ namespace MediaBrowser.Server.Implementations.Persistence return result; } - - protected override void CloseConnection() - { - if (_connection != null) - { - if (_connection.IsOpen()) - { - _connection.Close(); - } - - _connection.Dispose(); - _connection = null; - } - } } } diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index 9e869478ce..b0cf93673c 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -691,7 +691,7 @@ namespace MediaBrowser.Server.Startup.Common { var repo = new SqliteFileOrganizationRepository(LogManager, ServerConfigurationManager.ApplicationPaths, NativeApp.GetDbConnector()); - await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false); + await repo.Initialize().ConfigureAwait(false); return repo; } From f378a2c789a7a12c3f848e262885b5bdd137754e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 12 Jun 2016 01:03:52 -0400 Subject: [PATCH 5/6] update item queries --- MediaBrowser.Api/StartupWizardService.cs | 2 +- .../Channels/ChannelItemInfo.cs | 2 + MediaBrowser.Controller/Entities/BaseItem.cs | 3 + .../Entities/InternalItemsQuery.cs | 1 + MediaBrowser.Controller/Entities/TV/Season.cs | 27 +----- MediaBrowser.Controller/Entities/TV/Series.cs | 6 +- .../TV/MissingEpisodeProvider.cs | 3 +- .../Channels/ChannelManager.cs | 1 + .../Library/UserViewManager.cs | 37 ++++---- .../LiveTv/LiveTvManager.cs | 2 +- .../Persistence/SqliteItemRepository.cs | 86 +++++++++++-------- 11 files changed, 83 insertions(+), 87 deletions(-) diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs index dbb6478a18..21f87a6117 100644 --- a/MediaBrowser.Api/StartupWizardService.cs +++ b/MediaBrowser.Api/StartupWizardService.cs @@ -114,7 +114,7 @@ namespace MediaBrowser.Api config.EnableStandaloneMusicKeys = true; config.EnableCaseSensitiveItemIds = true; config.EnableFolderView = true; - config.SchemaVersion = 89; + config.SchemaVersion = 91; } public void Post(UpdateStartupConfiguration request) diff --git a/MediaBrowser.Controller/Channels/ChannelItemInfo.cs b/MediaBrowser.Controller/Channels/ChannelItemInfo.cs index 587023ab48..6135240e91 100644 --- a/MediaBrowser.Controller/Channels/ChannelItemInfo.cs +++ b/MediaBrowser.Controller/Channels/ChannelItemInfo.cs @@ -53,6 +53,8 @@ namespace MediaBrowser.Controller.Channels public bool IsInfiniteStream { get; set; } + public string HomePageUrl { get; set; } + public ChannelItemInfo() { MediaSources = new List(); diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index a45a462df4..33fd03e15d 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -71,6 +71,9 @@ namespace MediaBrowser.Controller.Entities public List ImageInfos { get; set; } + [IgnoreDataMember] + public bool IsVirtualItem { get; set; } + /// /// Gets or sets the album. /// diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 04dfc94912..5b9d94fc26 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -117,6 +117,7 @@ namespace MediaBrowser.Controller.Entities public bool? IsCurrentSchema { get; set; } public bool? HasDeadParentId { get; set; } public bool? IsOffline { get; set; } + public bool? IsVirtualItem { get; set; } public Guid? ParentId { get; set; } public string[] AncestorIds { get; set; } diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index f07d4be13e..c984a2832a 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -128,39 +128,16 @@ namespace MediaBrowser.Controller.Entities.TV return IndexNumber != null ? IndexNumber.Value.ToString("0000") : Name; } - public override bool RequiresRefresh() - { - var result = base.RequiresRefresh(); - - if (!result) - { - if (!IsVirtualItem.HasValue) - { - return true; - } - } - - return result; - } - - [IgnoreDataMember] - public bool? IsVirtualItem { get; set; } - [IgnoreDataMember] public bool IsMissingSeason { - get { return (IsVirtualItem ?? DetectIsVirtualItem()) && !IsUnaired; } + get { return (IsVirtualItem) && !IsUnaired; } } [IgnoreDataMember] public bool IsVirtualUnaired { - get { return (IsVirtualItem ?? DetectIsVirtualItem()) && IsUnaired; } - } - - private bool DetectIsVirtualItem() - { - return LocationType == LocationType.Virtual && GetEpisodes().All(i => i.LocationType == LocationType.Virtual); + get { return (IsVirtualItem) && IsUnaired; } } [IgnoreDataMember] diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 2f2968db8f..cc1378ae1a 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -92,10 +92,7 @@ namespace MediaBrowser.Controller.Entities.TV { get { - return GetRecursiveChildren(i => i is Episode) - .Select(i => i.DateCreated) - .OrderByDescending(i => i) - .FirstOrDefault(); + return DateLastMediaAdded ?? DateTime.MinValue; } } @@ -240,6 +237,7 @@ namespace MediaBrowser.Controller.Entities.TV AncestorWithPresentationUniqueKey = PresentationUniqueKey, IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name }, SortBy = new[] { ItemSortBy.SortName } + }).ToList(); var allSeriesEpisodes = allItems.OfType().ToList(); diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs index 2a3150c78b..4e2d9a8d2d 100644 --- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs @@ -428,7 +428,8 @@ namespace MediaBrowser.Providers.TV Name = name, IndexNumber = episodeNumber, ParentIndexNumber = seasonNumber, - Id = _libraryManager.GetNewItemId((series.Id + seasonNumber.ToString(_usCulture) + name), typeof(Episode)) + Id = _libraryManager.GetNewItemId((series.Id + seasonNumber.ToString(_usCulture) + name), typeof(Episode)), + IsVirtualItem = true }; episode.SetParent(season); diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs index 6a9842cb2e..8dc2091980 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs @@ -1307,6 +1307,7 @@ namespace MediaBrowser.Server.Implementations.Channels item.OfficialRating = info.OfficialRating; item.DateCreated = info.DateCreated ?? DateTime.UtcNow; item.Tags = info.Tags; + item.HomePageUrl = info.HomePageUrl; } var trailer = item as Trailer; diff --git a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs index e6a571f07d..319e715c33 100644 --- a/MediaBrowser.Server.Implementations/Library/UserViewManager.cs +++ b/MediaBrowser.Server.Implementations/Library/UserViewManager.cs @@ -202,23 +202,7 @@ namespace MediaBrowser.Server.Implementations.Library { var user = _userManager.GetUserById(request.UserId); - var includeTypes = request.IncludeItemTypes; - - var currentUser = user; - - var libraryItems = GetItemsForLatestItems(user, request.ParentId, includeTypes, request.Limit ?? 10).Where(i => - { - if (request.IsPlayed.HasValue) - { - var val = request.IsPlayed.Value; - if (i is Video && i.IsPlayed(currentUser) != val) - { - return false; - } - } - - return true; - }); + var libraryItems = GetItemsForLatestItems(user, request); var list = new List>>(); @@ -254,8 +238,13 @@ namespace MediaBrowser.Server.Implementations.Library return list; } - private IEnumerable GetItemsForLatestItems(User user, string parentId, string[] includeItemTypes, int limit) + private IEnumerable GetItemsForLatestItems(User user, LatestItemsQuery request) { + var parentId = request.ParentId; + + var includeItemTypes = request.IncludeItemTypes; + var limit = request.Limit ?? 10; + var parentIds = string.IsNullOrEmpty(parentId) ? new string[] { } : new[] { parentId }; @@ -276,7 +265,12 @@ namespace MediaBrowser.Server.Implementations.Library var excludeItemTypes = includeItemTypes.Length == 0 ? new[] { - typeof(Person).Name, typeof(Studio).Name, typeof(Year).Name, typeof(GameGenre).Name, typeof(MusicGenre).Name, typeof(Genre).Name + typeof(Person).Name, + typeof(Studio).Name, + typeof(Year).Name, + typeof(GameGenre).Name, + typeof(MusicGenre).Name, + typeof(Genre).Name } : new string[] { }; @@ -288,8 +282,9 @@ namespace MediaBrowser.Server.Implementations.Library IsFolder = includeItemTypes.Length == 0 ? false : (bool?)null, ExcludeItemTypes = excludeItemTypes, ExcludeLocationTypes = new[] { LocationType.Virtual }, - Limit = limit * 20, - ExcludeSourceTypes = parentIds.Length == 0 ? new[] { SourceType.Channel, SourceType.LiveTV } : new SourceType[] { } + Limit = limit * 5, + ExcludeSourceTypes = parentIds.Length == 0 ? new[] { SourceType.Channel, SourceType.LiveTV } : new SourceType[] { }, + IsPlayed = request.IsPlayed }, parentIds); } diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs index 171ed824e8..b3bd24d96d 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs @@ -952,7 +952,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv if (query.Limit.HasValue) { - internalQuery.Limit = Math.Max(query.Limit.Value * 5, 200); + internalQuery.Limit = Math.Max(query.Limit.Value * 4, 200); } if (query.HasAired.HasValue) diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 0eb56a1fc4..ba3ada7049 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -58,7 +58,9 @@ namespace MediaBrowser.Server.Implementations.Persistence private readonly string _criticReviewsPath; - public const int LatestSchemaVersion = 89; + public const int LatestSchemaVersion = 91; + + private IDbConnection _connection; /// /// Initializes a new instance of the class. @@ -88,9 +90,9 @@ namespace MediaBrowser.Server.Implementations.Persistence //AttachUserDataDb(connection); - //connection.RunQueries(new [] + //connection.RunQueries(new[] //{ - // "pragma locking_mode=EXCLUSIVE" + // "pragma locking_mode=NORMAL" //}, Logger); @@ -105,6 +107,8 @@ namespace MediaBrowser.Server.Implementations.Persistence /// Task. public async Task Initialize(IDbConnector dbConnector) { + //_connection = await CreateConnection().ConfigureAwait(false); + using (var connection = await CreateConnection().ConfigureAwait(false)) { var createMediaStreamsTableCommand @@ -115,7 +119,6 @@ namespace MediaBrowser.Server.Implementations.Persistence "create table if not exists TypedBaseItems (guid GUID primary key, type TEXT, data BLOB, ParentId GUID, Path TEXT)", "create index if not exists idx_PathTypedBaseItems on TypedBaseItems(Path)", "create index if not exists idx_ParentIdTypedBaseItems on TypedBaseItems(ParentId)", - "create index if not exists idx_TypedBaseItems2 on TypedBaseItems(Type,Guid)", "create table if not exists AncestorIds (ItemId GUID, AncestorId GUID, AncestorIdText TEXT, PRIMARY KEY (ItemId, AncestorId))", "create index if not exists idx_AncestorIds1 on AncestorIds(AncestorId)", @@ -234,9 +237,14 @@ namespace MediaBrowser.Server.Implementations.Persistence string[] postQueries = { "create index if not exists idx_PresentationUniqueKey on TypedBaseItems(PresentationUniqueKey)", + "create index if not exists idx_GuidType on TypedBaseItems(Guid,Type)", "create index if not exists idx_Type on TypedBaseItems(Type)", "create index if not exists idx_TopParentId on TypedBaseItems(TopParentId)", - "create index if not exists idx_TypeTopParentId on TypedBaseItems(Type,TopParentId)" + "create index if not exists idx_TypeTopParentId on TypedBaseItems(Type,TopParentId)", + "create index if not exists idx_TypeTopParentId2 on TypedBaseItems(TopParentId,MediaType,IsVirtualItem)", + "create index if not exists idx_TypeTopParentId3 on TypedBaseItems(TopParentId,IsFolder,IsVirtualItem)", + "create index if not exists idx_TypeTopParentId4 on TypedBaseItems(TopParentId,Type,IsVirtualItem)", + "create index if not exists idx_TypeTopParentId5 on TypedBaseItems(TopParentId,IsVirtualItem)" }; connection.RunQueries(postQueries, Logger); @@ -727,15 +735,7 @@ namespace MediaBrowser.Server.Implementations.Persistence saveItemCommand.GetParameter(index++).Value = item.Album; - var season = item as Season; - if (season != null && season.IsVirtualItem.HasValue) - { - saveItemCommand.GetParameter(index++).Value = season.IsVirtualItem.Value; - } - else - { - saveItemCommand.GetParameter(index++).Value = null; - } + saveItemCommand.GetParameter(index++).Value = item.IsVirtualItem || (!item.IsFolder && item.LocationType == LocationType.Virtual); var hasSeries = item as IHasSeries; if (hasSeries != null) @@ -1167,10 +1167,9 @@ namespace MediaBrowser.Server.Implementations.Persistence item.CriticRatingSummary = reader.GetString(57); } - var season = item as Season; - if (season != null && !reader.IsDBNull(58)) + if (!reader.IsDBNull(58)) { - season.IsVirtualItem = reader.GetBoolean(58); + item.IsVirtualItem = reader.GetBoolean(58); } return item; @@ -1651,7 +1650,7 @@ namespace MediaBrowser.Server.Implementations.Persistence var slowThreshold = 1000; #if DEBUG - slowThreshold = 100; + slowThreshold = 30; #endif if (elapsed >= slowThreshold) @@ -2196,18 +2195,6 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.Parameters.Add(cmd, "@IsFolder", DbType.Boolean).Value = query.IsFolder; } - var includeTypes = query.IncludeItemTypes.SelectMany(MapIncludeItemTypes).ToArray(); - if (includeTypes.Length == 1) - { - whereClauses.Add("type=@type"); - cmd.Parameters.Add(cmd, "@type", DbType.String).Value = includeTypes[0]; - } - else if (includeTypes.Length > 1) - { - var inClause = string.Join(",", includeTypes.Select(i => "'" + i + "'").ToArray()); - whereClauses.Add(string.Format("type in ({0})", inClause)); - } - var excludeTypes = query.ExcludeItemTypes.SelectMany(MapIncludeItemTypes).ToArray(); if (excludeTypes.Length == 1) { @@ -2220,6 +2207,18 @@ namespace MediaBrowser.Server.Implementations.Persistence whereClauses.Add(string.Format("type not in ({0})", inClause)); } + var includeTypes = query.IncludeItemTypes.SelectMany(MapIncludeItemTypes).ToArray(); + if (includeTypes.Length == 1) + { + whereClauses.Add("type=@type"); + cmd.Parameters.Add(cmd, "@type", DbType.String).Value = includeTypes[0]; + } + else if (includeTypes.Length > 1) + { + var inClause = string.Join(",", includeTypes.Select(i => "'" + i + "'").ToArray()); + whereClauses.Add(string.Format("type in ({0})", inClause)); + } + if (query.ChannelIds.Length == 1) { whereClauses.Add("ChannelId=@ChannelId"); @@ -2635,8 +2634,15 @@ namespace MediaBrowser.Server.Implementations.Persistence if (query.LocationTypes.Length == 1) { - whereClauses.Add("LocationType=@LocationType"); - cmd.Parameters.Add(cmd, "@LocationType", DbType.String).Value = query.LocationTypes[0].ToString(); + if (query.LocationTypes[0] == LocationType.Virtual && _config.Configuration.SchemaVersion >= 90) + { + query.IsVirtualItem = true; + } + else + { + whereClauses.Add("LocationType=@LocationType"); + cmd.Parameters.Add(cmd, "@LocationType", DbType.String).Value = query.LocationTypes[0].ToString(); + } } else if (query.LocationTypes.Length > 1) { @@ -2646,8 +2652,15 @@ namespace MediaBrowser.Server.Implementations.Persistence } if (query.ExcludeLocationTypes.Length == 1) { - whereClauses.Add("LocationType<>@ExcludeLocationTypes"); - cmd.Parameters.Add(cmd, "@ExcludeLocationTypes", DbType.String).Value = query.ExcludeLocationTypes[0].ToString(); + if (query.ExcludeLocationTypes[0] == LocationType.Virtual && _config.Configuration.SchemaVersion >= 90) + { + query.IsVirtualItem = false; + } + else + { + whereClauses.Add("LocationType<>@ExcludeLocationTypes"); + cmd.Parameters.Add(cmd, "@ExcludeLocationTypes", DbType.String).Value = query.ExcludeLocationTypes[0].ToString(); + } } else if (query.ExcludeLocationTypes.Length > 1) { @@ -2655,6 +2668,11 @@ namespace MediaBrowser.Server.Implementations.Persistence whereClauses.Add("LocationType not in (" + val + ")"); } + if (query.IsVirtualItem.HasValue) + { + whereClauses.Add("IsVirtualItem=@IsVirtualItem"); + cmd.Parameters.Add(cmd, "@IsVirtualItem", DbType.Boolean).Value = query.IsVirtualItem.Value; + } if (query.MediaTypes.Length == 1) { whereClauses.Add("MediaType=@MediaTypes"); From 383110f9af6b5ad79ddabb3c8db0bdb7d4b4db03 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 12 Jun 2016 19:33:11 -0400 Subject: [PATCH 6/6] switch recordings to ts when preserving original audio --- .../TV/SeriesPostScanTask.cs | 43 +- .../LiveTv/EmbyTV/EncodedRecorder.cs | 2 +- .../Persistence/BaseSqliteRepository.cs | 40 +- .../Persistence/SqliteExtensions.cs | 6 +- .../Persistence/SqliteItemRepository.cs | 3061 ++++++++--------- .../Persistence/SqliteUserDataRepository.cs | 336 +- .../ApplicationHost.cs | 4 +- 7 files changed, 1709 insertions(+), 1783 deletions(-) diff --git a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs index 3c0a5fc73b..d044c828ff 100644 --- a/MediaBrowser.Providers/TV/SeriesPostScanTask.cs +++ b/MediaBrowser.Providers/TV/SeriesPostScanTask.cs @@ -195,28 +195,35 @@ namespace MediaBrowser.Providers.TV private async void LibraryUpdateTimerCallback(object state) { - if (MissingEpisodeProvider.IsRunning) + try { - return; + if (MissingEpisodeProvider.IsRunning) + { + return; + } + + if (_libraryManager.IsScanRunning) + { + return; + } + + var seriesList = _libraryManager.GetItemList(new InternalItemsQuery() + { + IncludeItemTypes = new[] { typeof(Series).Name }, + Recursive = true, + GroupByPresentationUniqueKey = false + + }).Cast().ToList(); + + var seriesGroups = SeriesPostScanTask.FindSeriesGroups(seriesList).Where(g => !string.IsNullOrEmpty(g.Key)).ToList(); + + await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization, _fileSystem) + .Run(seriesGroups, false, CancellationToken.None).ConfigureAwait(false); } - - if (_libraryManager.IsScanRunning) + catch (Exception ex) { - return ; + _logger.ErrorException("Error in SeriesPostScanTask", ex); } - - var seriesList = _libraryManager.GetItemList(new InternalItemsQuery() - { - IncludeItemTypes = new[] { typeof(Series).Name }, - Recursive = true, - GroupByPresentationUniqueKey = false - - }).Cast().ToList(); - - var seriesGroups = SeriesPostScanTask.FindSeriesGroups(seriesList).Where(g => !string.IsNullOrEmpty(g.Key)).ToList(); - - await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization, _fileSystem) - .Run(seriesGroups, false, CancellationToken.None).ConfigureAwait(false); } private bool FilterItem(BaseItem item) diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index e9ea49fa32..4022252ac8 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -50,7 +50,7 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV var streams = mediaSource.MediaStreams ?? new List(); if (streams.Any(i => i.Type == MediaStreamType.Audio && (i.Codec ?? string.Empty).IndexOf("aac", StringComparison.OrdinalIgnoreCase) != -1)) { - return Path.ChangeExtension(targetFile, ".mkv"); + return Path.ChangeExtension(targetFile, ".ts"); } } diff --git a/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs b/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs index 709971797f..eec5b4b76c 100644 --- a/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs @@ -8,6 +8,7 @@ namespace MediaBrowser.Server.Implementations.Persistence { public abstract class BaseSqliteRepository : IDisposable { + protected readonly SemaphoreSlim WriteLock = new SemaphoreSlim(1, 1); protected readonly IDbConnector DbConnector; protected ILogger Logger; @@ -19,11 +20,16 @@ namespace MediaBrowser.Server.Implementations.Persistence Logger = logManager.GetLogger(GetType().Name); } + protected virtual bool EnableConnectionPooling + { + get { return true; } + } + protected virtual async Task CreateConnection(bool isReadOnly = false) { var connection = await DbConnector.Connect(DbFilePath, false, true).ConfigureAwait(false); - connection.RunQueries(new [] + connection.RunQueries(new[] { "pragma temp_store = memory" @@ -45,12 +51,15 @@ namespace MediaBrowser.Server.Implementations.Persistence { _disposed = true; Dispose(true); + GC.SuppressFinalize(this); } protected async Task Vacuum(IDbConnection connection) { CheckDisposed(); + await WriteLock.WaitAsync().ConfigureAwait(false); + try { using (var cmd = connection.CreateCommand()) @@ -65,14 +74,41 @@ namespace MediaBrowser.Server.Implementations.Persistence throw; } + finally + { + WriteLock.Release(); + } } + private readonly object _disposeLock = new object(); + /// /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool dispose) { + if (dispose) + { + try + { + lock (_disposeLock) + { + WriteLock.Wait(); + + CloseConnection(); + } + } + catch (Exception ex) + { + Logger.ErrorException("Error disposing database", ex); + } + } + } + + protected virtual void CloseConnection() + { + } } -} +} \ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs index 0a76381e12..b1206c297a 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs @@ -39,12 +39,8 @@ namespace MediaBrowser.Server.Implementations.Persistence var connectionString = connectionstr.ConnectionString; - if (enablePooling) - { - connectionString += ";Max Pool Size=100"; - } - //logger.Info("Sqlite {0} opening {1}", SQLiteConnection.SQLiteVersion, connectionString); + SQLiteConnection.SetMemoryStatus(false); var connection = new SQLiteConnection(connectionString); diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index ba3ada7049..4e851053b1 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -31,6 +31,8 @@ namespace MediaBrowser.Server.Implementations.Persistence /// public class SqliteItemRepository : BaseSqliteRepository, IItemRepository { + private IDbConnection _connection; + private readonly TypeMapper _typeMapper = new TypeMapper(); /// @@ -56,11 +58,43 @@ namespace MediaBrowser.Server.Implementations.Persistence /// private readonly IServerConfigurationManager _config; + /// + /// The _save item command + /// + private IDbCommand _saveItemCommand; + private readonly string _criticReviewsPath; - public const int LatestSchemaVersion = 91; + private IDbCommand _deleteItemCommand; - private IDbConnection _connection; + private IDbCommand _deletePeopleCommand; + private IDbCommand _savePersonCommand; + + private IDbCommand _deleteChaptersCommand; + private IDbCommand _saveChapterCommand; + + private IDbCommand _deleteStreamsCommand; + private IDbCommand _saveStreamCommand; + + private IDbCommand _deleteAncestorsCommand; + private IDbCommand _saveAncestorCommand; + + private IDbCommand _deleteUserDataKeysCommand; + private IDbCommand _saveUserDataKeysCommand; + + private IDbCommand _deleteItemValuesCommand; + private IDbCommand _saveItemValuesCommand; + + private IDbCommand _deleteProviderIdsCommand; + private IDbCommand _saveProviderIdsCommand; + + private IDbCommand _deleteImagesCommand; + private IDbCommand _saveImagesCommand; + + private IDbCommand _updateInheritedRatingCommand; + private IDbCommand _updateInheritedTagsCommand; + + public const int LatestSchemaVersion = 89; /// /// Initializes a new instance of the class. @@ -84,37 +118,33 @@ namespace MediaBrowser.Server.Implementations.Persistence DbFilePath = Path.Combine(_config.ApplicationPaths.DataPath, "library.db"); } + private const string ChaptersTableName = "Chapters2"; + protected override async Task CreateConnection(bool isReadOnly = false) { - var connection = await DbConnector.Connect(DbFilePath, false, true, 20000).ConfigureAwait(false); + var connection = await DbConnector.Connect(DbFilePath, false, false, 6000).ConfigureAwait(false); - //AttachUserDataDb(connection); + connection.RunQueries(new[] + { + "pragma temp_store = memory" - //connection.RunQueries(new[] - //{ - // "pragma locking_mode=NORMAL" - - //}, Logger); + }, Logger); return connection; } - private const string ChaptersTableName = "Chapters2"; - /// /// Opens the connection to the database /// /// Task. - public async Task Initialize(IDbConnector dbConnector) + public async Task Initialize() { - //_connection = await CreateConnection().ConfigureAwait(false); + _connection = await CreateConnection(false).ConfigureAwait(false); - using (var connection = await CreateConnection().ConfigureAwait(false)) - { - var 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, PRIMARY KEY (ItemId, StreamIndex))"; + var 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, PRIMARY KEY (ItemId, StreamIndex))"; - string[] queries = { + string[] queries = { "create table if not exists TypedBaseItems (guid GUID primary key, type TEXT, data BLOB, ParentId GUID, Path TEXT)", "create index if not exists idx_PathTypedBaseItems on TypedBaseItems(Path)", @@ -146,96 +176,96 @@ namespace MediaBrowser.Server.Implementations.Persistence createMediaStreamsTableCommand, "create index if not exists idx_mediastreams1 on mediastreams(ItemId)", - + }; - connection.RunQueries(queries, Logger); + _connection.RunQueries(queries, Logger); - connection.AddColumn(Logger, "AncestorIds", "AncestorIdText", "Text"); + _connection.AddColumn(Logger, "AncestorIds", "AncestorIdText", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "Path", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "StartDate", "DATETIME"); - connection.AddColumn(Logger, "TypedBaseItems", "EndDate", "DATETIME"); - connection.AddColumn(Logger, "TypedBaseItems", "ChannelId", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "IsMovie", "BIT"); - connection.AddColumn(Logger, "TypedBaseItems", "IsSports", "BIT"); - connection.AddColumn(Logger, "TypedBaseItems", "IsKids", "BIT"); - connection.AddColumn(Logger, "TypedBaseItems", "CommunityRating", "Float"); - connection.AddColumn(Logger, "TypedBaseItems", "CustomRating", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "IndexNumber", "INT"); - connection.AddColumn(Logger, "TypedBaseItems", "IsLocked", "BIT"); - connection.AddColumn(Logger, "TypedBaseItems", "Name", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "OfficialRating", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "Path", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "StartDate", "DATETIME"); + _connection.AddColumn(Logger, "TypedBaseItems", "EndDate", "DATETIME"); + _connection.AddColumn(Logger, "TypedBaseItems", "ChannelId", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "IsMovie", "BIT"); + _connection.AddColumn(Logger, "TypedBaseItems", "IsSports", "BIT"); + _connection.AddColumn(Logger, "TypedBaseItems", "IsKids", "BIT"); + _connection.AddColumn(Logger, "TypedBaseItems", "CommunityRating", "Float"); + _connection.AddColumn(Logger, "TypedBaseItems", "CustomRating", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "IndexNumber", "INT"); + _connection.AddColumn(Logger, "TypedBaseItems", "IsLocked", "BIT"); + _connection.AddColumn(Logger, "TypedBaseItems", "Name", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "OfficialRating", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "MediaType", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "Overview", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "ParentIndexNumber", "INT"); - connection.AddColumn(Logger, "TypedBaseItems", "PremiereDate", "DATETIME"); - connection.AddColumn(Logger, "TypedBaseItems", "ProductionYear", "INT"); - connection.AddColumn(Logger, "TypedBaseItems", "ParentId", "GUID"); - connection.AddColumn(Logger, "TypedBaseItems", "Genres", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "ParentalRatingValue", "INT"); - connection.AddColumn(Logger, "TypedBaseItems", "SchemaVersion", "INT"); - connection.AddColumn(Logger, "TypedBaseItems", "SortName", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "RunTimeTicks", "BIGINT"); + _connection.AddColumn(Logger, "TypedBaseItems", "MediaType", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "Overview", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "ParentIndexNumber", "INT"); + _connection.AddColumn(Logger, "TypedBaseItems", "PremiereDate", "DATETIME"); + _connection.AddColumn(Logger, "TypedBaseItems", "ProductionYear", "INT"); + _connection.AddColumn(Logger, "TypedBaseItems", "ParentId", "GUID"); + _connection.AddColumn(Logger, "TypedBaseItems", "Genres", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "ParentalRatingValue", "INT"); + _connection.AddColumn(Logger, "TypedBaseItems", "SchemaVersion", "INT"); + _connection.AddColumn(Logger, "TypedBaseItems", "SortName", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "RunTimeTicks", "BIGINT"); - connection.AddColumn(Logger, "TypedBaseItems", "OfficialRatingDescription", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "HomePageUrl", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "VoteCount", "INT"); - connection.AddColumn(Logger, "TypedBaseItems", "DisplayMediaType", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "DateCreated", "DATETIME"); - connection.AddColumn(Logger, "TypedBaseItems", "DateModified", "DATETIME"); + _connection.AddColumn(Logger, "TypedBaseItems", "OfficialRatingDescription", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "HomePageUrl", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "VoteCount", "INT"); + _connection.AddColumn(Logger, "TypedBaseItems", "DisplayMediaType", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "DateCreated", "DATETIME"); + _connection.AddColumn(Logger, "TypedBaseItems", "DateModified", "DATETIME"); - connection.AddColumn(Logger, "TypedBaseItems", "ForcedSortName", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "IsOffline", "BIT"); - connection.AddColumn(Logger, "TypedBaseItems", "LocationType", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "ForcedSortName", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "IsOffline", "BIT"); + _connection.AddColumn(Logger, "TypedBaseItems", "LocationType", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "IsSeries", "BIT"); - connection.AddColumn(Logger, "TypedBaseItems", "IsLive", "BIT"); - connection.AddColumn(Logger, "TypedBaseItems", "IsNews", "BIT"); - connection.AddColumn(Logger, "TypedBaseItems", "IsPremiere", "BIT"); + _connection.AddColumn(Logger, "TypedBaseItems", "IsSeries", "BIT"); + _connection.AddColumn(Logger, "TypedBaseItems", "IsLive", "BIT"); + _connection.AddColumn(Logger, "TypedBaseItems", "IsNews", "BIT"); + _connection.AddColumn(Logger, "TypedBaseItems", "IsPremiere", "BIT"); - connection.AddColumn(Logger, "TypedBaseItems", "EpisodeTitle", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "IsRepeat", "BIT"); + _connection.AddColumn(Logger, "TypedBaseItems", "EpisodeTitle", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "IsRepeat", "BIT"); - connection.AddColumn(Logger, "TypedBaseItems", "PreferredMetadataLanguage", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "PreferredMetadataCountryCode", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "IsHD", "BIT"); - connection.AddColumn(Logger, "TypedBaseItems", "ExternalEtag", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "DateLastRefreshed", "DATETIME"); + _connection.AddColumn(Logger, "TypedBaseItems", "PreferredMetadataLanguage", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "PreferredMetadataCountryCode", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "IsHD", "BIT"); + _connection.AddColumn(Logger, "TypedBaseItems", "ExternalEtag", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "DateLastRefreshed", "DATETIME"); - connection.AddColumn(Logger, "TypedBaseItems", "DateLastSaved", "DATETIME"); - connection.AddColumn(Logger, "TypedBaseItems", "IsInMixedFolder", "BIT"); - connection.AddColumn(Logger, "TypedBaseItems", "LockedFields", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "Studios", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "Audio", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "ExternalServiceId", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "Tags", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "IsFolder", "BIT"); - connection.AddColumn(Logger, "TypedBaseItems", "InheritedParentalRatingValue", "INT"); - connection.AddColumn(Logger, "TypedBaseItems", "UnratedType", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "TopParentId", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "IsItemByName", "BIT"); - connection.AddColumn(Logger, "TypedBaseItems", "SourceType", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "TrailerTypes", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "CriticRating", "Float"); - connection.AddColumn(Logger, "TypedBaseItems", "CriticRatingSummary", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "DateModifiedDuringLastRefresh", "DATETIME"); - connection.AddColumn(Logger, "TypedBaseItems", "InheritedTags", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "CleanName", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "PresentationUniqueKey", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "SlugName", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "OriginalTitle", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "PrimaryVersionId", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "DateLastMediaAdded", "DATETIME"); - connection.AddColumn(Logger, "TypedBaseItems", "Album", "Text"); - connection.AddColumn(Logger, "TypedBaseItems", "IsVirtualItem", "BIT"); - connection.AddColumn(Logger, "TypedBaseItems", "SeriesName", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "DateLastSaved", "DATETIME"); + _connection.AddColumn(Logger, "TypedBaseItems", "IsInMixedFolder", "BIT"); + _connection.AddColumn(Logger, "TypedBaseItems", "LockedFields", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "Studios", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "Audio", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "ExternalServiceId", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "Tags", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "IsFolder", "BIT"); + _connection.AddColumn(Logger, "TypedBaseItems", "InheritedParentalRatingValue", "INT"); + _connection.AddColumn(Logger, "TypedBaseItems", "UnratedType", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "TopParentId", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "IsItemByName", "BIT"); + _connection.AddColumn(Logger, "TypedBaseItems", "SourceType", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "TrailerTypes", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "CriticRating", "Float"); + _connection.AddColumn(Logger, "TypedBaseItems", "CriticRatingSummary", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "DateModifiedDuringLastRefresh", "DATETIME"); + _connection.AddColumn(Logger, "TypedBaseItems", "InheritedTags", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "CleanName", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "PresentationUniqueKey", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "SlugName", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "OriginalTitle", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "PrimaryVersionId", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "DateLastMediaAdded", "DATETIME"); + _connection.AddColumn(Logger, "TypedBaseItems", "Album", "Text"); + _connection.AddColumn(Logger, "TypedBaseItems", "IsVirtualItem", "BIT"); + _connection.AddColumn(Logger, "TypedBaseItems", "SeriesName", "Text"); - connection.AddColumn(Logger, "UserDataKeys", "Priority", "INT"); + _connection.AddColumn(Logger, "UserDataKeys", "Priority", "INT"); - string[] postQueries = - { + string[] postQueries = + { "create index if not exists idx_PresentationUniqueKey on TypedBaseItems(PresentationUniqueKey)", "create index if not exists idx_GuidType on TypedBaseItems(Guid,Type)", "create index if not exists idx_Type on TypedBaseItems(Type)", @@ -247,17 +277,13 @@ namespace MediaBrowser.Server.Implementations.Persistence "create index if not exists idx_TypeTopParentId5 on TypedBaseItems(TopParentId,IsVirtualItem)" }; - connection.RunQueries(postQueries, Logger); + _connection.RunQueries(postQueries, Logger); - new MediaStreamColumns(connection, Logger).AddColumns(); + PrepareStatements(); - //AttachUserDataDb(connection); - } - } + new MediaStreamColumns(_connection, Logger).AddColumns(); - private void AttachUserDataDb(IDbConnection connection) - { - DataExtensions.Attach(connection, Path.Combine(_config.ApplicationPaths.DataPath, "userdata_v2.db"), "UserDataDb" + Guid.NewGuid().ToString("N")); + DataExtensions.Attach(_connection, Path.Combine(_config.ApplicationPaths.DataPath, "userdata_v2.db"), "UserDataDb"); } private readonly string[] _retriveItemColumns = @@ -359,6 +385,220 @@ namespace MediaBrowser.Server.Implementations.Persistence "CodecTimeBase" }; + /// + /// Prepares the statements. + /// + private void PrepareStatements() + { + var saveColumns = new List + { + "guid", + "type", + "data", + "Path", + "StartDate", + "EndDate", + "ChannelId", + "IsKids", + "IsMovie", + "IsSports", + "IsSeries", + "IsLive", + "IsNews", + "IsPremiere", + "EpisodeTitle", + "IsRepeat", + "CommunityRating", + "CustomRating", + "IndexNumber", + "IsLocked", + "Name", + "OfficialRating", + "MediaType", + "Overview", + "ParentIndexNumber", + "PremiereDate", + "ProductionYear", + "ParentId", + "Genres", + "ParentalRatingValue", + "InheritedParentalRatingValue", + "SchemaVersion", + "SortName", + "RunTimeTicks", + "OfficialRatingDescription", + "HomePageUrl", + "VoteCount", + "DisplayMediaType", + "DateCreated", + "DateModified", + "ForcedSortName", + "IsOffline", + "LocationType", + "PreferredMetadataLanguage", + "PreferredMetadataCountryCode", + "IsHD", + "ExternalEtag", + "DateLastRefreshed", + "DateLastSaved", + "IsInMixedFolder", + "LockedFields", + "Studios", + "Audio", + "ExternalServiceId", + "Tags", + "IsFolder", + "UnratedType", + "TopParentId", + "IsItemByName", + "SourceType", + "TrailerTypes", + "CriticRating", + "CriticRatingSummary", + "DateModifiedDuringLastRefresh", + "InheritedTags", + "CleanName", + "PresentationUniqueKey", + "SlugName", + "OriginalTitle", + "PrimaryVersionId", + "DateLastMediaAdded", + "Album", + "IsVirtualItem", + "SeriesName" + }; + _saveItemCommand = _connection.CreateCommand(); + _saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values ("; + + for (var i = 1; i <= saveColumns.Count; i++) + { + if (i > 1) + { + _saveItemCommand.CommandText += ","; + } + _saveItemCommand.CommandText += "@" + i.ToString(CultureInfo.InvariantCulture); + + _saveItemCommand.Parameters.Add(_saveItemCommand, "@" + i.ToString(CultureInfo.InvariantCulture)); + } + _saveItemCommand.CommandText += ")"; + + _deleteItemCommand = _connection.CreateCommand(); + _deleteItemCommand.CommandText = "delete from TypedBaseItems where guid=@Id"; + _deleteItemCommand.Parameters.Add(_deleteItemCommand, "@Id"); + + // People + _deletePeopleCommand = _connection.CreateCommand(); + _deletePeopleCommand.CommandText = "delete from People where ItemId=@Id"; + _deletePeopleCommand.Parameters.Add(_deletePeopleCommand, "@Id"); + + _savePersonCommand = _connection.CreateCommand(); + _savePersonCommand.CommandText = "insert into People (ItemId, Name, Role, PersonType, SortOrder, ListOrder) values (@ItemId, @Name, @Role, @PersonType, @SortOrder, @ListOrder)"; + _savePersonCommand.Parameters.Add(_savePersonCommand, "@ItemId"); + _savePersonCommand.Parameters.Add(_savePersonCommand, "@Name"); + _savePersonCommand.Parameters.Add(_savePersonCommand, "@Role"); + _savePersonCommand.Parameters.Add(_savePersonCommand, "@PersonType"); + _savePersonCommand.Parameters.Add(_savePersonCommand, "@SortOrder"); + _savePersonCommand.Parameters.Add(_savePersonCommand, "@ListOrder"); + + // Ancestors + _deleteAncestorsCommand = _connection.CreateCommand(); + _deleteAncestorsCommand.CommandText = "delete from AncestorIds where ItemId=@Id"; + _deleteAncestorsCommand.Parameters.Add(_deleteAncestorsCommand, "@Id"); + + _saveAncestorCommand = _connection.CreateCommand(); + _saveAncestorCommand.CommandText = "insert into AncestorIds (ItemId, AncestorId, AncestorIdText) values (@ItemId, @AncestorId, @AncestorIdText)"; + _saveAncestorCommand.Parameters.Add(_saveAncestorCommand, "@ItemId"); + _saveAncestorCommand.Parameters.Add(_saveAncestorCommand, "@AncestorId"); + _saveAncestorCommand.Parameters.Add(_saveAncestorCommand, "@AncestorIdText"); + + // Chapters + _deleteChaptersCommand = _connection.CreateCommand(); + _deleteChaptersCommand.CommandText = "delete from " + ChaptersTableName + " where ItemId=@ItemId"; + _deleteChaptersCommand.Parameters.Add(_deleteChaptersCommand, "@ItemId"); + + _saveChapterCommand = _connection.CreateCommand(); + _saveChapterCommand.CommandText = "replace into " + ChaptersTableName + " (ItemId, ChapterIndex, StartPositionTicks, Name, ImagePath) values (@ItemId, @ChapterIndex, @StartPositionTicks, @Name, @ImagePath)"; + + _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@ItemId"); + _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@ChapterIndex"); + _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@StartPositionTicks"); + _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@Name"); + _saveChapterCommand.Parameters.Add(_saveChapterCommand, "@ImagePath"); + + // MediaStreams + _deleteStreamsCommand = _connection.CreateCommand(); + _deleteStreamsCommand.CommandText = "delete from mediastreams where ItemId=@ItemId"; + _deleteStreamsCommand.Parameters.Add(_deleteStreamsCommand, "@ItemId"); + + _saveStreamCommand = _connection.CreateCommand(); + + _saveStreamCommand.CommandText = string.Format("replace into mediastreams ({0}) values ({1})", + string.Join(",", _mediaStreamSaveColumns), + string.Join(",", _mediaStreamSaveColumns.Select(i => "@" + i).ToArray())); + + foreach (var col in _mediaStreamSaveColumns) + { + _saveStreamCommand.Parameters.Add(_saveStreamCommand, "@" + col); + } + + _updateInheritedRatingCommand = _connection.CreateCommand(); + _updateInheritedRatingCommand.CommandText = "Update TypedBaseItems set InheritedParentalRatingValue=@InheritedParentalRatingValue where Guid=@Guid"; + _updateInheritedRatingCommand.Parameters.Add(_updateInheritedRatingCommand, "@Guid"); + _updateInheritedRatingCommand.Parameters.Add(_updateInheritedRatingCommand, "@InheritedParentalRatingValue"); + + _updateInheritedTagsCommand = _connection.CreateCommand(); + _updateInheritedTagsCommand.CommandText = "Update TypedBaseItems set InheritedTags=@InheritedTags where Guid=@Guid"; + _updateInheritedTagsCommand.Parameters.Add(_updateInheritedTagsCommand, "@Guid"); + _updateInheritedTagsCommand.Parameters.Add(_updateInheritedTagsCommand, "@InheritedTags"); + + // user data + _deleteUserDataKeysCommand = _connection.CreateCommand(); + _deleteUserDataKeysCommand.CommandText = "delete from UserDataKeys where ItemId=@Id"; + _deleteUserDataKeysCommand.Parameters.Add(_deleteUserDataKeysCommand, "@Id"); + + _saveUserDataKeysCommand = _connection.CreateCommand(); + _saveUserDataKeysCommand.CommandText = "insert into UserDataKeys (ItemId, UserDataKey, Priority) values (@ItemId, @UserDataKey, @Priority)"; + _saveUserDataKeysCommand.Parameters.Add(_saveUserDataKeysCommand, "@ItemId"); + _saveUserDataKeysCommand.Parameters.Add(_saveUserDataKeysCommand, "@UserDataKey"); + _saveUserDataKeysCommand.Parameters.Add(_saveUserDataKeysCommand, "@Priority"); + + // item values + _deleteItemValuesCommand = _connection.CreateCommand(); + _deleteItemValuesCommand.CommandText = "delete from ItemValues where ItemId=@Id"; + _deleteItemValuesCommand.Parameters.Add(_deleteItemValuesCommand, "@Id"); + + _saveItemValuesCommand = _connection.CreateCommand(); + _saveItemValuesCommand.CommandText = "insert into ItemValues (ItemId, Type, Value) values (@ItemId, @Type, @Value)"; + _saveItemValuesCommand.Parameters.Add(_saveItemValuesCommand, "@ItemId"); + _saveItemValuesCommand.Parameters.Add(_saveItemValuesCommand, "@Type"); + _saveItemValuesCommand.Parameters.Add(_saveItemValuesCommand, "@Value"); + + // provider ids + _deleteProviderIdsCommand = _connection.CreateCommand(); + _deleteProviderIdsCommand.CommandText = "delete from ProviderIds where ItemId=@Id"; + _deleteProviderIdsCommand.Parameters.Add(_deleteProviderIdsCommand, "@Id"); + + _saveProviderIdsCommand = _connection.CreateCommand(); + _saveProviderIdsCommand.CommandText = "insert into ProviderIds (ItemId, Name, Value) values (@ItemId, @Name, @Value)"; + _saveProviderIdsCommand.Parameters.Add(_saveProviderIdsCommand, "@ItemId"); + _saveProviderIdsCommand.Parameters.Add(_saveProviderIdsCommand, "@Name"); + _saveProviderIdsCommand.Parameters.Add(_saveProviderIdsCommand, "@Value"); + + // images + _deleteImagesCommand = _connection.CreateCommand(); + _deleteImagesCommand.CommandText = "delete from Images where ItemId=@Id"; + _deleteImagesCommand.Parameters.Add(_deleteImagesCommand, "@Id"); + + _saveImagesCommand = _connection.CreateCommand(); + _saveImagesCommand.CommandText = "insert into Images (ItemId, ImageType, Path, DateModified, IsPlaceHolder, SortOrder) values (@ItemId, @ImageType, @Path, @DateModified, @IsPlaceHolder, @SortOrder)"; + _saveImagesCommand.Parameters.Add(_saveImagesCommand, "@ItemId"); + _saveImagesCommand.Parameters.Add(_saveImagesCommand, "@ImageType"); + _saveImagesCommand.Parameters.Add(_saveImagesCommand, "@Path"); + _saveImagesCommand.Parameters.Add(_saveImagesCommand, "@DateModified"); + _saveImagesCommand.Parameters.Add(_saveImagesCommand, "@IsPlaceHolder"); + _saveImagesCommand.Parameters.Add(_saveImagesCommand, "@SortOrder"); + } + /// /// Save a standard item in the repo /// @@ -398,400 +638,306 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); - using (var connection = await CreateConnection().ConfigureAwait(false)) + await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); + + IDbTransaction transaction = null; + + try { - IDbTransaction transaction = null; + transaction = _connection.BeginTransaction(); - try + foreach (var item in items) { - transaction = connection.BeginTransaction(); + cancellationToken.ThrowIfCancellationRequested(); - using (var saveItemCommand = connection.CreateCommand()) + var index = 0; + + _saveItemCommand.GetParameter(index++).Value = item.Id; + _saveItemCommand.GetParameter(index++).Value = item.GetType().FullName; + _saveItemCommand.GetParameter(index++).Value = _jsonSerializer.SerializeToBytes(item); + + _saveItemCommand.GetParameter(index++).Value = item.Path; + + var hasStartDate = item as IHasStartDate; + if (hasStartDate != null) { - var saveColumns = new List - { - "guid", - "type", - "data", - "Path", - "StartDate", - "EndDate", - "ChannelId", - "IsKids", - "IsMovie", - "IsSports", - "IsSeries", - "IsLive", - "IsNews", - "IsPremiere", - "EpisodeTitle", - "IsRepeat", - "CommunityRating", - "CustomRating", - "IndexNumber", - "IsLocked", - "Name", - "OfficialRating", - "MediaType", - "Overview", - "ParentIndexNumber", - "PremiereDate", - "ProductionYear", - "ParentId", - "Genres", - "ParentalRatingValue", - "InheritedParentalRatingValue", - "SchemaVersion", - "SortName", - "RunTimeTicks", - "OfficialRatingDescription", - "HomePageUrl", - "VoteCount", - "DisplayMediaType", - "DateCreated", - "DateModified", - "ForcedSortName", - "IsOffline", - "LocationType", - "PreferredMetadataLanguage", - "PreferredMetadataCountryCode", - "IsHD", - "ExternalEtag", - "DateLastRefreshed", - "DateLastSaved", - "IsInMixedFolder", - "LockedFields", - "Studios", - "Audio", - "ExternalServiceId", - "Tags", - "IsFolder", - "UnratedType", - "TopParentId", - "IsItemByName", - "SourceType", - "TrailerTypes", - "CriticRating", - "CriticRatingSummary", - "DateModifiedDuringLastRefresh", - "InheritedTags", - "CleanName", - "PresentationUniqueKey", - "SlugName", - "OriginalTitle", - "PrimaryVersionId", - "DateLastMediaAdded", - "Album", - "IsVirtualItem", - "SeriesName" - }; - - saveItemCommand.CommandText = "replace into TypedBaseItems (" + string.Join(",", saveColumns.ToArray()) + ") values ("; - - for (var i = 1; i <= saveColumns.Count; i++) - { - if (i > 1) - { - saveItemCommand.CommandText += ","; - } - saveItemCommand.CommandText += "@" + i.ToString(CultureInfo.InvariantCulture); - - saveItemCommand.Parameters.Add(saveItemCommand, "@" + i.ToString(CultureInfo.InvariantCulture)); - } - saveItemCommand.CommandText += ")"; - - foreach (var item in items) - { - cancellationToken.ThrowIfCancellationRequested(); - - var index = 0; - - saveItemCommand.GetParameter(index++).Value = item.Id; - saveItemCommand.GetParameter(index++).Value = item.GetType().FullName; - saveItemCommand.GetParameter(index++).Value = _jsonSerializer.SerializeToBytes(item); - - saveItemCommand.GetParameter(index++).Value = item.Path; - - var hasStartDate = item as IHasStartDate; - if (hasStartDate != null) - { - saveItemCommand.GetParameter(index++).Value = hasStartDate.StartDate; - } - else - { - saveItemCommand.GetParameter(index++).Value = null; - } - - saveItemCommand.GetParameter(index++).Value = item.EndDate; - saveItemCommand.GetParameter(index++).Value = item.ChannelId; - - var hasProgramAttributes = item as IHasProgramAttributes; - if (hasProgramAttributes != null) - { - saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsKids; - saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsMovie; - saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsSports; - saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsSeries; - saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsLive; - saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsNews; - saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsPremiere; - saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.EpisodeTitle; - saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsRepeat; - } - else - { - saveItemCommand.GetParameter(index++).Value = null; - saveItemCommand.GetParameter(index++).Value = null; - saveItemCommand.GetParameter(index++).Value = null; - saveItemCommand.GetParameter(index++).Value = null; - saveItemCommand.GetParameter(index++).Value = null; - saveItemCommand.GetParameter(index++).Value = null; - saveItemCommand.GetParameter(index++).Value = null; - saveItemCommand.GetParameter(index++).Value = null; - saveItemCommand.GetParameter(index++).Value = null; - } - - saveItemCommand.GetParameter(index++).Value = item.CommunityRating; - saveItemCommand.GetParameter(index++).Value = item.CustomRating; - - saveItemCommand.GetParameter(index++).Value = item.IndexNumber; - saveItemCommand.GetParameter(index++).Value = item.IsLocked; - - saveItemCommand.GetParameter(index++).Value = item.Name; - saveItemCommand.GetParameter(index++).Value = item.OfficialRating; - - saveItemCommand.GetParameter(index++).Value = item.MediaType; - saveItemCommand.GetParameter(index++).Value = item.Overview; - saveItemCommand.GetParameter(index++).Value = item.ParentIndexNumber; - saveItemCommand.GetParameter(index++).Value = item.PremiereDate; - saveItemCommand.GetParameter(index++).Value = item.ProductionYear; - - if (item.ParentId == Guid.Empty) - { - saveItemCommand.GetParameter(index++).Value = null; - } - else - { - saveItemCommand.GetParameter(index++).Value = item.ParentId; - } - - saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Genres.ToArray()); - saveItemCommand.GetParameter(index++).Value = item.GetParentalRatingValue() ?? 0; - saveItemCommand.GetParameter(index++).Value = item.GetInheritedParentalRatingValue() ?? 0; - - saveItemCommand.GetParameter(index++).Value = LatestSchemaVersion; - saveItemCommand.GetParameter(index++).Value = item.SortName; - saveItemCommand.GetParameter(index++).Value = item.RunTimeTicks; - - saveItemCommand.GetParameter(index++).Value = item.OfficialRatingDescription; - saveItemCommand.GetParameter(index++).Value = item.HomePageUrl; - saveItemCommand.GetParameter(index++).Value = item.VoteCount; - saveItemCommand.GetParameter(index++).Value = item.DisplayMediaType; - saveItemCommand.GetParameter(index++).Value = item.DateCreated; - saveItemCommand.GetParameter(index++).Value = item.DateModified; - - saveItemCommand.GetParameter(index++).Value = item.ForcedSortName; - saveItemCommand.GetParameter(index++).Value = item.IsOffline; - saveItemCommand.GetParameter(index++).Value = item.LocationType.ToString(); - - saveItemCommand.GetParameter(index++).Value = item.PreferredMetadataLanguage; - saveItemCommand.GetParameter(index++).Value = item.PreferredMetadataCountryCode; - saveItemCommand.GetParameter(index++).Value = item.IsHD; - saveItemCommand.GetParameter(index++).Value = item.ExternalEtag; - - if (item.DateLastRefreshed == default(DateTime)) - { - saveItemCommand.GetParameter(index++).Value = null; - } - else - { - saveItemCommand.GetParameter(index++).Value = item.DateLastRefreshed; - } - - if (item.DateLastSaved == default(DateTime)) - { - saveItemCommand.GetParameter(index++).Value = null; - } - else - { - saveItemCommand.GetParameter(index++).Value = item.DateLastSaved; - } - - saveItemCommand.GetParameter(index++).Value = item.IsInMixedFolder; - saveItemCommand.GetParameter(index++).Value = string.Join("|", item.LockedFields.Select(i => i.ToString()).ToArray()); - saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Studios.ToArray()); - - if (item.Audio.HasValue) - { - saveItemCommand.GetParameter(index++).Value = item.Audio.Value.ToString(); - } - else - { - saveItemCommand.GetParameter(index++).Value = null; - } - - saveItemCommand.GetParameter(index++).Value = item.ServiceName; - - if (item.Tags.Count > 0) - { - saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Tags.ToArray()); - } - else - { - saveItemCommand.GetParameter(index++).Value = null; - } - - saveItemCommand.GetParameter(index++).Value = item.IsFolder; - - saveItemCommand.GetParameter(index++).Value = item.GetBlockUnratedType().ToString(); - - var topParent = item.GetTopParent(); - if (topParent != null) - { - //Logger.Debug("Item {0} has top parent {1}", item.Id, topParent.Id); - saveItemCommand.GetParameter(index++).Value = topParent.Id.ToString("N"); - } - else - { - //Logger.Debug("Item {0} has null top parent", item.Id); - saveItemCommand.GetParameter(index++).Value = null; - } - - var isByName = false; - var byName = item as IItemByName; - if (byName != null) - { - var dualAccess = item as IHasDualAccess; - isByName = dualAccess == null || dualAccess.IsAccessedByName; - } - saveItemCommand.GetParameter(index++).Value = isByName; - - saveItemCommand.GetParameter(index++).Value = item.SourceType.ToString(); - - var trailer = item as Trailer; - if (trailer != null && trailer.TrailerTypes.Count > 0) - { - saveItemCommand.GetParameter(index++).Value = string.Join("|", trailer.TrailerTypes.Select(i => i.ToString()).ToArray()); - } - else - { - saveItemCommand.GetParameter(index++).Value = null; - } - - saveItemCommand.GetParameter(index++).Value = item.CriticRating; - saveItemCommand.GetParameter(index++).Value = item.CriticRatingSummary; - - if (!item.DateModifiedDuringLastRefresh.HasValue || item.DateModifiedDuringLastRefresh.Value == default(DateTime)) - { - saveItemCommand.GetParameter(index++).Value = null; - } - else - { - saveItemCommand.GetParameter(index++).Value = item.DateModifiedDuringLastRefresh.Value; - } - - var inheritedTags = item.GetInheritedTags(); - if (inheritedTags.Count > 0) - { - saveItemCommand.GetParameter(index++).Value = string.Join("|", inheritedTags.ToArray()); - } - else - { - saveItemCommand.GetParameter(index++).Value = null; - } - - if (string.IsNullOrWhiteSpace(item.Name)) - { - saveItemCommand.GetParameter(index++).Value = null; - } - else - { - saveItemCommand.GetParameter(index++).Value = item.Name.RemoveDiacritics(); - } - - saveItemCommand.GetParameter(index++).Value = item.PresentationUniqueKey; - saveItemCommand.GetParameter(index++).Value = item.SlugName; - saveItemCommand.GetParameter(index++).Value = item.OriginalTitle; - - var video = item as Video; - if (video != null) - { - saveItemCommand.GetParameter(index++).Value = video.PrimaryVersionId; - } - else - { - saveItemCommand.GetParameter(index++).Value = null; - } - - var folder = item as Folder; - if (folder != null && folder.DateLastMediaAdded.HasValue) - { - saveItemCommand.GetParameter(index++).Value = folder.DateLastMediaAdded.Value; - } - else - { - saveItemCommand.GetParameter(index++).Value = null; - } - - saveItemCommand.GetParameter(index++).Value = item.Album; - - saveItemCommand.GetParameter(index++).Value = item.IsVirtualItem || (!item.IsFolder && item.LocationType == LocationType.Virtual); - - var hasSeries = item as IHasSeries; - if (hasSeries != null) - { - saveItemCommand.GetParameter(index++).Value = hasSeries.SeriesName; - } - else - { - saveItemCommand.GetParameter(index++).Value = null; - } - - saveItemCommand.Transaction = transaction; - - saveItemCommand.ExecuteNonQuery(); - - if (item.SupportsAncestors) - { - UpdateAncestors(item.Id, item.GetAncestorIds().Distinct().ToList(), connection, transaction); - } - - UpdateUserDataKeys(item.Id, item.GetUserDataKeys().Distinct(StringComparer.OrdinalIgnoreCase).ToList(), connection, transaction); - UpdateImages(item.Id, item.ImageInfos, connection, transaction); - UpdateProviderIds(item.Id, item.ProviderIds, connection, transaction); - UpdateItemValues(item.Id, GetItemValues(item), connection, transaction); - } + _saveItemCommand.GetParameter(index++).Value = hasStartDate.StartDate; + } + else + { + _saveItemCommand.GetParameter(index++).Value = null; } - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + _saveItemCommand.GetParameter(index++).Value = item.EndDate; + _saveItemCommand.GetParameter(index++).Value = item.ChannelId; + + var hasProgramAttributes = item as IHasProgramAttributes; + if (hasProgramAttributes != null) { - transaction.Rollback(); + _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsKids; + _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsMovie; + _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsSports; + _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsSeries; + _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsLive; + _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsNews; + _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsPremiere; + _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.EpisodeTitle; + _saveItemCommand.GetParameter(index++).Value = hasProgramAttributes.IsRepeat; + } + else + { + _saveItemCommand.GetParameter(index++).Value = null; + _saveItemCommand.GetParameter(index++).Value = null; + _saveItemCommand.GetParameter(index++).Value = null; + _saveItemCommand.GetParameter(index++).Value = null; + _saveItemCommand.GetParameter(index++).Value = null; + _saveItemCommand.GetParameter(index++).Value = null; + _saveItemCommand.GetParameter(index++).Value = null; + _saveItemCommand.GetParameter(index++).Value = null; + _saveItemCommand.GetParameter(index++).Value = null; } - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save items:", e); + _saveItemCommand.GetParameter(index++).Value = item.CommunityRating; + _saveItemCommand.GetParameter(index++).Value = item.CustomRating; - if (transaction != null) + _saveItemCommand.GetParameter(index++).Value = item.IndexNumber; + _saveItemCommand.GetParameter(index++).Value = item.IsLocked; + + _saveItemCommand.GetParameter(index++).Value = item.Name; + _saveItemCommand.GetParameter(index++).Value = item.OfficialRating; + + _saveItemCommand.GetParameter(index++).Value = item.MediaType; + _saveItemCommand.GetParameter(index++).Value = item.Overview; + _saveItemCommand.GetParameter(index++).Value = item.ParentIndexNumber; + _saveItemCommand.GetParameter(index++).Value = item.PremiereDate; + _saveItemCommand.GetParameter(index++).Value = item.ProductionYear; + + if (item.ParentId == Guid.Empty) { - transaction.Rollback(); + _saveItemCommand.GetParameter(index++).Value = null; + } + else + { + _saveItemCommand.GetParameter(index++).Value = item.ParentId; } - throw; - } - finally - { - if (transaction != null) + _saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Genres.ToArray()); + _saveItemCommand.GetParameter(index++).Value = item.GetParentalRatingValue() ?? 0; + _saveItemCommand.GetParameter(index++).Value = item.GetInheritedParentalRatingValue() ?? 0; + + _saveItemCommand.GetParameter(index++).Value = LatestSchemaVersion; + _saveItemCommand.GetParameter(index++).Value = item.SortName; + _saveItemCommand.GetParameter(index++).Value = item.RunTimeTicks; + + _saveItemCommand.GetParameter(index++).Value = item.OfficialRatingDescription; + _saveItemCommand.GetParameter(index++).Value = item.HomePageUrl; + _saveItemCommand.GetParameter(index++).Value = item.VoteCount; + _saveItemCommand.GetParameter(index++).Value = item.DisplayMediaType; + _saveItemCommand.GetParameter(index++).Value = item.DateCreated; + _saveItemCommand.GetParameter(index++).Value = item.DateModified; + + _saveItemCommand.GetParameter(index++).Value = item.ForcedSortName; + _saveItemCommand.GetParameter(index++).Value = item.IsOffline; + _saveItemCommand.GetParameter(index++).Value = item.LocationType.ToString(); + + _saveItemCommand.GetParameter(index++).Value = item.PreferredMetadataLanguage; + _saveItemCommand.GetParameter(index++).Value = item.PreferredMetadataCountryCode; + _saveItemCommand.GetParameter(index++).Value = item.IsHD; + _saveItemCommand.GetParameter(index++).Value = item.ExternalEtag; + + if (item.DateLastRefreshed == default(DateTime)) { - transaction.Dispose(); + _saveItemCommand.GetParameter(index++).Value = null; } + else + { + _saveItemCommand.GetParameter(index++).Value = item.DateLastRefreshed; + } + + if (item.DateLastSaved == default(DateTime)) + { + _saveItemCommand.GetParameter(index++).Value = null; + } + else + { + _saveItemCommand.GetParameter(index++).Value = item.DateLastSaved; + } + + _saveItemCommand.GetParameter(index++).Value = item.IsInMixedFolder; + _saveItemCommand.GetParameter(index++).Value = string.Join("|", item.LockedFields.Select(i => i.ToString()).ToArray()); + _saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Studios.ToArray()); + + if (item.Audio.HasValue) + { + _saveItemCommand.GetParameter(index++).Value = item.Audio.Value.ToString(); + } + else + { + _saveItemCommand.GetParameter(index++).Value = null; + } + + _saveItemCommand.GetParameter(index++).Value = item.ServiceName; + + if (item.Tags.Count > 0) + { + _saveItemCommand.GetParameter(index++).Value = string.Join("|", item.Tags.ToArray()); + } + else + { + _saveItemCommand.GetParameter(index++).Value = null; + } + + _saveItemCommand.GetParameter(index++).Value = item.IsFolder; + + _saveItemCommand.GetParameter(index++).Value = item.GetBlockUnratedType().ToString(); + + var topParent = item.GetTopParent(); + if (topParent != null) + { + //Logger.Debug("Item {0} has top parent {1}", item.Id, topParent.Id); + _saveItemCommand.GetParameter(index++).Value = topParent.Id.ToString("N"); + } + else + { + //Logger.Debug("Item {0} has null top parent", item.Id); + _saveItemCommand.GetParameter(index++).Value = null; + } + + var isByName = false; + var byName = item as IItemByName; + if (byName != null) + { + var dualAccess = item as IHasDualAccess; + isByName = dualAccess == null || dualAccess.IsAccessedByName; + } + _saveItemCommand.GetParameter(index++).Value = isByName; + + _saveItemCommand.GetParameter(index++).Value = item.SourceType.ToString(); + + var trailer = item as Trailer; + if (trailer != null && trailer.TrailerTypes.Count > 0) + { + _saveItemCommand.GetParameter(index++).Value = string.Join("|", trailer.TrailerTypes.Select(i => i.ToString()).ToArray()); + } + else + { + _saveItemCommand.GetParameter(index++).Value = null; + } + + _saveItemCommand.GetParameter(index++).Value = item.CriticRating; + _saveItemCommand.GetParameter(index++).Value = item.CriticRatingSummary; + + if (!item.DateModifiedDuringLastRefresh.HasValue || item.DateModifiedDuringLastRefresh.Value == default(DateTime)) + { + _saveItemCommand.GetParameter(index++).Value = null; + } + else + { + _saveItemCommand.GetParameter(index++).Value = item.DateModifiedDuringLastRefresh.Value; + } + + var inheritedTags = item.GetInheritedTags(); + if (inheritedTags.Count > 0) + { + _saveItemCommand.GetParameter(index++).Value = string.Join("|", inheritedTags.ToArray()); + } + else + { + _saveItemCommand.GetParameter(index++).Value = null; + } + + if (string.IsNullOrWhiteSpace(item.Name)) + { + _saveItemCommand.GetParameter(index++).Value = null; + } + else + { + _saveItemCommand.GetParameter(index++).Value = item.Name.RemoveDiacritics(); + } + + _saveItemCommand.GetParameter(index++).Value = item.PresentationUniqueKey; + _saveItemCommand.GetParameter(index++).Value = item.SlugName; + _saveItemCommand.GetParameter(index++).Value = item.OriginalTitle; + + var video = item as Video; + if (video != null) + { + _saveItemCommand.GetParameter(index++).Value = video.PrimaryVersionId; + } + else + { + _saveItemCommand.GetParameter(index++).Value = null; + } + + var folder = item as Folder; + if (folder != null && folder.DateLastMediaAdded.HasValue) + { + _saveItemCommand.GetParameter(index++).Value = folder.DateLastMediaAdded.Value; + } + else + { + _saveItemCommand.GetParameter(index++).Value = null; + } + + _saveItemCommand.GetParameter(index++).Value = item.Album; + + _saveItemCommand.GetParameter(index++).Value = item.IsVirtualItem || (!item.IsFolder && item.LocationType == LocationType.Virtual); + + var hasSeries = item as IHasSeries; + if (hasSeries != null) + { + _saveItemCommand.GetParameter(index++).Value = hasSeries.SeriesName; + } + else + { + _saveItemCommand.GetParameter(index++).Value = null; + } + + _saveItemCommand.Transaction = transaction; + + _saveItemCommand.ExecuteNonQuery(); + + if (item.SupportsAncestors) + { + UpdateAncestors(item.Id, item.GetAncestorIds().Distinct().ToList(), transaction); + } + + UpdateUserDataKeys(item.Id, item.GetUserDataKeys().Distinct(StringComparer.OrdinalIgnoreCase).ToList(), transaction); + UpdateImages(item.Id, item.ImageInfos, transaction); + UpdateProviderIds(item.Id, item.ProviderIds, transaction); + UpdateItemValues(item.Id, GetItemValues(item), transaction); } + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save items:", e); + + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + + WriteLock.Release(); } } @@ -811,22 +957,19 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); - using (var connection = CreateConnection(true).Result) + using (var cmd = _connection.CreateCommand()) { - using (var cmd = connection.CreateCommand()) - { - cmd.CommandText = "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems where guid = @guid"; - cmd.Parameters.Add(cmd, "@guid", DbType.Guid).Value = id; + cmd.CommandText = "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems where guid = @guid"; + cmd.Parameters.Add(cmd, "@guid", DbType.Guid).Value = id; - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) + { + if (reader.Read()) { - if (reader.Read()) - { - return GetItem(reader); - } + return GetItem(reader); } - return null; } + return null; } } @@ -1231,25 +1374,22 @@ namespace MediaBrowser.Server.Implementations.Persistence } var list = new List(); - using (var connection = CreateConnection(true).Result) + using (var cmd = _connection.CreateCommand()) { - using (var cmd = connection.CreateCommand()) + cmd.CommandText = "select StartPositionTicks,Name,ImagePath from " + ChaptersTableName + " where ItemId = @ItemId order by ChapterIndex asc"; + + cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = id; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) { - cmd.CommandText = "select StartPositionTicks,Name,ImagePath from " + ChaptersTableName + " where ItemId = @ItemId order by ChapterIndex asc"; - - cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = id; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + while (reader.Read()) { - while (reader.Read()) - { - list.Add(GetChapter(reader)); - } + list.Add(GetChapter(reader)); } } - - return list; } + + return list; } /// @@ -1267,24 +1407,21 @@ namespace MediaBrowser.Server.Implementations.Persistence throw new ArgumentNullException("id"); } - using (var connection = CreateConnection(true).Result) + using (var cmd = _connection.CreateCommand()) { - using (var cmd = connection.CreateCommand()) + cmd.CommandText = "select StartPositionTicks,Name,ImagePath from " + ChaptersTableName + " where ItemId = @ItemId and ChapterIndex=@ChapterIndex"; + + cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = id; + cmd.Parameters.Add(cmd, "@ChapterIndex", DbType.Int32).Value = index; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) { - cmd.CommandText = "select StartPositionTicks,Name,ImagePath from " + ChaptersTableName + " where ItemId = @ItemId and ChapterIndex=@ChapterIndex"; - - cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = id; - cmd.Parameters.Add(cmd, "@ChapterIndex", DbType.Int32).Value = index; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) + if (reader.Read()) { - if (reader.Read()) - { - return GetChapter(reader); - } + return GetChapter(reader); } - return null; } + return null; } } @@ -1313,21 +1450,6 @@ namespace MediaBrowser.Server.Implementations.Persistence return chapter; } - private void DeleteChapters(IDbConnection connection, IDbTransaction transaction, Guid id) - { - using (var deleteChaptersCommand = connection.CreateCommand()) - { - deleteChaptersCommand.CommandText = "delete from " + ChaptersTableName + " where ItemId=@ItemId"; - deleteChaptersCommand.Parameters.Add(deleteChaptersCommand, "@ItemId"); - - deleteChaptersCommand.GetParameter(0).Value = id; - - deleteChaptersCommand.Transaction = transaction; - - deleteChaptersCommand.ExecuteNonQuery(); - } - } - /// /// Saves the chapters. /// @@ -1358,83 +1480,84 @@ namespace MediaBrowser.Server.Implementations.Persistence cancellationToken.ThrowIfCancellationRequested(); - using (var connection = await CreateConnection().ConfigureAwait(false)) + await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); + + IDbTransaction transaction = null; + + try { - IDbTransaction transaction = null; + transaction = _connection.BeginTransaction(); - try + // First delete chapters + _deleteChaptersCommand.GetParameter(0).Value = id; + + _deleteChaptersCommand.Transaction = transaction; + + _deleteChaptersCommand.ExecuteNonQuery(); + + var index = 0; + + foreach (var chapter in chapters) { - transaction = connection.BeginTransaction(); + cancellationToken.ThrowIfCancellationRequested(); - // First delete chapters - DeleteChapters(connection, transaction, id); + _saveChapterCommand.GetParameter(0).Value = id; + _saveChapterCommand.GetParameter(1).Value = index; + _saveChapterCommand.GetParameter(2).Value = chapter.StartPositionTicks; + _saveChapterCommand.GetParameter(3).Value = chapter.Name; + _saveChapterCommand.GetParameter(4).Value = chapter.ImagePath; - var index = 0; + _saveChapterCommand.Transaction = transaction; - if (chapters.Count > 0) - { - using (var saveChapterCommand = connection.CreateCommand()) - { - saveChapterCommand.CommandText = "replace into " + ChaptersTableName + " (ItemId, ChapterIndex, StartPositionTicks, Name, ImagePath) values (@ItemId, @ChapterIndex, @StartPositionTicks, @Name, @ImagePath)"; - saveChapterCommand.Parameters.Add(saveChapterCommand, "@ItemId"); - saveChapterCommand.Parameters.Add(saveChapterCommand, "@ChapterIndex"); - saveChapterCommand.Parameters.Add(saveChapterCommand, "@StartPositionTicks"); - saveChapterCommand.Parameters.Add(saveChapterCommand, "@Name"); - saveChapterCommand.Parameters.Add(saveChapterCommand, "@ImagePath"); + _saveChapterCommand.ExecuteNonQuery(); - if (chapters.Count > 1) - { - saveChapterCommand.Prepare(); - } - - foreach (var chapter in chapters) - { - cancellationToken.ThrowIfCancellationRequested(); - - saveChapterCommand.GetParameter(0).Value = id; - saveChapterCommand.GetParameter(1).Value = index; - saveChapterCommand.GetParameter(2).Value = chapter.StartPositionTicks; - saveChapterCommand.GetParameter(3).Value = chapter.Name; - saveChapterCommand.GetParameter(4).Value = chapter.ImagePath; - - saveChapterCommand.Transaction = transaction; - - saveChapterCommand.ExecuteNonQuery(); - - index++; - } - } - } - - transaction.Commit(); + index++; } - catch (OperationCanceledException) + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) { - if (transaction != null) - { - transaction.Rollback(); - } - - throw; + transaction.Rollback(); } - catch (Exception e) + + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save chapters:", e); + + if (transaction != null) { - Logger.ErrorException("Failed to save chapters:", e); - - if (transaction != null) - { - transaction.Rollback(); - } - - throw; + transaction.Rollback(); } - finally + + throw; + } + finally + { + if (transaction != null) { - if (transaction != null) - { - transaction.Dispose(); - } + transaction.Dispose(); } + + WriteLock.Release(); + } + } + + protected override void CloseConnection() + { + if (_connection != null) + { + if (_connection.IsOpen()) + { + _connection.Close(); + } + + _connection.Dispose(); + _connection = null; } } @@ -1508,13 +1631,13 @@ namespace MediaBrowser.Server.Implementations.Persistence if (EnableJoinUserData(query)) { - list.Add("UserData.UserId"); - list.Add("UserData.lastPlayedDate"); - list.Add("UserData.playbackPositionTicks"); - list.Add("UserData.playcount"); - list.Add("UserData.isFavorite"); - list.Add("UserData.played"); - list.Add("UserData.rating"); + list.Add("UserDataDb.UserData.UserId"); + list.Add("UserDataDb.UserData.lastPlayedDate"); + list.Add("UserDataDb.UserData.playbackPositionTicks"); + list.Add("UserDataDb.UserData.playcount"); + list.Add("UserDataDb.UserData.isFavorite"); + list.Add("UserDataDb.UserData.played"); + list.Add("UserDataDb.UserData.rating"); } if (query.SimilarTo != null) @@ -1568,7 +1691,7 @@ namespace MediaBrowser.Server.Implementations.Persistence return string.Empty; } - return " left join UserData on (select UserDataKey from UserDataKeys where ItemId=Guid order by Priority LIMIT 1)=UserData.Key"; + return " left join UserDataDb.UserData on (select UserDataKey from UserDataKeys where ItemId=Guid order by Priority LIMIT 1)=UserDataDb.UserData.Key"; } public IEnumerable GetItemList(InternalItemsQuery query) @@ -1582,61 +1705,53 @@ namespace MediaBrowser.Server.Implementations.Persistence var now = DateTime.UtcNow; - using (var connection = CreateConnection(true).Result) + using (var cmd = _connection.CreateCommand()) { + cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns, cmd)) + " from TypedBaseItems"; + cmd.CommandText += GetJoinUserDataText(query); + if (EnableJoinUserData(query)) { - AttachUserDataDb(connection); + cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; } - using (var cmd = connection.CreateCommand()) + var whereClauses = GetWhereClauses(query, cmd); + + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); + + cmd.CommandText += whereText; + + if (EnableGroupByPresentationUniqueKey(query)) { - cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns, cmd)) + " from TypedBaseItems"; - cmd.CommandText += GetJoinUserDataText(query); + cmd.CommandText += " Group by PresentationUniqueKey"; + } - if (EnableJoinUserData(query)) + cmd.CommandText += GetOrderByText(query); + + if (query.Limit.HasValue || query.StartIndex.HasValue) + { + var limit = query.Limit ?? int.MaxValue; + + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + + if (query.StartIndex.HasValue) { - cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); } + } - var whereClauses = GetWhereClauses(query, cmd); + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + LogQueryTime("GetItemList", cmd, now); - var whereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); - - cmd.CommandText += whereText; - - if (EnableGroupByPresentationUniqueKey(query)) + while (reader.Read()) { - cmd.CommandText += " Group by PresentationUniqueKey"; - } - - cmd.CommandText += GetOrderByText(query); - - if (query.Limit.HasValue || query.StartIndex.HasValue) - { - var limit = query.Limit ?? int.MaxValue; - - cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); - - if (query.StartIndex.HasValue) + var item = GetItem(reader); + if (item != null) { - cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); - } - } - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) - { - LogQueryTime("GetItemList", cmd, now); - - while (reader.Read()) - { - var item = GetItem(reader); - if (item != null) - { - yield return item; - } + yield return item; } } } @@ -1650,7 +1765,7 @@ namespace MediaBrowser.Server.Implementations.Persistence var slowThreshold = 1000; #if DEBUG - slowThreshold = 30; + slowThreshold = 100; #endif if (elapsed >= slowThreshold) @@ -1680,94 +1795,86 @@ namespace MediaBrowser.Server.Implementations.Persistence var now = DateTime.UtcNow; - using (var connection = CreateConnection(true).Result) + using (var cmd = _connection.CreateCommand()) { + cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns, cmd)) + " from TypedBaseItems"; + cmd.CommandText += GetJoinUserDataText(query); + if (EnableJoinUserData(query)) { - AttachUserDataDb(connection); + cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; } - using (var cmd = connection.CreateCommand()) + var whereClauses = GetWhereClauses(query, cmd); + + var whereTextWithoutPaging = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); + + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); + + cmd.CommandText += whereText; + + if (EnableGroupByPresentationUniqueKey(query)) { - cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns, cmd)) + " from TypedBaseItems"; - cmd.CommandText += GetJoinUserDataText(query); - - if (EnableJoinUserData(query)) - { - cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; - } - - var whereClauses = GetWhereClauses(query, cmd); - - var whereTextWithoutPaging = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); - - var whereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); - - cmd.CommandText += whereText; - - if (EnableGroupByPresentationUniqueKey(query)) - { - cmd.CommandText += " Group by PresentationUniqueKey"; - } - - cmd.CommandText += GetOrderByText(query); - - if (query.Limit.HasValue || query.StartIndex.HasValue) - { - var limit = query.Limit ?? int.MaxValue; - - cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); - - if (query.StartIndex.HasValue) - { - cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); - } - } - - if (EnableGroupByPresentationUniqueKey(query)) - { - cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems"; - } - else - { - cmd.CommandText += "; select count (guid) from TypedBaseItems"; - } - - cmd.CommandText += GetJoinUserDataText(query); - cmd.CommandText += whereTextWithoutPaging; - - var list = new List(); - var count = 0; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) - { - LogQueryTime("GetItems", cmd, now); - - while (reader.Read()) - { - var item = GetItem(reader); - if (item != null) - { - list.Add(item); - } - } - - if (reader.NextResult() && reader.Read()) - { - count = reader.GetInt32(0); - } - } - - return new QueryResult() - { - Items = list.ToArray(), - TotalRecordCount = count - }; + cmd.CommandText += " Group by PresentationUniqueKey"; } + + cmd.CommandText += GetOrderByText(query); + + if (query.Limit.HasValue || query.StartIndex.HasValue) + { + var limit = query.Limit ?? int.MaxValue; + + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + + if (query.StartIndex.HasValue) + { + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + } + } + + if (EnableGroupByPresentationUniqueKey(query)) + { + cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems"; + } + else + { + cmd.CommandText += "; select count (guid) from TypedBaseItems"; + } + + cmd.CommandText += GetJoinUserDataText(query); + cmd.CommandText += whereTextWithoutPaging; + + var list = new List(); + var count = 0; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) + { + LogQueryTime("GetItems", cmd, now); + + while (reader.Read()) + { + var item = GetItem(reader); + if (item != null) + { + list.Add(item); + } + } + + if (reader.NextResult() && reader.Read()) + { + count = reader.GetInt32(0); + } + } + + return new QueryResult() + { + Items = list.ToArray(), + TotalRecordCount = count + }; } } @@ -1885,64 +1992,56 @@ namespace MediaBrowser.Server.Implementations.Persistence var now = DateTime.UtcNow; - using (var connection = CreateConnection(true).Result) + using (var cmd = _connection.CreateCommand()) { + cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" }, cmd)) + " from TypedBaseItems"; + cmd.CommandText += GetJoinUserDataText(query); + if (EnableJoinUserData(query)) { - AttachUserDataDb(connection); + cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; } - using (var cmd = connection.CreateCommand()) + var whereClauses = GetWhereClauses(query, cmd); + + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); + + cmd.CommandText += whereText; + + if (EnableGroupByPresentationUniqueKey(query)) { - cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" }, cmd)) + " from TypedBaseItems"; - cmd.CommandText += GetJoinUserDataText(query); - - if (EnableJoinUserData(query)) - { - cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; - } - - var whereClauses = GetWhereClauses(query, cmd); - - var whereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); - - cmd.CommandText += whereText; - - if (EnableGroupByPresentationUniqueKey(query)) - { - cmd.CommandText += " Group by PresentationUniqueKey"; - } - - cmd.CommandText += GetOrderByText(query); - - if (query.Limit.HasValue || query.StartIndex.HasValue) - { - var limit = query.Limit ?? int.MaxValue; - - cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); - - if (query.StartIndex.HasValue) - { - cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); - } - } - - var list = new List(); - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) - { - LogQueryTime("GetItemIdsList", cmd, now); - - while (reader.Read()) - { - list.Add(reader.GetGuid(0)); - } - } - - return list; + cmd.CommandText += " Group by PresentationUniqueKey"; } + + cmd.CommandText += GetOrderByText(query); + + if (query.Limit.HasValue || query.StartIndex.HasValue) + { + var limit = query.Limit ?? int.MaxValue; + + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + + if (query.StartIndex.HasValue) + { + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + } + } + + var list = new List(); + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + LogQueryTime("GetItemIdsList", cmd, now); + + while (reader.Read()) + { + list.Add(reader.GetGuid(0)); + } + } + + return list; } } @@ -1955,76 +2054,73 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); - using (var connection = CreateConnection(true).Result) + using (var cmd = _connection.CreateCommand()) { - using (var cmd = connection.CreateCommand()) + cmd.CommandText = "select guid,path from TypedBaseItems"; + + var whereClauses = GetWhereClauses(query, cmd); + + var whereTextWithoutPaging = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); + + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); + + cmd.CommandText += whereText; + + if (EnableGroupByPresentationUniqueKey(query)) { - cmd.CommandText = "select guid,path from TypedBaseItems"; - - var whereClauses = GetWhereClauses(query, cmd); - - var whereTextWithoutPaging = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); - - var whereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); - - cmd.CommandText += whereText; - - if (EnableGroupByPresentationUniqueKey(query)) - { - cmd.CommandText += " Group by PresentationUniqueKey"; - } - - cmd.CommandText += GetOrderByText(query); - - if (query.Limit.HasValue || query.StartIndex.HasValue) - { - var limit = query.Limit ?? int.MaxValue; - - cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); - - if (query.StartIndex.HasValue) - { - cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); - } - } - - cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging; - - var list = new List>(); - var count = 0; - - Logger.Debug(cmd.CommandText); - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) - { - while (reader.Read()) - { - var id = reader.GetGuid(0); - string path = null; - - if (!reader.IsDBNull(1)) - { - path = reader.GetString(1); - } - list.Add(new Tuple(id, path)); - } - - if (reader.NextResult() && reader.Read()) - { - count = reader.GetInt32(0); - } - } - - return new QueryResult>() - { - Items = list.ToArray(), - TotalRecordCount = count - }; + cmd.CommandText += " Group by PresentationUniqueKey"; } + + cmd.CommandText += GetOrderByText(query); + + if (query.Limit.HasValue || query.StartIndex.HasValue) + { + var limit = query.Limit ?? int.MaxValue; + + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + + if (query.StartIndex.HasValue) + { + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + } + } + + cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging; + + var list = new List>(); + var count = 0; + + Logger.Debug(cmd.CommandText); + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) + { + while (reader.Read()) + { + var id = reader.GetGuid(0); + string path = null; + + if (!reader.IsDBNull(1)) + { + path = reader.GetString(1); + } + list.Add(new Tuple(id, path)); + } + + if (reader.NextResult() && reader.Read()) + { + count = reader.GetInt32(0); + } + } + + return new QueryResult>() + { + Items = list.ToArray(), + TotalRecordCount = count + }; } } @@ -2039,86 +2135,78 @@ namespace MediaBrowser.Server.Implementations.Persistence var now = DateTime.UtcNow; - using (var connection = CreateConnection(true).Result) + using (var cmd = _connection.CreateCommand()) { + cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" }, cmd)) + " from TypedBaseItems"; + + var whereClauses = GetWhereClauses(query, cmd); + cmd.CommandText += GetJoinUserDataText(query); + if (EnableJoinUserData(query)) { - AttachUserDataDb(connection); + cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; } - using (var cmd = connection.CreateCommand()) + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); + + cmd.CommandText += whereText; + + if (EnableGroupByPresentationUniqueKey(query)) { - cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" }, cmd)) + " from TypedBaseItems"; - - var whereClauses = GetWhereClauses(query, cmd); - cmd.CommandText += GetJoinUserDataText(query); - - if (EnableJoinUserData(query)) - { - cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; - } - - var whereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); - - cmd.CommandText += whereText; - - if (EnableGroupByPresentationUniqueKey(query)) - { - cmd.CommandText += " Group by PresentationUniqueKey"; - } - - cmd.CommandText += GetOrderByText(query); - - if (query.Limit.HasValue || query.StartIndex.HasValue) - { - var limit = query.Limit ?? int.MaxValue; - - cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); - - if (query.StartIndex.HasValue) - { - cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); - } - } - - if (EnableGroupByPresentationUniqueKey(query)) - { - cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems"; - } - else - { - cmd.CommandText += "; select count (guid) from TypedBaseItems"; - } - - cmd.CommandText += GetJoinUserDataText(query); - cmd.CommandText += whereText; - - var list = new List(); - var count = 0; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) - { - LogQueryTime("GetItemIds", cmd, now); - - while (reader.Read()) - { - list.Add(reader.GetGuid(0)); - } - - if (reader.NextResult() && reader.Read()) - { - count = reader.GetInt32(0); - } - } - - return new QueryResult() - { - Items = list.ToArray(), - TotalRecordCount = count - }; + cmd.CommandText += " Group by PresentationUniqueKey"; } + + cmd.CommandText += GetOrderByText(query); + + if (query.Limit.HasValue || query.StartIndex.HasValue) + { + var limit = query.Limit ?? int.MaxValue; + + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + + if (query.StartIndex.HasValue) + { + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + } + } + + if (EnableGroupByPresentationUniqueKey(query)) + { + cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems"; + } + else + { + cmd.CommandText += "; select count (guid) from TypedBaseItems"; + } + + cmd.CommandText += GetJoinUserDataText(query); + cmd.CommandText += whereText; + + var list = new List(); + var count = 0; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) + { + LogQueryTime("GetItemIds", cmd, now); + + while (reader.Read()) + { + list.Add(reader.GetGuid(0)); + } + + if (reader.NextResult() && reader.Read()) + { + count = reader.GetInt32(0); + } + } + + return new QueryResult() + { + Items = list.ToArray(), + TotalRecordCount = count + }; } } @@ -2195,18 +2283,6 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.Parameters.Add(cmd, "@IsFolder", DbType.Boolean).Value = query.IsFolder; } - var excludeTypes = query.ExcludeItemTypes.SelectMany(MapIncludeItemTypes).ToArray(); - if (excludeTypes.Length == 1) - { - whereClauses.Add("type<>@type"); - cmd.Parameters.Add(cmd, "@type", DbType.String).Value = excludeTypes[0]; - } - else if (excludeTypes.Length > 1) - { - var inClause = string.Join(",", excludeTypes.Select(i => "'" + i + "'").ToArray()); - whereClauses.Add(string.Format("type not in ({0})", inClause)); - } - var includeTypes = query.IncludeItemTypes.SelectMany(MapIncludeItemTypes).ToArray(); if (includeTypes.Length == 1) { @@ -2219,6 +2295,18 @@ namespace MediaBrowser.Server.Implementations.Persistence whereClauses.Add(string.Format("type in ({0})", inClause)); } + var excludeTypes = query.ExcludeItemTypes.SelectMany(MapIncludeItemTypes).ToArray(); + if (excludeTypes.Length == 1) + { + whereClauses.Add("type<>@type"); + cmd.Parameters.Add(cmd, "@type", DbType.String).Value = excludeTypes[0]; + } + else if (excludeTypes.Length > 1) + { + var inClause = string.Join(",", excludeTypes.Select(i => "'" + i + "'").ToArray()); + whereClauses.Add(string.Format("type not in ({0})", inClause)); + } + if (query.ChannelIds.Length == 1) { whereClauses.Add("ChannelId=@ChannelId"); @@ -2921,88 +3009,77 @@ namespace MediaBrowser.Server.Implementations.Persistence private async Task UpdateInheritedTags(CancellationToken cancellationToken) { - using (var connection = await CreateConnection().ConfigureAwait(false)) + var newValues = new List>(); + + using (var cmd = _connection.CreateCommand()) { - var newValues = new List>(); + cmd.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 cmd = connection.CreateCommand()) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) { - cmd.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 reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + while (reader.Read()) { - while (reader.Read()) - { - var id = reader.GetGuid(0); - string value = reader.IsDBNull(2) ? null : reader.GetString(2); + var id = reader.GetGuid(0); + string value = reader.IsDBNull(2) ? null : reader.GetString(2); - newValues.Add(new Tuple(id, value)); - } + newValues.Add(new Tuple(id, value)); } } + } - Logger.Debug("UpdateInheritedTags - {0} rows", newValues.Count); - if (newValues.Count == 0) + Logger.Debug("UpdateInheritedTags - {0} rows", newValues.Count); + if (newValues.Count == 0) + { + return; + } + + await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); + + IDbTransaction transaction = null; + + try + { + transaction = _connection.BeginTransaction(); + + foreach (var item in newValues) { - return; + _updateInheritedTagsCommand.GetParameter(0).Value = item.Item1; + _updateInheritedTagsCommand.GetParameter(1).Value = item.Item2; + + _updateInheritedTagsCommand.Transaction = transaction; + _updateInheritedTagsCommand.ExecuteNonQuery(); } - IDbTransaction transaction = null; - - try + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) { - transaction = connection.BeginTransaction(); - - using (var updateInheritedTagsCommand = connection.CreateCommand()) - { - updateInheritedTagsCommand.CommandText = "Update TypedBaseItems set InheritedTags=@InheritedTags where Guid=@Guid"; - updateInheritedTagsCommand.Parameters.Add(updateInheritedTagsCommand, "@Guid"); - updateInheritedTagsCommand.Parameters.Add(updateInheritedTagsCommand, "@InheritedTags"); - - if (newValues.Count > 1) - { - updateInheritedTagsCommand.Prepare(); - } - - foreach (var item in newValues) - { - updateInheritedTagsCommand.GetParameter(0).Value = item.Item1; - updateInheritedTagsCommand.GetParameter(1).Value = item.Item2; - - updateInheritedTagsCommand.Transaction = transaction; - updateInheritedTagsCommand.ExecuteNonQuery(); - } - } - - transaction.Commit(); + transaction.Rollback(); } - catch (OperationCanceledException) + + throw; + } + catch (Exception e) + { + Logger.ErrorException("Error running query:", e); + + if (transaction != null) { - if (transaction != null) - { - transaction.Rollback(); - } - - throw; + transaction.Rollback(); } - catch (Exception e) + + throw; + } + finally + { + if (transaction != null) { - Logger.ErrorException("Error running query:", e); - - if (transaction != null) - { - transaction.Rollback(); - } - - throw; - } - finally - { - if (transaction != null) - { - transaction.Dispose(); - } + transaction.Dispose(); } + + WriteLock.Release(); } } @@ -3010,82 +3087,75 @@ namespace MediaBrowser.Server.Implementations.Persistence { var newValues = new List>(); - using (var connection = await CreateConnection().ConfigureAwait(false)) + using (var cmd = _connection.CreateCommand()) { - using (var cmd = connection.CreateCommand()) + cmd.CommandText = "select Guid,InheritedParentalRatingValue,(select Max(ParentalRatingValue, (select COALESCE(MAX(ParentalRatingValue),0) from TypedBaseItems where guid in (Select AncestorId from AncestorIds where ItemId=Outer.guid)))) as NewInheritedParentalRatingValue from typedbaseitems as Outer where InheritedParentalRatingValue <> NewInheritedParentalRatingValue"; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) { - cmd.CommandText = "select Guid,InheritedParentalRatingValue,(select Max(ParentalRatingValue, (select COALESCE(MAX(ParentalRatingValue),0) from TypedBaseItems where guid in (Select AncestorId from AncestorIds where ItemId=Outer.guid)))) as NewInheritedParentalRatingValue from typedbaseitems as Outer where InheritedParentalRatingValue <> NewInheritedParentalRatingValue"; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + while (reader.Read()) { - while (reader.Read()) - { - var id = reader.GetGuid(0); - var newValue = reader.GetInt32(2); + var id = reader.GetGuid(0); + var newValue = reader.GetInt32(2); - newValues.Add(new Tuple(id, newValue)); - } + newValues.Add(new Tuple(id, newValue)); } } + } - Logger.Debug("UpdateInheritedParentalRatings - {0} rows", newValues.Count); - if (newValues.Count == 0) + Logger.Debug("UpdateInheritedParentalRatings - {0} rows", newValues.Count); + if (newValues.Count == 0) + { + return; + } + + await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); + + IDbTransaction transaction = null; + + try + { + transaction = _connection.BeginTransaction(); + + foreach (var item in newValues) { - return; + _updateInheritedRatingCommand.GetParameter(0).Value = item.Item1; + _updateInheritedRatingCommand.GetParameter(1).Value = item.Item2; + + _updateInheritedRatingCommand.Transaction = transaction; + _updateInheritedRatingCommand.ExecuteNonQuery(); } - using (var updateInheritedRatingCommand = connection.CreateCommand()) + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) { - updateInheritedRatingCommand.CommandText = "Update TypedBaseItems set InheritedParentalRatingValue=@InheritedParentalRatingValue where Guid=@Guid"; - updateInheritedRatingCommand.Parameters.Add(updateInheritedRatingCommand, "@Guid"); - updateInheritedRatingCommand.Parameters.Add(updateInheritedRatingCommand, "@InheritedParentalRatingValue"); - updateInheritedRatingCommand.Prepare(); - - IDbTransaction transaction = null; - - try - { - transaction = connection.BeginTransaction(); - - foreach (var item in newValues) - { - updateInheritedRatingCommand.GetParameter(0).Value = item.Item1; - updateInheritedRatingCommand.GetParameter(1).Value = item.Item2; - - updateInheritedRatingCommand.Transaction = transaction; - updateInheritedRatingCommand.ExecuteNonQuery(); - } - - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) - { - transaction.Rollback(); - } - - throw; - } - catch (Exception e) - { - Logger.ErrorException("Error running query:", e); - - if (transaction != null) - { - transaction.Rollback(); - } - - throw; - } - finally - { - if (transaction != null) - { - transaction.Dispose(); - } - } + transaction.Rollback(); } + + throw; + } + catch (Exception e) + { + Logger.ErrorException("Error running query:", e); + + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + + WriteLock.Release(); } } @@ -3128,73 +3198,89 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); - using (var connection = await CreateConnection().ConfigureAwait(false)) + await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); + + IDbTransaction transaction = null; + + try { - IDbTransaction transaction = null; + transaction = _connection.BeginTransaction(); - try + // Delete people + _deletePeopleCommand.GetParameter(0).Value = id; + _deletePeopleCommand.Transaction = transaction; + _deletePeopleCommand.ExecuteNonQuery(); + + // Delete chapters + _deleteChaptersCommand.GetParameter(0).Value = id; + _deleteChaptersCommand.Transaction = transaction; + _deleteChaptersCommand.ExecuteNonQuery(); + + // Delete media streams + _deleteStreamsCommand.GetParameter(0).Value = id; + _deleteStreamsCommand.Transaction = transaction; + _deleteStreamsCommand.ExecuteNonQuery(); + + // Delete ancestors + _deleteAncestorsCommand.GetParameter(0).Value = id; + _deleteAncestorsCommand.Transaction = transaction; + _deleteAncestorsCommand.ExecuteNonQuery(); + + // Delete user data keys + _deleteUserDataKeysCommand.GetParameter(0).Value = id; + _deleteUserDataKeysCommand.Transaction = transaction; + _deleteUserDataKeysCommand.ExecuteNonQuery(); + + // Delete item values + _deleteItemValuesCommand.GetParameter(0).Value = id; + _deleteItemValuesCommand.Transaction = transaction; + _deleteItemValuesCommand.ExecuteNonQuery(); + + // Delete provider ids + _deleteProviderIdsCommand.GetParameter(0).Value = id; + _deleteProviderIdsCommand.Transaction = transaction; + _deleteProviderIdsCommand.ExecuteNonQuery(); + + // Delete images + _deleteImagesCommand.GetParameter(0).Value = id; + _deleteImagesCommand.Transaction = transaction; + _deleteImagesCommand.ExecuteNonQuery(); + + // Delete the item + _deleteItemCommand.GetParameter(0).Value = id; + _deleteItemCommand.Transaction = transaction; + _deleteItemCommand.ExecuteNonQuery(); + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) { - transaction = connection.BeginTransaction(); - - // Delete people - DeletePeople(connection, transaction, id); - DeleteChapters(connection, transaction, id); - DeleteMediaStreams(connection, transaction, id); - - // Delete ancestors - DeleteAncestors(connection, transaction, id); - - // Delete user data keys - DeleteUserDataKeys(connection, transaction, id); - - // Delete item values - DeleteItemValues(connection, transaction, id); - - // Delete provider ids - DeleteProviderIds(connection, transaction, id); - - DeleteImages(connection, transaction, id); - - // Delete the item - using (var deleteItemCommand = connection.CreateCommand()) - { - deleteItemCommand.CommandText = "delete from TypedBaseItems where guid=@Id"; - deleteItemCommand.Parameters.Add(deleteItemCommand, "@Id"); - - deleteItemCommand.GetParameter(0).Value = id; - deleteItemCommand.Transaction = transaction; - deleteItemCommand.ExecuteNonQuery(); - } - - transaction.Commit(); + transaction.Rollback(); } - catch (OperationCanceledException) + + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save children:", e); + + if (transaction != null) { - if (transaction != null) - { - transaction.Rollback(); - } - - throw; + transaction.Rollback(); } - catch (Exception e) + + throw; + } + finally + { + if (transaction != null) { - Logger.ErrorException("Failed to save children:", e); - - if (transaction != null) - { - transaction.Rollback(); - } - - throw; - } - finally - { - if (transaction != null) - { - transaction.Dispose(); - } + transaction.Dispose(); } + + WriteLock.Release(); } } @@ -3207,33 +3293,30 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); - using (var connection = CreateConnection(true).Result) + using (var cmd = _connection.CreateCommand()) { - using (var cmd = connection.CreateCommand()) + cmd.CommandText = "select Distinct Name from People"; + + var whereClauses = GetPeopleWhereClauses(query, cmd); + + if (whereClauses.Count > 0) { - cmd.CommandText = "select Distinct Name from People"; - - var whereClauses = GetPeopleWhereClauses(query, cmd); - - if (whereClauses.Count > 0) - { - cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); - } - - cmd.CommandText += " order by ListOrder"; - - var list = new List(); - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) - { - while (reader.Read()) - { - list.Add(reader.GetString(0)); - } - } - - return list; + cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); } + + cmd.CommandText += " order by ListOrder"; + + var list = new List(); + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) + { + list.Add(reader.GetString(0)); + } + } + + return list; } } @@ -3246,33 +3329,30 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); - using (var connection = CreateConnection(true).Result) + using (var cmd = _connection.CreateCommand()) { - using (var cmd = connection.CreateCommand()) + cmd.CommandText = "select ItemId, Name, Role, PersonType, SortOrder from People"; + + var whereClauses = GetPeopleWhereClauses(query, cmd); + + if (whereClauses.Count > 0) { - cmd.CommandText = "select ItemId, Name, Role, PersonType, SortOrder from People"; - - var whereClauses = GetPeopleWhereClauses(query, cmd); - - if (whereClauses.Count > 0) - { - cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); - } - - cmd.CommandText += " order by ListOrder"; - - var list = new List(); - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) - { - while (reader.Read()) - { - list.Add(GetPerson(reader)); - } - } - - return list; + cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); } + + cmd.CommandText += " order by ListOrder"; + + var list = new List(); + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) + { + list.Add(GetPerson(reader)); + } + } + + return list; } } @@ -3326,21 +3406,7 @@ namespace MediaBrowser.Server.Implementations.Persistence return whereClauses; } - private void DeleteAncestors(IDbConnection connection, IDbTransaction transaction, Guid id) - { - using (var deleteAncestorsCommand = connection.CreateCommand()) - { - deleteAncestorsCommand.CommandText = "delete from AncestorIds where ItemId=@Id"; - deleteAncestorsCommand.Parameters.Add(deleteAncestorsCommand, "@Id"); - - deleteAncestorsCommand.GetParameter(0).Value = id; - deleteAncestorsCommand.Transaction = transaction; - - deleteAncestorsCommand.ExecuteNonQuery(); - } - } - - private void UpdateAncestors(Guid itemId, List ancestorIds, IDbConnection connection, IDbTransaction transaction) + private void UpdateAncestors(Guid itemId, List ancestorIds, IDbTransaction transaction) { if (itemId == Guid.Empty) { @@ -3355,33 +3421,20 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); // First delete - DeleteAncestors(connection, transaction, itemId); + _deleteAncestorsCommand.GetParameter(0).Value = itemId; + _deleteAncestorsCommand.Transaction = transaction; - if (ancestorIds.Count > 0) + _deleteAncestorsCommand.ExecuteNonQuery(); + + foreach (var ancestorId in ancestorIds) { - using (var saveAncestorCommand = connection.CreateCommand()) - { - saveAncestorCommand.CommandText = "insert into AncestorIds (ItemId, AncestorId, AncestorIdText) values (@ItemId, @AncestorId, @AncestorIdText)"; - saveAncestorCommand.Parameters.Add(saveAncestorCommand, "@ItemId"); - saveAncestorCommand.Parameters.Add(saveAncestorCommand, "@AncestorId"); - saveAncestorCommand.Parameters.Add(saveAncestorCommand, "@AncestorIdText"); + _saveAncestorCommand.GetParameter(0).Value = itemId; + _saveAncestorCommand.GetParameter(1).Value = ancestorId; + _saveAncestorCommand.GetParameter(2).Value = ancestorId.ToString("N"); - if (ancestorIds.Count > 1) - { - saveAncestorCommand.Prepare(); - } + _saveAncestorCommand.Transaction = transaction; - foreach (var ancestorId in ancestorIds) - { - saveAncestorCommand.GetParameter(0).Value = itemId; - saveAncestorCommand.GetParameter(1).Value = ancestorId; - saveAncestorCommand.GetParameter(2).Value = ancestorId.ToString("N"); - - saveAncestorCommand.Transaction = transaction; - - saveAncestorCommand.ExecuteNonQuery(); - } - } + _saveAncestorCommand.ExecuteNonQuery(); } } @@ -3409,20 +3462,7 @@ namespace MediaBrowser.Server.Implementations.Persistence return list; } - private void DeleteImages(IDbConnection connection, IDbTransaction transaction, Guid id) - { - using (var deleteImagesCommand = connection.CreateCommand()) - { - deleteImagesCommand.CommandText = "delete from Images where ItemId=@Id"; - deleteImagesCommand.Parameters.Add(deleteImagesCommand, "@Id"); - - deleteImagesCommand.GetParameter(0).Value = id; - deleteImagesCommand.Transaction = transaction; - deleteImagesCommand.ExecuteNonQuery(); - } - } - - private void UpdateImages(Guid itemId, List images, IDbConnection connection, IDbTransaction transaction) + private void UpdateImages(Guid itemId, List images, IDbTransaction transaction) { if (itemId == Guid.Empty) { @@ -3437,70 +3477,38 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); // First delete - DeleteImages(connection, transaction, itemId); + _deleteImagesCommand.GetParameter(0).Value = itemId; + _deleteImagesCommand.Transaction = transaction; - if (images.Count > 0) + _deleteImagesCommand.ExecuteNonQuery(); + + var index = 0; + foreach (var image in images) { - using (var saveImagesCommand = connection.CreateCommand()) + _saveImagesCommand.GetParameter(0).Value = itemId; + _saveImagesCommand.GetParameter(1).Value = image.Type; + _saveImagesCommand.GetParameter(2).Value = image.Path; + + if (image.DateModified == default(DateTime)) { - var index = 0; - - saveImagesCommand.CommandText = "insert into Images (ItemId, ImageType, Path, DateModified, IsPlaceHolder, SortOrder) values (@ItemId, @ImageType, @Path, @DateModified, @IsPlaceHolder, @SortOrder)"; - saveImagesCommand.Parameters.Add(saveImagesCommand, "@ItemId"); - saveImagesCommand.Parameters.Add(saveImagesCommand, "@ImageType"); - saveImagesCommand.Parameters.Add(saveImagesCommand, "@Path"); - saveImagesCommand.Parameters.Add(saveImagesCommand, "@DateModified"); - saveImagesCommand.Parameters.Add(saveImagesCommand, "@IsPlaceHolder"); - saveImagesCommand.Parameters.Add(saveImagesCommand, "@SortOrder"); - - if (images.Count > 1) - { - saveImagesCommand.Prepare(); - } - - foreach (var image in images) - { - saveImagesCommand.GetParameter(0).Value = itemId; - saveImagesCommand.GetParameter(1).Value = image.Type; - saveImagesCommand.GetParameter(2).Value = image.Path; - - if (image.DateModified == default(DateTime)) - { - saveImagesCommand.GetParameter(3).Value = null; - } - else - { - saveImagesCommand.GetParameter(3).Value = image.DateModified; - } - - saveImagesCommand.GetParameter(4).Value = image.IsPlaceholder; - saveImagesCommand.GetParameter(5).Value = index; - - saveImagesCommand.Transaction = transaction; - - saveImagesCommand.ExecuteNonQuery(); - index++; - } + _saveImagesCommand.GetParameter(3).Value = null; } + else + { + _saveImagesCommand.GetParameter(3).Value = image.DateModified; + } + + _saveImagesCommand.GetParameter(4).Value = image.IsPlaceholder; + _saveImagesCommand.GetParameter(5).Value = index; + + _saveImagesCommand.Transaction = transaction; + + _saveImagesCommand.ExecuteNonQuery(); + index++; } } - private void DeleteProviderIds(IDbConnection connection, IDbTransaction transaction, Guid itemId) - { - using (var deleteProviderIdsCommand = connection.CreateCommand()) - { - // provider ids - deleteProviderIdsCommand.CommandText = "delete from ProviderIds where ItemId=@Id"; - deleteProviderIdsCommand.Parameters.Add(deleteProviderIdsCommand, "@Id"); - - deleteProviderIdsCommand.GetParameter(0).Value = itemId; - deleteProviderIdsCommand.Transaction = transaction; - - deleteProviderIdsCommand.ExecuteNonQuery(); - } - } - - private void UpdateProviderIds(Guid itemId, Dictionary values, IDbConnection connection, IDbTransaction transaction) + private void UpdateProviderIds(Guid itemId, Dictionary values, IDbTransaction transaction) { if (itemId == Guid.Empty) { @@ -3515,51 +3523,23 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); // First delete - DeleteProviderIds(connection, transaction, itemId); + _deleteProviderIdsCommand.GetParameter(0).Value = itemId; + _deleteProviderIdsCommand.Transaction = transaction; - if (values.Count > 0) + _deleteProviderIdsCommand.ExecuteNonQuery(); + + foreach (var pair in values) { - using (var saveProviderIdsCommand = connection.CreateCommand()) - { - saveProviderIdsCommand.CommandText = "insert into ProviderIds (ItemId, Name, Value) values (@ItemId, @Name, @Value)"; - saveProviderIdsCommand.Parameters.Add(saveProviderIdsCommand, "@ItemId"); - saveProviderIdsCommand.Parameters.Add(saveProviderIdsCommand, "@Name"); - saveProviderIdsCommand.Parameters.Add(saveProviderIdsCommand, "@Value"); + _saveProviderIdsCommand.GetParameter(0).Value = itemId; + _saveProviderIdsCommand.GetParameter(1).Value = pair.Key; + _saveProviderIdsCommand.GetParameter(2).Value = pair.Value; + _saveProviderIdsCommand.Transaction = transaction; - if (values.Count > 1) - { - saveProviderIdsCommand.Prepare(); - } - - foreach (var pair in values) - { - saveProviderIdsCommand.GetParameter(0).Value = itemId; - saveProviderIdsCommand.GetParameter(1).Value = pair.Key; - saveProviderIdsCommand.GetParameter(2).Value = pair.Value; - saveProviderIdsCommand.Transaction = transaction; - - saveProviderIdsCommand.ExecuteNonQuery(); - } - } + _saveProviderIdsCommand.ExecuteNonQuery(); } } - private void DeleteItemValues(IDbConnection connection, IDbTransaction transaction, Guid itemId) - { - using (var deleteItemValuesCommand = connection.CreateCommand()) - { - deleteItemValuesCommand.CommandText = "delete from ItemValues where ItemId=@Id"; - deleteItemValuesCommand.Parameters.Add(deleteItemValuesCommand, "@Id"); - - // First delete - deleteItemValuesCommand.GetParameter(0).Value = itemId; - deleteItemValuesCommand.Transaction = transaction; - - deleteItemValuesCommand.ExecuteNonQuery(); - } - } - - private void UpdateItemValues(Guid itemId, List> values, IDbConnection connection, IDbTransaction transaction) + private void UpdateItemValues(Guid itemId, List> values, IDbTransaction transaction) { if (itemId == Guid.Empty) { @@ -3574,51 +3554,23 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); // First delete - DeleteItemValues(connection, transaction, itemId); + _deleteItemValuesCommand.GetParameter(0).Value = itemId; + _deleteItemValuesCommand.Transaction = transaction; - if (values.Count > 0) + _deleteItemValuesCommand.ExecuteNonQuery(); + + foreach (var pair in values) { - using (var saveItemValuesCommand = connection.CreateCommand()) - { - saveItemValuesCommand.CommandText = "insert into ItemValues (ItemId, Type, Value) values (@ItemId, @Type, @Value)"; - saveItemValuesCommand.Parameters.Add(saveItemValuesCommand, "@ItemId"); - saveItemValuesCommand.Parameters.Add(saveItemValuesCommand, "@Type"); - saveItemValuesCommand.Parameters.Add(saveItemValuesCommand, "@Value"); + _saveItemValuesCommand.GetParameter(0).Value = itemId; + _saveItemValuesCommand.GetParameter(1).Value = pair.Item1; + _saveItemValuesCommand.GetParameter(2).Value = pair.Item2; + _saveItemValuesCommand.Transaction = transaction; - if (values.Count > 1) - { - saveItemValuesCommand.Prepare(); - } - - foreach (var pair in values) - { - saveItemValuesCommand.GetParameter(0).Value = itemId; - saveItemValuesCommand.GetParameter(1).Value = pair.Item1; - saveItemValuesCommand.GetParameter(2).Value = pair.Item2; - saveItemValuesCommand.Transaction = transaction; - - saveItemValuesCommand.ExecuteNonQuery(); - } - } + _saveItemValuesCommand.ExecuteNonQuery(); } } - private void DeleteUserDataKeys(IDbConnection connection, IDbTransaction transaction, Guid itemId) - { - using (var deleteUserDataKeysCommand = connection.CreateCommand()) - { - // user data - deleteUserDataKeysCommand.CommandText = "delete from UserDataKeys where ItemId=@Id"; - deleteUserDataKeysCommand.Parameters.Add(deleteUserDataKeysCommand, "@Id"); - - deleteUserDataKeysCommand.GetParameter(0).Value = itemId; - deleteUserDataKeysCommand.Transaction = transaction; - - deleteUserDataKeysCommand.ExecuteNonQuery(); - } - } - - private void UpdateUserDataKeys(Guid itemId, List keys, IDbConnection connection, IDbTransaction transaction) + private void UpdateUserDataKeys(Guid itemId, List keys, IDbTransaction transaction) { if (itemId == Guid.Empty) { @@ -3633,50 +3585,21 @@ namespace MediaBrowser.Server.Implementations.Persistence CheckDisposed(); // First delete - DeleteUserDataKeys(connection, transaction, itemId); + _deleteUserDataKeysCommand.GetParameter(0).Value = itemId; + _deleteUserDataKeysCommand.Transaction = transaction; + _deleteUserDataKeysCommand.ExecuteNonQuery(); var index = 0; - if (keys.Count > 0) + foreach (var key in keys) { - using (var saveUserDataKeysCommand = connection.CreateCommand()) - { - saveUserDataKeysCommand.CommandText = "insert into UserDataKeys (ItemId, UserDataKey, Priority) values (@ItemId, @UserDataKey, @Priority)"; - saveUserDataKeysCommand.Parameters.Add(saveUserDataKeysCommand, "@ItemId"); - saveUserDataKeysCommand.Parameters.Add(saveUserDataKeysCommand, "@UserDataKey"); - saveUserDataKeysCommand.Parameters.Add(saveUserDataKeysCommand, "@Priority"); + _saveUserDataKeysCommand.GetParameter(0).Value = itemId; + _saveUserDataKeysCommand.GetParameter(1).Value = key; + _saveUserDataKeysCommand.GetParameter(2).Value = index; + index++; + _saveUserDataKeysCommand.Transaction = transaction; - if (keys.Count > 1) - { - saveUserDataKeysCommand.Prepare(); - } - - foreach (var key in keys) - { - saveUserDataKeysCommand.GetParameter(0).Value = itemId; - saveUserDataKeysCommand.GetParameter(1).Value = key; - saveUserDataKeysCommand.GetParameter(2).Value = index; - index++; - saveUserDataKeysCommand.Transaction = transaction; - - saveUserDataKeysCommand.ExecuteNonQuery(); - } - } - } - } - - private void DeletePeople(IDbConnection connection, IDbTransaction transaction, Guid id) - { - using (var deletePeopleCommand = connection.CreateCommand()) - { - deletePeopleCommand.CommandText = "delete from People where ItemId=@Id"; - deletePeopleCommand.Parameters.Add(deletePeopleCommand, "@Id"); - - - deletePeopleCommand.GetParameter(0).Value = id; - deletePeopleCommand.Transaction = transaction; - - deletePeopleCommand.ExecuteNonQuery(); + _saveUserDataKeysCommand.ExecuteNonQuery(); } } @@ -3696,85 +3619,69 @@ namespace MediaBrowser.Server.Implementations.Persistence var cancellationToken = CancellationToken.None; - using (var connection = await CreateConnection().ConfigureAwait(false)) + await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); + + IDbTransaction transaction = null; + + try { - IDbTransaction transaction = null; + transaction = _connection.BeginTransaction(); - try + // First delete + _deletePeopleCommand.GetParameter(0).Value = itemId; + _deletePeopleCommand.Transaction = transaction; + + _deletePeopleCommand.ExecuteNonQuery(); + + var listIndex = 0; + + foreach (var person in people) { - transaction = connection.BeginTransaction(); + cancellationToken.ThrowIfCancellationRequested(); - // First delete - DeletePeople(connection, transaction, itemId); + _savePersonCommand.GetParameter(0).Value = itemId; + _savePersonCommand.GetParameter(1).Value = person.Name; + _savePersonCommand.GetParameter(2).Value = person.Role; + _savePersonCommand.GetParameter(3).Value = person.Type; + _savePersonCommand.GetParameter(4).Value = person.SortOrder; + _savePersonCommand.GetParameter(5).Value = listIndex; - var listIndex = 0; - - if (people.Count > 0) - { - using (var savePersonCommand = connection.CreateCommand()) - { - savePersonCommand.CommandText = "insert into People (ItemId, Name, Role, PersonType, SortOrder, ListOrder) values (@ItemId, @Name, @Role, @PersonType, @SortOrder, @ListOrder)"; - savePersonCommand.Parameters.Add(savePersonCommand, "@ItemId"); - savePersonCommand.Parameters.Add(savePersonCommand, "@Name"); - savePersonCommand.Parameters.Add(savePersonCommand, "@Role"); - savePersonCommand.Parameters.Add(savePersonCommand, "@PersonType"); - savePersonCommand.Parameters.Add(savePersonCommand, "@SortOrder"); - savePersonCommand.Parameters.Add(savePersonCommand, "@ListOrder"); - - if (people.Count > 1) - { - savePersonCommand.Prepare(); - } - - foreach (var person in people) - { - cancellationToken.ThrowIfCancellationRequested(); - - savePersonCommand.GetParameter(0).Value = itemId; - savePersonCommand.GetParameter(1).Value = person.Name; - savePersonCommand.GetParameter(2).Value = person.Role; - savePersonCommand.GetParameter(3).Value = person.Type; - savePersonCommand.GetParameter(4).Value = person.SortOrder; - savePersonCommand.GetParameter(5).Value = listIndex; - - savePersonCommand.Transaction = transaction; - - savePersonCommand.ExecuteNonQuery(); - listIndex++; - } - } - } - - transaction.Commit(); + _savePersonCommand.Transaction = transaction; + _savePersonCommand.ExecuteNonQuery(); + listIndex++; } - catch (OperationCanceledException) + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) { - if (transaction != null) - { - transaction.Rollback(); - } - - throw; + transaction.Rollback(); } - catch (Exception e) + + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save people:", e); + + if (transaction != null) { - Logger.ErrorException("Failed to save people:", e); - - if (transaction != null) - { - transaction.Rollback(); - } - - throw; + transaction.Rollback(); } - finally + + throw; + } + finally + { + if (transaction != null) { - if (transaction != null) - { - transaction.Dispose(); - } + transaction.Dispose(); } + + WriteLock.Release(); } } @@ -3814,58 +3721,39 @@ namespace MediaBrowser.Server.Implementations.Persistence var list = new List(); - using (var connection = CreateConnection(true).Result) + using (var cmd = _connection.CreateCommand()) { - using (var cmd = connection.CreateCommand()) + var cmdText = "select " + string.Join(",", _mediaStreamSaveColumns) + " from mediastreams where"; + + cmdText += " ItemId=@ItemId"; + cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = query.ItemId; + + if (query.Type.HasValue) { - var cmdText = "select " + string.Join(",", _mediaStreamSaveColumns) + " from mediastreams where"; - - cmdText += " ItemId=@ItemId"; - cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = query.ItemId; - - if (query.Type.HasValue) - { - cmdText += " AND StreamType=@StreamType"; - cmd.Parameters.Add(cmd, "@StreamType", DbType.String).Value = query.Type.Value.ToString(); - } - - if (query.Index.HasValue) - { - cmdText += " AND StreamIndex=@StreamIndex"; - cmd.Parameters.Add(cmd, "@StreamIndex", DbType.Int32).Value = query.Index.Value; - } - - cmdText += " order by StreamIndex ASC"; - - cmd.CommandText = cmdText; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) - { - while (reader.Read()) - { - list.Add(GetMediaStream(reader)); - } - } + cmdText += " AND StreamType=@StreamType"; + cmd.Parameters.Add(cmd, "@StreamType", DbType.String).Value = query.Type.Value.ToString(); } - return list; + if (query.Index.HasValue) + { + cmdText += " AND StreamIndex=@StreamIndex"; + cmd.Parameters.Add(cmd, "@StreamIndex", DbType.Int32).Value = query.Index.Value; + } + + cmdText += " order by StreamIndex ASC"; + + cmd.CommandText = cmdText; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) + { + list.Add(GetMediaStream(reader)); + } + } } - } - private void DeleteMediaStreams(IDbConnection connection, IDbTransaction transaction, Guid id) - { - using (var deleteStreamsCommand = connection.CreateCommand()) - { - // MediaStreams - deleteStreamsCommand.CommandText = "delete from mediastreams where ItemId=@ItemId"; - deleteStreamsCommand.Parameters.Add(deleteStreamsCommand, "@ItemId"); - - deleteStreamsCommand.GetParameter(0).Value = id; - - deleteStreamsCommand.Transaction = transaction; - - deleteStreamsCommand.ExecuteNonQuery(); - } + return list; } public async Task SaveMediaStreams(Guid id, List streams, CancellationToken cancellationToken) @@ -3884,115 +3772,100 @@ namespace MediaBrowser.Server.Implementations.Persistence cancellationToken.ThrowIfCancellationRequested(); - using (var connection = await CreateConnection().ConfigureAwait(false)) + await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); + + IDbTransaction transaction = null; + + try { - IDbTransaction transaction = null; + transaction = _connection.BeginTransaction(); - try + // First delete chapters + _deleteStreamsCommand.GetParameter(0).Value = id; + + _deleteStreamsCommand.Transaction = transaction; + + _deleteStreamsCommand.ExecuteNonQuery(); + + foreach (var stream in streams) { - transaction = connection.BeginTransaction(); + cancellationToken.ThrowIfCancellationRequested(); - // First delete - DeleteMediaStreams(connection, transaction, id); + var index = 0; - if (streams.Count > 0) - { - using (var saveStreamCommand = connection.CreateCommand()) - { - saveStreamCommand.CommandText = string.Format("replace into mediastreams ({0}) values ({1})", - string.Join(",", _mediaStreamSaveColumns), - string.Join(",", _mediaStreamSaveColumns.Select(i => "@" + i).ToArray())); + _saveStreamCommand.GetParameter(index++).Value = id; + _saveStreamCommand.GetParameter(index++).Value = stream.Index; + _saveStreamCommand.GetParameter(index++).Value = stream.Type.ToString(); + _saveStreamCommand.GetParameter(index++).Value = stream.Codec; + _saveStreamCommand.GetParameter(index++).Value = stream.Language; + _saveStreamCommand.GetParameter(index++).Value = stream.ChannelLayout; + _saveStreamCommand.GetParameter(index++).Value = stream.Profile; + _saveStreamCommand.GetParameter(index++).Value = stream.AspectRatio; + _saveStreamCommand.GetParameter(index++).Value = stream.Path; - foreach (var col in _mediaStreamSaveColumns) - { - saveStreamCommand.Parameters.Add(saveStreamCommand, "@" + col); - } + _saveStreamCommand.GetParameter(index++).Value = stream.IsInterlaced; - if (streams.Count > 1) - { - saveStreamCommand.Prepare(); - } + _saveStreamCommand.GetParameter(index++).Value = stream.BitRate; + _saveStreamCommand.GetParameter(index++).Value = stream.Channels; + _saveStreamCommand.GetParameter(index++).Value = stream.SampleRate; - foreach (var stream in streams) - { - cancellationToken.ThrowIfCancellationRequested(); + _saveStreamCommand.GetParameter(index++).Value = stream.IsDefault; + _saveStreamCommand.GetParameter(index++).Value = stream.IsForced; + _saveStreamCommand.GetParameter(index++).Value = stream.IsExternal; - var index = 0; + _saveStreamCommand.GetParameter(index++).Value = stream.Width; + _saveStreamCommand.GetParameter(index++).Value = stream.Height; + _saveStreamCommand.GetParameter(index++).Value = stream.AverageFrameRate; + _saveStreamCommand.GetParameter(index++).Value = stream.RealFrameRate; + _saveStreamCommand.GetParameter(index++).Value = stream.Level; + _saveStreamCommand.GetParameter(index++).Value = stream.PixelFormat; + _saveStreamCommand.GetParameter(index++).Value = stream.BitDepth; + _saveStreamCommand.GetParameter(index++).Value = stream.IsAnamorphic; + _saveStreamCommand.GetParameter(index++).Value = stream.RefFrames; - saveStreamCommand.GetParameter(index++).Value = id; - saveStreamCommand.GetParameter(index++).Value = stream.Index; - saveStreamCommand.GetParameter(index++).Value = stream.Type.ToString(); - saveStreamCommand.GetParameter(index++).Value = stream.Codec; - saveStreamCommand.GetParameter(index++).Value = stream.Language; - saveStreamCommand.GetParameter(index++).Value = stream.ChannelLayout; - saveStreamCommand.GetParameter(index++).Value = stream.Profile; - saveStreamCommand.GetParameter(index++).Value = stream.AspectRatio; - saveStreamCommand.GetParameter(index++).Value = stream.Path; + _saveStreamCommand.GetParameter(index++).Value = stream.CodecTag; + _saveStreamCommand.GetParameter(index++).Value = stream.Comment; + _saveStreamCommand.GetParameter(index++).Value = stream.NalLengthSize; + _saveStreamCommand.GetParameter(index++).Value = stream.IsAVC; + _saveStreamCommand.GetParameter(index++).Value = stream.Title; - saveStreamCommand.GetParameter(index++).Value = stream.IsInterlaced; + _saveStreamCommand.GetParameter(index++).Value = stream.TimeBase; + _saveStreamCommand.GetParameter(index++).Value = stream.CodecTimeBase; - saveStreamCommand.GetParameter(index++).Value = stream.BitRate; - saveStreamCommand.GetParameter(index++).Value = stream.Channels; - saveStreamCommand.GetParameter(index++).Value = stream.SampleRate; - - saveStreamCommand.GetParameter(index++).Value = stream.IsDefault; - saveStreamCommand.GetParameter(index++).Value = stream.IsForced; - saveStreamCommand.GetParameter(index++).Value = stream.IsExternal; - - saveStreamCommand.GetParameter(index++).Value = stream.Width; - saveStreamCommand.GetParameter(index++).Value = stream.Height; - saveStreamCommand.GetParameter(index++).Value = stream.AverageFrameRate; - saveStreamCommand.GetParameter(index++).Value = stream.RealFrameRate; - saveStreamCommand.GetParameter(index++).Value = stream.Level; - saveStreamCommand.GetParameter(index++).Value = stream.PixelFormat; - saveStreamCommand.GetParameter(index++).Value = stream.BitDepth; - saveStreamCommand.GetParameter(index++).Value = stream.IsAnamorphic; - saveStreamCommand.GetParameter(index++).Value = stream.RefFrames; - - saveStreamCommand.GetParameter(index++).Value = stream.CodecTag; - saveStreamCommand.GetParameter(index++).Value = stream.Comment; - saveStreamCommand.GetParameter(index++).Value = stream.NalLengthSize; - saveStreamCommand.GetParameter(index++).Value = stream.IsAVC; - saveStreamCommand.GetParameter(index++).Value = stream.Title; - - saveStreamCommand.GetParameter(index++).Value = stream.TimeBase; - saveStreamCommand.GetParameter(index++).Value = stream.CodecTimeBase; - - saveStreamCommand.Transaction = transaction; - saveStreamCommand.ExecuteNonQuery(); - } - } - } - - transaction.Commit(); + _saveStreamCommand.Transaction = transaction; + _saveStreamCommand.ExecuteNonQuery(); } - catch (OperationCanceledException) + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) { - if (transaction != null) - { - transaction.Rollback(); - } - - throw; + transaction.Rollback(); } - catch (Exception e) + + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save media streams:", e); + + if (transaction != null) { - Logger.ErrorException("Failed to save media streams:", e); - - if (transaction != null) - { - transaction.Rollback(); - } - - throw; + transaction.Rollback(); } - finally + + throw; + } + finally + { + if (transaction != null) { - if (transaction != null) - { - transaction.Dispose(); - } + transaction.Dispose(); } + + WriteLock.Release(); } } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs index da0f584d53..6edacba535 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs @@ -15,11 +15,18 @@ namespace MediaBrowser.Server.Implementations.Persistence { public class SqliteUserDataRepository : BaseSqliteRepository, IUserDataRepository { + private IDbConnection _connection; + public SqliteUserDataRepository(ILogManager logManager, IApplicationPaths appPaths, IDbConnector connector) : base(logManager, connector) { DbFilePath = Path.Combine(appPaths.DataPath, "userdata_v2.db"); } + protected override bool EnableConnectionPooling + { + get { return false; } + } + /// /// Gets the name of the repository /// @@ -36,23 +43,27 @@ namespace MediaBrowser.Server.Implementations.Persistence /// Opens the connection to the database /// /// Task. - public async Task Initialize(IDbConnector dbConnector) + public async Task Initialize() { - using (var connection = await CreateConnection().ConfigureAwait(false)) - { - string[] queries = { + _connection = await CreateConnection(false).ConfigureAwait(false); + + string[] queries = { "create table if not exists userdata (key nvarchar, userId GUID, rating float null, played bit, playCount int, isFavorite bit, playbackPositionTicks bigint, lastPlayedDate datetime null)", "create index if not exists idx_userdata on userdata(key)", - "create unique index if not exists userdataindex on userdata (key, userId)" + "create unique index if not exists userdataindex on userdata (key, userId)", + + //pragmas + "pragma temp_store = memory", + + "pragma shrink_memory" }; - connection.RunQueries(queries, Logger); + _connection.RunQueries(queries, Logger); - connection.AddColumn(Logger, "userdata", "AudioStreamIndex", "int"); - connection.AddColumn(Logger, "userdata", "SubtitleStreamIndex", "int"); - } + _connection.AddColumn(Logger, "userdata", "AudioStreamIndex", "int"); + _connection.AddColumn(Logger, "userdata", "SubtitleStreamIndex", "int"); } /// @@ -114,63 +125,64 @@ namespace MediaBrowser.Server.Implementations.Persistence { cancellationToken.ThrowIfCancellationRequested(); - using (var connection = await CreateConnection().ConfigureAwait(false)) + await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); + + IDbTransaction transaction = null; + + try { - IDbTransaction transaction = null; + transaction = _connection.BeginTransaction(); - try + using (var cmd = _connection.CreateCommand()) { - transaction = connection.BeginTransaction(); + cmd.CommandText = "replace into userdata (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate,@AudioStreamIndex,@SubtitleStreamIndex)"; - using (var cmd = connection.CreateCommand()) - { - cmd.CommandText = "replace into userdata (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate,@AudioStreamIndex,@SubtitleStreamIndex)"; + cmd.Parameters.Add(cmd, "@key", DbType.String).Value = key; + cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; + cmd.Parameters.Add(cmd, "@rating", DbType.Double).Value = userData.Rating; + cmd.Parameters.Add(cmd, "@played", DbType.Boolean).Value = userData.Played; + cmd.Parameters.Add(cmd, "@playCount", DbType.Int32).Value = userData.PlayCount; + cmd.Parameters.Add(cmd, "@isFavorite", DbType.Boolean).Value = userData.IsFavorite; + cmd.Parameters.Add(cmd, "@playbackPositionTicks", DbType.Int64).Value = userData.PlaybackPositionTicks; + cmd.Parameters.Add(cmd, "@lastPlayedDate", DbType.DateTime).Value = userData.LastPlayedDate; + cmd.Parameters.Add(cmd, "@AudioStreamIndex", DbType.Int32).Value = userData.AudioStreamIndex; + cmd.Parameters.Add(cmd, "@SubtitleStreamIndex", DbType.Int32).Value = userData.SubtitleStreamIndex; - cmd.Parameters.Add(cmd, "@key", DbType.String).Value = key; - cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; - cmd.Parameters.Add(cmd, "@rating", DbType.Double).Value = userData.Rating; - cmd.Parameters.Add(cmd, "@played", DbType.Boolean).Value = userData.Played; - cmd.Parameters.Add(cmd, "@playCount", DbType.Int32).Value = userData.PlayCount; - cmd.Parameters.Add(cmd, "@isFavorite", DbType.Boolean).Value = userData.IsFavorite; - cmd.Parameters.Add(cmd, "@playbackPositionTicks", DbType.Int64).Value = userData.PlaybackPositionTicks; - cmd.Parameters.Add(cmd, "@lastPlayedDate", DbType.DateTime).Value = userData.LastPlayedDate; - cmd.Parameters.Add(cmd, "@AudioStreamIndex", DbType.Int32).Value = userData.AudioStreamIndex; - cmd.Parameters.Add(cmd, "@SubtitleStreamIndex", DbType.Int32).Value = userData.SubtitleStreamIndex; + cmd.Transaction = transaction; - cmd.Transaction = transaction; - - cmd.ExecuteNonQuery(); - } - - transaction.Commit(); + cmd.ExecuteNonQuery(); } - catch (OperationCanceledException) + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) { - if (transaction != null) - { - transaction.Rollback(); - } - - throw; + transaction.Rollback(); } - catch (Exception e) + + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save user data:", e); + + if (transaction != null) { - Logger.ErrorException("Failed to save user data:", e); - - if (transaction != null) - { - transaction.Rollback(); - } - - throw; + transaction.Rollback(); } - finally + + throw; + } + finally + { + if (transaction != null) { - if (transaction != null) - { - transaction.Dispose(); - } + transaction.Dispose(); } + + WriteLock.Release(); } } @@ -185,68 +197,69 @@ namespace MediaBrowser.Server.Implementations.Persistence { cancellationToken.ThrowIfCancellationRequested(); - using (var connection = await CreateConnection().ConfigureAwait(false)) + await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); + + IDbTransaction transaction = null; + + try { - IDbTransaction transaction = null; + transaction = _connection.BeginTransaction(); - try + foreach (var userItemData in userData) { - transaction = connection.BeginTransaction(); - - foreach (var userItemData in userData) + using (var cmd = _connection.CreateCommand()) { - using (var cmd = connection.CreateCommand()) - { - cmd.CommandText = "replace into userdata (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate,@AudioStreamIndex,@SubtitleStreamIndex)"; + cmd.CommandText = "replace into userdata (key, userId, rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex) values (@key, @userId, @rating,@played,@playCount,@isFavorite,@playbackPositionTicks,@lastPlayedDate,@AudioStreamIndex,@SubtitleStreamIndex)"; - cmd.Parameters.Add(cmd, "@key", DbType.String).Value = userItemData.Key; - cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; - cmd.Parameters.Add(cmd, "@rating", DbType.Double).Value = userItemData.Rating; - cmd.Parameters.Add(cmd, "@played", DbType.Boolean).Value = userItemData.Played; - cmd.Parameters.Add(cmd, "@playCount", DbType.Int32).Value = userItemData.PlayCount; - cmd.Parameters.Add(cmd, "@isFavorite", DbType.Boolean).Value = userItemData.IsFavorite; - cmd.Parameters.Add(cmd, "@playbackPositionTicks", DbType.Int64).Value = userItemData.PlaybackPositionTicks; - cmd.Parameters.Add(cmd, "@lastPlayedDate", DbType.DateTime).Value = userItemData.LastPlayedDate; - cmd.Parameters.Add(cmd, "@AudioStreamIndex", DbType.Int32).Value = userItemData.AudioStreamIndex; - cmd.Parameters.Add(cmd, "@SubtitleStreamIndex", DbType.Int32).Value = userItemData.SubtitleStreamIndex; + cmd.Parameters.Add(cmd, "@key", DbType.String).Value = userItemData.Key; + cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; + cmd.Parameters.Add(cmd, "@rating", DbType.Double).Value = userItemData.Rating; + cmd.Parameters.Add(cmd, "@played", DbType.Boolean).Value = userItemData.Played; + cmd.Parameters.Add(cmd, "@playCount", DbType.Int32).Value = userItemData.PlayCount; + cmd.Parameters.Add(cmd, "@isFavorite", DbType.Boolean).Value = userItemData.IsFavorite; + cmd.Parameters.Add(cmd, "@playbackPositionTicks", DbType.Int64).Value = userItemData.PlaybackPositionTicks; + cmd.Parameters.Add(cmd, "@lastPlayedDate", DbType.DateTime).Value = userItemData.LastPlayedDate; + cmd.Parameters.Add(cmd, "@AudioStreamIndex", DbType.Int32).Value = userItemData.AudioStreamIndex; + cmd.Parameters.Add(cmd, "@SubtitleStreamIndex", DbType.Int32).Value = userItemData.SubtitleStreamIndex; - cmd.Transaction = transaction; + cmd.Transaction = transaction; - cmd.ExecuteNonQuery(); - } - - cancellationToken.ThrowIfCancellationRequested(); + cmd.ExecuteNonQuery(); } - transaction.Commit(); + cancellationToken.ThrowIfCancellationRequested(); } - catch (OperationCanceledException) - { - if (transaction != null) - { - transaction.Rollback(); - } - throw; - } - catch (Exception e) + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) { - Logger.ErrorException("Failed to save user data:", e); - - if (transaction != null) - { - transaction.Rollback(); - } - - throw; + transaction.Rollback(); } - finally + + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save user data:", e); + + if (transaction != null) { - if (transaction != null) - { - transaction.Dispose(); - } + transaction.Rollback(); } + + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + + WriteLock.Release(); } } @@ -272,25 +285,22 @@ namespace MediaBrowser.Server.Implementations.Persistence throw new ArgumentNullException("key"); } - using (var connection = CreateConnection(true).Result) + using (var cmd = _connection.CreateCommand()) { - using (var cmd = connection.CreateCommand()) + cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where key = @key and userId=@userId"; + + cmd.Parameters.Add(cmd, "@key", DbType.String).Value = key; + cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) { - cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where key = @key and userId=@userId"; - - cmd.Parameters.Add(cmd, "@key", DbType.String).Value = key; - cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) + if (reader.Read()) { - if (reader.Read()) - { - return ReadRow(reader); - } + return ReadRow(reader); } - - return null; } + + return null; } } @@ -305,41 +315,38 @@ namespace MediaBrowser.Server.Implementations.Persistence throw new ArgumentNullException("keys"); } - using (var connection = CreateConnection(true).Result) + using (var cmd = _connection.CreateCommand()) { - using (var cmd = connection.CreateCommand()) + var index = 0; + var excludeIds = new List(); + var builder = new StringBuilder(); + foreach (var key in keys) { - var index = 0; - var excludeIds = new List(); - var builder = new StringBuilder(); - foreach (var key in keys) - { - var paramName = "@Key" + index; - excludeIds.Add("Key =" + paramName); - cmd.Parameters.Add(cmd, paramName, DbType.String).Value = key; - builder.Append(" WHEN Key=" + paramName + " THEN " + index); - index++; - } - - var keyText = string.Join(" OR ", excludeIds.ToArray()); - - cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where userId=@userId AND (" + keyText + ") "; - - cmd.CommandText += " ORDER BY (Case " + builder + " Else " + keys.Count.ToString(CultureInfo.InvariantCulture) + " End )"; - cmd.CommandText += " LIMIT 1"; - - cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) - { - if (reader.Read()) - { - return ReadRow(reader); - } - } - - return null; + var paramName = "@Key" + index; + excludeIds.Add("Key =" + paramName); + cmd.Parameters.Add(cmd, paramName, DbType.String).Value = key; + builder.Append(" WHEN Key=" + paramName + " THEN " + index); + index++; } + + var keyText = string.Join(" OR ", excludeIds.ToArray()); + + cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where userId=@userId AND (" + keyText + ") "; + + cmd.CommandText += " ORDER BY (Case " + builder + " Else " + keys.Count.ToString(CultureInfo.InvariantCulture) + " End )"; + cmd.CommandText += " LIMIT 1"; + + cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) + { + if (reader.Read()) + { + return ReadRow(reader); + } + } + + return null; } } @@ -355,27 +362,20 @@ namespace MediaBrowser.Server.Implementations.Persistence throw new ArgumentNullException("userId"); } - var list = new List(); - - using (var connection = CreateConnection(true).Result) + using (var cmd = _connection.CreateCommand()) { - using (var cmd = connection.CreateCommand()) + cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where userId=@userId"; + + cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) { - cmd.CommandText = "select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where userId=@userId"; - - cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + while (reader.Read()) { - while (reader.Read()) - { - list.Add(ReadRow(reader)); - } + yield return ReadRow(reader); } } } - - return list; } /// @@ -416,5 +416,19 @@ namespace MediaBrowser.Server.Implementations.Persistence return userData; } + + protected override void CloseConnection() + { + if (_connection != null) + { + if (_connection.IsOpen()) + { + _connection.Close(); + } + + _connection.Dispose(); + _connection = null; + } + } } } \ No newline at end of file diff --git a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs index b0cf93673c..e7f5c071c7 100644 --- a/MediaBrowser.Server.Startup.Common/ApplicationHost.cs +++ b/MediaBrowser.Server.Startup.Common/ApplicationHost.cs @@ -573,7 +573,7 @@ namespace MediaBrowser.Server.Startup.Common await displayPreferencesRepo.Initialize().ConfigureAwait(false); await ConfigureUserDataRepositories().ConfigureAwait(false); - await itemRepo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false); + await itemRepo.Initialize().ConfigureAwait(false); ((LibraryManager)LibraryManager).ItemRepository = ItemRepository; await ConfigureNotificationsRepository().ConfigureAwait(false); progress.Report(100); @@ -746,7 +746,7 @@ namespace MediaBrowser.Server.Startup.Common { var repo = new SqliteUserDataRepository(LogManager, ApplicationPaths, NativeApp.GetDbConnector()); - await repo.Initialize(NativeApp.GetDbConnector()).ConfigureAwait(false); + await repo.Initialize().ConfigureAwait(false); ((UserDataManager)UserDataManager).Repository = repo; }