From e1f562e16ff585b440a43029efe9db314b4de965 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 1 Jun 2016 01:50:00 -0400 Subject: calculate similarity at database level --- .../Persistence/SqliteExtensions.cs | 175 +++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs (limited to 'MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs') diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs new file mode 100644 index 0000000000..5e07bac310 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SQLite; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using MediaBrowser.Model.Logging; + +namespace MediaBrowser.Server.Implementations.Persistence +{ + /// + /// Class SQLiteExtensions + /// + public static class SqliteExtensions + { + /// + /// Connects to db. + /// + /// The db path. + /// The logger. + /// Task{IDbConnection}. + /// dbPath + public static async Task ConnectToDb(string dbPath, ILogger logger) + { + if (string.IsNullOrEmpty(dbPath)) + { + throw new ArgumentNullException("dbPath"); + } + + logger.Info("Sqlite {0} opening {1}", SQLiteConnection.SQLiteVersion, dbPath); + + var connectionstr = new SQLiteConnectionStringBuilder + { + PageSize = 4096, + CacheSize = 2000, + SyncMode = SynchronizationModes.Normal, + DataSource = dbPath, + JournalMode = SQLiteJournalModeEnum.Wal + }; + + var connection = new SQLiteConnection(connectionstr.ConnectionString); + + await connection.OpenAsync().ConfigureAwait(false); + + return connection; + } + + public static void BindGetSimilarityScore(IDbConnection connection, ILogger logger) + { + var sqlConnection = (SQLiteConnection) connection; + SimiliarToFunction.Logger = logger; + sqlConnection.BindFunction(new SimiliarToFunction()); + } + + public static void BindFunction(this SQLiteConnection connection, SQLiteFunction function) + { + var attributes = function.GetType().GetCustomAttributes(typeof(SQLiteFunctionAttribute), true).Cast().ToArray(); + if (attributes.Length == 0) + { + throw new InvalidOperationException("SQLiteFunction doesn't have SQLiteFunctionAttribute"); + } + connection.BindFunction(attributes[0], function); + } + } + + [SQLiteFunction(Name = "GetSimilarityScore", Arguments = 12, FuncType = FunctionType.Scalar)] + public class SimiliarToFunction : SQLiteFunction + { + internal static ILogger Logger; + + public override object Invoke(object[] args) + { + var score = 0; + + var inputOfficialRating = args[0] as string; + var rowOfficialRating = args[1] as string; + if (!string.IsNullOrWhiteSpace(inputOfficialRating) && string.Equals(inputOfficialRating, rowOfficialRating)) + { + score += 10; + } + + long? inputYear = args[2] == null ? (long?)null : (long)args[2]; + long? rowYear = args[3] == null ? (long?)null : (long)args[3]; + + if (inputYear.HasValue && rowYear.HasValue) + { + var diff = Math.Abs(inputYear.Value - rowYear.Value); + + // Add if they came out within the same decade + if (diff < 10) + { + score += 2; + } + + // And more if within five years + if (diff < 5) + { + score += 2; + } + } + + // genres + score += GetListScore(args, 4, 5); + + // tags + score += GetListScore(args, 6, 7); + + // keywords + score += GetListScore(args, 8, 9); + + // studios + score += GetListScore(args, 10, 11, 3); + + + // TODO: People + // var item2PeopleNames = allPeople.Where(i => i.ItemId == item2.Id) + //.Select(i => i.Name) + //.Where(i => !string.IsNullOrWhiteSpace(i)) + //.DistinctNames() + //.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); + + // points += item1People.Where(i => item2PeopleNames.ContainsKey(i.Name)).Sum(i => + // { + // if (string.Equals(i.Type, PersonType.Director, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Director, StringComparison.OrdinalIgnoreCase)) + // { + // return 5; + // } + // if (string.Equals(i.Type, PersonType.Actor, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Actor, StringComparison.OrdinalIgnoreCase)) + // { + // return 3; + // } + // if (string.Equals(i.Type, PersonType.Composer, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Composer, StringComparison.OrdinalIgnoreCase)) + // { + // return 3; + // } + // if (string.Equals(i.Type, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase)) + // { + // return 3; + // } + // if (string.Equals(i.Type, PersonType.Writer, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Writer, StringComparison.OrdinalIgnoreCase)) + // { + // return 2; + // } + + // return 1; + // }); + + // return points; + + //Logger.Debug("Returning score {0}", score); + return score; + } + + private int GetListScore(object[] args, int index1, int index2, int value = 10) + { + var score = 0; + + var inputGenres = args[index1] as string; + var rowGenres = args[index2] as string; + var inputGenreList = string.IsNullOrWhiteSpace(inputGenres) ? new string[] { } : inputGenres.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); + var rowGenresList = string.IsNullOrWhiteSpace(rowGenres) ? new string[] { } : rowGenres.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); + + foreach (var genre in inputGenreList) + { + if (rowGenresList.Contains(genre, StringComparer.OrdinalIgnoreCase)) + { + score += value; + } + } + + return score; + } + } +} -- cgit v1.2.3 From 05acd63f8f0019e46ea57ab895bf54372c14161b Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 2 Jun 2016 15:32:15 -0400 Subject: add people to similar queries --- .../Persistence/SqliteExtensions.cs | 59 +++++++++------------- .../Persistence/SqliteItemRepository.cs | 6 ++- 2 files changed, 28 insertions(+), 37 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs') diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs index 5e07bac310..b819fb9790 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs @@ -5,6 +5,8 @@ using System.Data.SQLite; using System.Linq; using System.Text; using System.Threading.Tasks; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; namespace MediaBrowser.Server.Implementations.Persistence @@ -48,7 +50,7 @@ namespace MediaBrowser.Server.Implementations.Persistence public static void BindGetSimilarityScore(IDbConnection connection, ILogger logger) { - var sqlConnection = (SQLiteConnection) connection; + var sqlConnection = (SQLiteConnection)connection; SimiliarToFunction.Logger = logger; sqlConnection.BindFunction(new SimiliarToFunction()); } @@ -64,11 +66,23 @@ namespace MediaBrowser.Server.Implementations.Persistence } } - [SQLiteFunction(Name = "GetSimilarityScore", Arguments = 12, FuncType = FunctionType.Scalar)] + [SQLiteFunction(Name = "GetSimilarityScore", Arguments = 13, FuncType = FunctionType.Scalar)] public class SimiliarToFunction : SQLiteFunction { internal static ILogger Logger; + private readonly Dictionary _personTypeScores = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + { PersonType.Actor, 3}, + { PersonType.Director, 5}, + { PersonType.Composer, 2}, + { PersonType.GuestStar, 3}, + { PersonType.Writer, 2}, + { PersonType.Conductor, 2}, + { PersonType.Producer, 2}, + { PersonType.Lyricist, 2} + }; + public override object Invoke(object[] args) { var score = 0; @@ -112,41 +126,14 @@ namespace MediaBrowser.Server.Implementations.Persistence // studios score += GetListScore(args, 10, 11, 3); + var rowPeopleNamesText = (args[12] as string) ?? string.Empty; + var rowPeopleNames = rowPeopleNamesText.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); - // TODO: People - // var item2PeopleNames = allPeople.Where(i => i.ItemId == item2.Id) - //.Select(i => i.Name) - //.Where(i => !string.IsNullOrWhiteSpace(i)) - //.DistinctNames() - //.ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); - - // points += item1People.Where(i => item2PeopleNames.ContainsKey(i.Name)).Sum(i => - // { - // if (string.Equals(i.Type, PersonType.Director, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Director, StringComparison.OrdinalIgnoreCase)) - // { - // return 5; - // } - // if (string.Equals(i.Type, PersonType.Actor, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Actor, StringComparison.OrdinalIgnoreCase)) - // { - // return 3; - // } - // if (string.Equals(i.Type, PersonType.Composer, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Composer, StringComparison.OrdinalIgnoreCase)) - // { - // return 3; - // } - // if (string.Equals(i.Type, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.GuestStar, StringComparison.OrdinalIgnoreCase)) - // { - // return 3; - // } - // if (string.Equals(i.Type, PersonType.Writer, StringComparison.OrdinalIgnoreCase) || string.Equals(i.Role, PersonType.Writer, StringComparison.OrdinalIgnoreCase)) - // { - // return 2; - // } - - // return 1; - // }); - - // return points; + foreach (var name in rowPeopleNames) + { + // TODO: Send along person types + score += 3; + } //Logger.Debug("Returning score {0}", score); return score; diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 494e1b12f3..bf50f9a0e4 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -1638,7 +1638,10 @@ namespace MediaBrowser.Server.Implementations.Persistence builder.Append("(select group_concat((Select Value from ItemValues where ItemId=Guid and Type=5), '|')),"); builder.Append("@ItemStudios,"); - builder.Append("Studios"); + builder.Append("Studios,"); + + builder.Append("(select group_concat((Select Name from People where ItemId=Guid and Name in (Select Name from People where ItemId=@SimilarItemId)), '|'))"); + builder.Append(") as SimilarityScore"); list.Add(builder.ToString()); @@ -1648,6 +1651,7 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.Parameters.Add(cmd, "@ItemTags", DbType.String).Value = string.Join("|", item.Tags.ToArray()); cmd.Parameters.Add(cmd, "@ItemKeywords", DbType.String).Value = string.Join("|", item.Keywords.ToArray()); cmd.Parameters.Add(cmd, "@ItemStudios", DbType.String).Value = string.Join("|", item.Studios.ToArray()); + cmd.Parameters.Add(cmd, "@SimilarItemId", DbType.Guid).Value = item.Id; var excludeIds = query.ExcludeItemIds.ToList(); excludeIds.Add(item.Id.ToString("N")); -- cgit v1.2.3 From 53afb1e1e54a383f9fdda9b9c5fb21a6af50962e Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 3 Jun 2016 12:24:04 -0400 Subject: add images table --- MediaBrowser.Api/StartupWizardService.cs | 2 +- MediaBrowser.Controller/Entities/Folder.cs | 6 - .../Configuration/UserConfiguration.cs | 3 +- MediaBrowser.Model/Entities/ImageType.cs | 24 ++-- .../FileOrganization/EpisodeFileOrganizer.cs | 7 +- .../Persistence/SqliteExtensions.cs | 43 +++---- .../Persistence/SqliteItemRepository.cs | 132 +++++++++++++++++---- 7 files changed, 150 insertions(+), 67 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs') diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs index 8bb840697e..0a8d39ee5c 100644 --- a/MediaBrowser.Api/StartupWizardService.cs +++ b/MediaBrowser.Api/StartupWizardService.cs @@ -113,7 +113,7 @@ namespace MediaBrowser.Api config.EnableCustomPathSubFolders = true; config.EnableStandaloneMusicKeys = true; config.EnableCaseSensitiveItemIds = true; - config.SchemaVersion = 79; + config.SchemaVersion = 87; } public void Post(UpdateStartupConfiguration request) diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index ba94c99d2a..2cec15d511 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -889,12 +889,6 @@ namespace MediaBrowser.Controller.Entities return true; } - if (query.ImageTypes.Length > 0) - { - Logger.Debug("Query requires post-filtering due to ImageTypes"); - return true; - } - // Apply studio filter if (query.StudioIds.Length > 0) { diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs index 6195e3e70f..69dc23b21c 100644 --- a/MediaBrowser.Model/Configuration/UserConfiguration.cs +++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs @@ -48,7 +48,8 @@ namespace MediaBrowser.Model.Configuration public bool RememberAudioSelections { get; set; } public bool RememberSubtitleSelections { get; set; } public bool EnableNextEpisodeAutoPlay { get; set; } - + public bool DisplayFoldersView { get; set; } + /// /// Initializes a new instance of the class. /// diff --git a/MediaBrowser.Model/Entities/ImageType.cs b/MediaBrowser.Model/Entities/ImageType.cs index 18097abb44..6e0ba717f0 100644 --- a/MediaBrowser.Model/Entities/ImageType.cs +++ b/MediaBrowser.Model/Entities/ImageType.cs @@ -9,50 +9,50 @@ namespace MediaBrowser.Model.Entities /// /// The primary /// - Primary, + Primary = 0, /// /// The art /// - Art, + Art = 1, /// /// The backdrop /// - Backdrop, + Backdrop = 2, /// /// The banner /// - Banner, + Banner = 3, /// /// The logo /// - Logo, + Logo = 4, /// /// The thumb /// - Thumb, + Thumb = 5, /// /// The disc /// - Disc, + Disc = 6, /// /// The box /// - Box, + Box = 7, /// /// The screenshot /// - Screenshot, + Screenshot = 8, /// /// The menu /// - Menu, + Menu = 9, /// /// The chapter image /// - Chapter, + Chapter = 10, /// /// The box rear /// - BoxRear + BoxRear = 11 } } diff --git a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs index 83801b3e76..2109f8d59e 100644 --- a/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs +++ b/MediaBrowser.Server.Implementations/FileOrganization/EpisodeFileOrganizer.cs @@ -562,9 +562,10 @@ namespace MediaBrowser.Server.Implementations.FileOrganization series = _libraryManager.GetItemList(new Controller.Entities.InternalItemsQuery { IncludeItemTypes = new[] { typeof(Series).Name }, - Recursive = true - }).Cast() - .FirstOrDefault(i => string.Equals(i.Name, info.ItemName, StringComparison.OrdinalIgnoreCase)); + Recursive = true, + Name = info.ItemName + + }).Cast().FirstOrDefault(); } } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs index b819fb9790..519731a5cc 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs @@ -66,7 +66,7 @@ namespace MediaBrowser.Server.Implementations.Persistence } } - [SQLiteFunction(Name = "GetSimilarityScore", Arguments = 13, FuncType = FunctionType.Scalar)] + [SQLiteFunction(Name = "GetSimilarityScore", Arguments = 6, FuncType = FunctionType.Scalar)] public class SimiliarToFunction : SQLiteFunction { internal static ILogger Logger; @@ -87,19 +87,17 @@ namespace MediaBrowser.Server.Implementations.Persistence { var score = 0; - var inputOfficialRating = args[0] as string; - var rowOfficialRating = args[1] as string; - if (!string.IsNullOrWhiteSpace(inputOfficialRating) && string.Equals(inputOfficialRating, rowOfficialRating)) + // Official rating equals + if ((long)args[0] == 1) { score += 10; } - long? inputYear = args[2] == null ? (long?)null : (long)args[2]; - long? rowYear = args[3] == null ? (long?)null : (long)args[3]; - - if (inputYear.HasValue && rowYear.HasValue) + // Year difference + long? yearDifference = args[1] == null ? (long?)null : (long)args[1]; + if (yearDifference.HasValue) { - var diff = Math.Abs(inputYear.Value - rowYear.Value); + var diff = Math.Abs(yearDifference.Value); // Add if they came out within the same decade if (diff < 10) @@ -115,25 +113,28 @@ namespace MediaBrowser.Server.Implementations.Persistence } // genres - score += GetListScore(args, 4, 5); + score += Convert.ToInt32((long)args[2]) * 10; // tags - score += GetListScore(args, 6, 7); + score += Convert.ToInt32((long)args[3]) * 10; + + // # of common keywords + score += Convert.ToInt32((long)args[4]) *10; - // keywords - score += GetListScore(args, 8, 9); + // # of common studios + score += Convert.ToInt32((long)args[5]) * 3; // studios - score += GetListScore(args, 10, 11, 3); + //score += GetListScore(args, 7, 8, 3); - var rowPeopleNamesText = (args[12] as string) ?? string.Empty; - var rowPeopleNames = rowPeopleNamesText.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); + //var rowPeopleNamesText = (args[12] as string) ?? string.Empty; + //var rowPeopleNames = rowPeopleNamesText.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); - foreach (var name in rowPeopleNames) - { - // TODO: Send along person types - score += 3; - } + //foreach (var name in rowPeopleNames) + //{ + // // TODO: Send along person types + // score += 3; + //} //Logger.Debug("Returning score {0}", score); return score; diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index bf50f9a0e4..9f827c553a 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -88,10 +88,13 @@ namespace MediaBrowser.Server.Implementations.Persistence private IDbCommand _deleteProviderIdsCommand; private IDbCommand _saveProviderIdsCommand; + private IDbCommand _deleteImagesCommand; + private IDbCommand _saveImagesCommand; + private IDbCommand _updateInheritedRatingCommand; private IDbCommand _updateInheritedTagsCommand; - public const int LatestSchemaVersion = 84; + public const int LatestSchemaVersion = 87; /// /// Initializes a new instance of the class. @@ -144,10 +147,14 @@ namespace MediaBrowser.Server.Implementations.Persistence "create table if not exists ItemValues (ItemId GUID, Type INT, Value TEXT)", "create index if not exists idx_ItemValues on ItemValues(ItemId)", + "create index if not exists idx_ItemValues2 on ItemValues(ItemId,Type)", "create table if not exists ProviderIds (ItemId GUID, Name TEXT, Value TEXT, PRIMARY KEY (ItemId, Name))", "create index if not exists Idx_ProviderIds on ProviderIds(ItemId)", + "create table if not exists Images (ItemId GUID NOT NULL, Path TEXT NOT NULL, ImageType INT NOT NULL, DateModified DATETIME, IsPlaceHolder BIT NOT NULL, SortOrder INT)", + "create index if not exists idx_Images on Images(ItemId)", + "create table if not exists People (ItemId GUID, Name TEXT NOT NULL, Role TEXT, PersonType TEXT, SortOrder int, ListOrder int)", "create index if not exists idxPeopleItemId on People(ItemId)", "create index if not exists idxPeopleName on People(Name)", @@ -564,6 +571,19 @@ namespace MediaBrowser.Server.Implementations.Persistence _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"); } /// @@ -878,6 +898,7 @@ namespace MediaBrowser.Server.Implementations.Persistence } 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); } @@ -1620,37 +1641,33 @@ namespace MediaBrowser.Server.Implementations.Persistence var item = query.SimilarTo; var builder = new StringBuilder(); - builder.Append("GetSimilarityScore("); + builder.Append("("); + + builder.Append("((OfficialRating=@ItemOfficialRating) * 10)"); + //builder.Append("+ ((ProductionYear=@ItemProductionYear) * 10)"); - builder.Append("@ItemOfficialRating,"); - builder.Append("OfficialRating,"); + builder.Append("+(Select Case When Abs(COALESCE(ProductionYear, 0) - @ItemProductionYear) < 10 Then 2 Else 0 End )"); + builder.Append("+(Select Case When Abs(COALESCE(ProductionYear, 0) - @ItemProductionYear) < 5 Then 2 Else 0 End )"); - builder.Append("@ItemProductionYear,"); - builder.Append("ProductionYear,"); + //// genres + builder.Append("+ ((Select count(value) from ItemValues where ItemId=Guid and Type=2 and value in (select value from itemvalues where ItemId=@SimilarItemId and type=2)) * 10)"); - builder.Append("@ItemGenres,"); - builder.Append("Genres,"); + //// tags + builder.Append("+ ((Select count(value) from ItemValues where ItemId=Guid and Type=4 and value in (select value from itemvalues where ItemId=@SimilarItemId and type=4)) * 10)"); - builder.Append("@ItemTags,"); - builder.Append("Tags,"); + builder.Append("+ ((Select count(value) from ItemValues where ItemId=Guid and Type=5 and value in (select value from itemvalues where ItemId=@SimilarItemId and type=5)) * 10)"); - builder.Append("@ItemKeywords,"); - builder.Append("(select group_concat((Select Value from ItemValues where ItemId=Guid and Type=5), '|')),"); + builder.Append("+ ((Select count(value) from ItemValues where ItemId=Guid and Type=3 and value in (select value from itemvalues where ItemId=@SimilarItemId and type=3)) * 3)"); - builder.Append("@ItemStudios,"); - builder.Append("Studios,"); + //builder.Append("+ ((Select count(Name) from People where ItemId=Guid and Name in (select Name from People where ItemId=@SimilarItemId)) * 3)"); - builder.Append("(select group_concat((Select Name from People where ItemId=Guid and Name in (Select Name from People where ItemId=@SimilarItemId)), '|'))"); + ////builder.Append("(select group_concat((Select Name from People where ItemId=Guid and Name in (Select Name from People where ItemId=@SimilarItemId)), '|'))"); builder.Append(") as SimilarityScore"); list.Add(builder.ToString()); cmd.Parameters.Add(cmd, "@ItemOfficialRating", DbType.String).Value = item.OfficialRating; - cmd.Parameters.Add(cmd, "@ItemProductionYear", DbType.Int32).Value = item.ProductionYear ?? -1; - cmd.Parameters.Add(cmd, "@ItemGenres", DbType.String).Value = string.Join("|", item.Genres.ToArray()); - cmd.Parameters.Add(cmd, "@ItemTags", DbType.String).Value = string.Join("|", item.Tags.ToArray()); - cmd.Parameters.Add(cmd, "@ItemKeywords", DbType.String).Value = string.Join("|", item.Keywords.ToArray()); - cmd.Parameters.Add(cmd, "@ItemStudios", DbType.String).Value = string.Join("|", item.Studios.ToArray()); + cmd.Parameters.Add(cmd, "@ItemProductionYear", DbType.Int32).Value = item.ProductionYear ?? 0; cmd.Parameters.Add(cmd, "@SimilarItemId", DbType.Guid).Value = item.Id; var excludeIds = query.ExcludeItemIds.ToList(); @@ -1865,7 +1882,7 @@ namespace MediaBrowser.Server.Implementations.Persistence { if (query.User != null) { - query.SortBy = new[] { "SimilarityScore", "IsUnplayed", "Random" }; + query.SortBy = new[] { "SimilarityScore", "IsPlayed", "Random" }; } else { @@ -2478,6 +2495,19 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.Parameters.Add(cmd, "@NameLessThan", DbType.String).Value = query.NameLessThan.ToLower(); } + if (query.ImageTypes.Length > 0 && _config.Configuration.SchemaVersion >= 87) + { + var requiredImageIndex = 0; + + foreach (var requiredImage in query.ImageTypes) + { + var paramName = "@RequiredImageType" + requiredImageIndex; + whereClauses.Add("(select path from images where ItemId=Guid and ImageType=" + paramName + " limit 1) not null"); + cmd.Parameters.Add(cmd, paramName, DbType.Int32).Value = (int)requiredImage; + requiredImageIndex++; + } + } + if (query.IsLiked.HasValue) { if (query.IsLiked.Value) @@ -2741,8 +2771,13 @@ namespace MediaBrowser.Server.Implementations.Persistence var index = 0; foreach (var pair in query.ExcludeProviderIds) { + if (string.Equals(pair.Key, MetadataProviders.TmdbCollection.ToString(), StringComparison.OrdinalIgnoreCase)) + { + continue; + } + var paramName = "@ExcludeProviderId" + index; - excludeIds.Add("(COALESCE((select value from ProviderIds where ItemId=Guid and Name = 'Imdb'), '') <> " + paramName + ")"); + excludeIds.Add("(COALESCE((select value from ProviderIds where ItemId=Guid and Name = '" + pair.Key + "'), '') <> " + paramName + ")"); cmd.Parameters.Add(cmd, paramName, DbType.String).Value = pair.Value; index++; } @@ -3183,6 +3218,11 @@ namespace MediaBrowser.Server.Implementations.Persistence _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; @@ -3399,6 +3439,52 @@ namespace MediaBrowser.Server.Implementations.Persistence return list; } + private void UpdateImages(Guid itemId, List images, IDbTransaction transaction) + { + if (itemId == Guid.Empty) + { + throw new ArgumentNullException("itemId"); + } + + if (images == null) + { + throw new ArgumentNullException("images"); + } + + CheckDisposed(); + + // First delete + _deleteImagesCommand.GetParameter(0).Value = itemId; + _deleteImagesCommand.Transaction = transaction; + + _deleteImagesCommand.ExecuteNonQuery(); + + var index = 0; + 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++; + } + } + private void UpdateProviderIds(Guid itemId, Dictionary values, IDbTransaction transaction) { if (itemId == Guid.Empty) @@ -3408,7 +3494,7 @@ namespace MediaBrowser.Server.Implementations.Persistence if (values == null) { - throw new ArgumentNullException("keys"); + throw new ArgumentNullException("values"); } CheckDisposed(); -- cgit v1.2.3 From 1edd61bf38f26665f0d0381788d12e180230c4f3 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 4 Jun 2016 13:14:03 -0400 Subject: update tabs --- .../Music/MusicBrainzAlbumProvider.cs | 2 +- .../Persistence/SqliteExtensions.cs | 102 --------------------- .../Migrations/FolderViewSettingMigration.cs | 5 +- 3 files changed, 5 insertions(+), 104 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs') diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs index d76c89dfb8..6e57b4022a 100644 --- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs +++ b/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs @@ -25,7 +25,7 @@ namespace MediaBrowser.Providers.Music private readonly IApplicationHost _appHost; private readonly ILogger _logger; - public static string MusicBrainzBaseUrl = "http://musicbrainz.fercasas.com:5000"; + public static string MusicBrainzBaseUrl = "https://www.musicbrainz.org"; public MusicBrainzAlbumProvider(IHttpClient httpClient, IApplicationHost appHost, ILogger logger) { diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs index 519731a5cc..dd2f15cfd7 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs @@ -48,13 +48,6 @@ namespace MediaBrowser.Server.Implementations.Persistence return connection; } - public static void BindGetSimilarityScore(IDbConnection connection, ILogger logger) - { - var sqlConnection = (SQLiteConnection)connection; - SimiliarToFunction.Logger = logger; - sqlConnection.BindFunction(new SimiliarToFunction()); - } - public static void BindFunction(this SQLiteConnection connection, SQLiteFunction function) { var attributes = function.GetType().GetCustomAttributes(typeof(SQLiteFunctionAttribute), true).Cast().ToArray(); @@ -65,99 +58,4 @@ namespace MediaBrowser.Server.Implementations.Persistence connection.BindFunction(attributes[0], function); } } - - [SQLiteFunction(Name = "GetSimilarityScore", Arguments = 6, FuncType = FunctionType.Scalar)] - public class SimiliarToFunction : SQLiteFunction - { - internal static ILogger Logger; - - private readonly Dictionary _personTypeScores = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { PersonType.Actor, 3}, - { PersonType.Director, 5}, - { PersonType.Composer, 2}, - { PersonType.GuestStar, 3}, - { PersonType.Writer, 2}, - { PersonType.Conductor, 2}, - { PersonType.Producer, 2}, - { PersonType.Lyricist, 2} - }; - - public override object Invoke(object[] args) - { - var score = 0; - - // Official rating equals - if ((long)args[0] == 1) - { - score += 10; - } - - // Year difference - long? yearDifference = args[1] == null ? (long?)null : (long)args[1]; - if (yearDifference.HasValue) - { - var diff = Math.Abs(yearDifference.Value); - - // Add if they came out within the same decade - if (diff < 10) - { - score += 2; - } - - // And more if within five years - if (diff < 5) - { - score += 2; - } - } - - // genres - score += Convert.ToInt32((long)args[2]) * 10; - - // tags - score += Convert.ToInt32((long)args[3]) * 10; - - // # of common keywords - score += Convert.ToInt32((long)args[4]) *10; - - // # of common studios - score += Convert.ToInt32((long)args[5]) * 3; - - // studios - //score += GetListScore(args, 7, 8, 3); - - //var rowPeopleNamesText = (args[12] as string) ?? string.Empty; - //var rowPeopleNames = rowPeopleNamesText.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); - - //foreach (var name in rowPeopleNames) - //{ - // // TODO: Send along person types - // score += 3; - //} - - //Logger.Debug("Returning score {0}", score); - return score; - } - - private int GetListScore(object[] args, int index1, int index2, int value = 10) - { - var score = 0; - - var inputGenres = args[index1] as string; - var rowGenres = args[index2] as string; - var inputGenreList = string.IsNullOrWhiteSpace(inputGenres) ? new string[] { } : inputGenres.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); - var rowGenresList = string.IsNullOrWhiteSpace(rowGenres) ? new string[] { } : rowGenres.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); - - foreach (var genre in inputGenreList) - { - if (rowGenresList.Contains(genre, StringComparer.OrdinalIgnoreCase)) - { - score += value; - } - } - - return score; - } - } } diff --git a/MediaBrowser.Server.Startup.Common/Migrations/FolderViewSettingMigration.cs b/MediaBrowser.Server.Startup.Common/Migrations/FolderViewSettingMigration.cs index 4049d17548..12054864b3 100644 --- a/MediaBrowser.Server.Startup.Common/Migrations/FolderViewSettingMigration.cs +++ b/MediaBrowser.Server.Startup.Common/Migrations/FolderViewSettingMigration.cs @@ -24,7 +24,10 @@ namespace MediaBrowser.Server.Startup.Common.Migrations { if (_config.Configuration.IsStartupWizardCompleted) { - _config.Configuration.EnableFolderView = _userManager.Users.Any(i => i.Configuration.DisplayFoldersView); + if (_userManager.Users.Any(i => i.Configuration.DisplayFoldersView)) + { + _config.Configuration.EnableFolderView = true; + } } migrationKeyList.Add(migrationKey); -- cgit v1.2.3 From 3ba9d3c12f71208cb45d58b93b7c472780a5d541 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Fri, 10 Jun 2016 12:45:04 -0400 Subject: update channel mapping --- MediaBrowser.Api/LiveTv/LiveTvService.cs | 8 +++++--- MediaBrowser.Controller/LiveTv/ILiveTvManager.cs | 2 ++ .../Library/MediaSourceManager.cs | 4 ++++ .../LiveTv/Listings/SchedulesDirect.cs | 14 +++++++++++--- .../Persistence/IDbConnector.cs | 2 +- .../Persistence/SqliteExtensions.cs | 4 ++-- .../Persistence/SqliteItemRepository.cs | 2 +- MediaBrowser.Server.Mono/Native/DbConnector.cs | 4 ++-- MediaBrowser.ServerApplication/Native/DbConnector.cs | 4 ++-- 9 files changed, 30 insertions(+), 14 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs') diff --git a/MediaBrowser.Api/LiveTv/LiveTvService.cs b/MediaBrowser.Api/LiveTv/LiveTvService.cs index ddc389f03a..b2f0704ea4 100644 --- a/MediaBrowser.Api/LiveTv/LiveTvService.cs +++ b/MediaBrowser.Api/LiveTv/LiveTvService.cs @@ -578,7 +578,9 @@ namespace MediaBrowser.Api.LiveTv { var config = GetConfiguration(); - var listingProvider = config.ListingProviders.First(i => string.Equals(request.ProviderId, i.Id, StringComparison.OrdinalIgnoreCase)); + var listingsProviderInfo = config.ListingProviders.First(i => string.Equals(request.ProviderId, i.Id, StringComparison.OrdinalIgnoreCase)); + + var listingsProviderName = _liveTvManager.ListingProviders.First(i => string.Equals(i.Type, listingsProviderInfo.Type, StringComparison.OrdinalIgnoreCase)).Name; var tunerChannels = await _liveTvManager.GetChannelsForListingsProvider(request.ProviderId, CancellationToken.None) .ConfigureAwait(false); @@ -586,7 +588,7 @@ namespace MediaBrowser.Api.LiveTv var providerChannels = await _liveTvManager.GetChannelsFromListingsProviderData(request.ProviderId, CancellationToken.None) .ConfigureAwait(false); - var mappings = listingProvider.ChannelMappings.ToList(); + var mappings = listingsProviderInfo.ChannelMappings.ToList(); var result = new ChannelMappingOptions { @@ -601,7 +603,7 @@ namespace MediaBrowser.Api.LiveTv Mappings = mappings, - ProviderName = "Schedules Direct" + ProviderName = listingsProviderName }; return ToOptimizedResult(result); diff --git a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs index 9cb0476bac..ffba3097ce 100644 --- a/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs +++ b/MediaBrowser.Controller/LiveTv/ILiveTvManager.cs @@ -390,6 +390,8 @@ namespace MediaBrowser.Controller.LiveTv Task> GetChannelsForListingsProvider(string id, CancellationToken cancellationToken); Task> GetChannelsFromListingsProviderData(string id, CancellationToken cancellationToken); + List ListingProviders { get;} + event EventHandler> SeriesTimerCancelled; event EventHandler> TimerCancelled; event EventHandler> TimerCreated; diff --git a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs index 0ef7efe1b8..1bcb02ac39 100644 --- a/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MediaSourceManager.cs @@ -73,6 +73,10 @@ namespace MediaBrowser.Server.Implementations.Library { return false; } + if (string.Equals(stream.Codec, "ssa", StringComparison.OrdinalIgnoreCase)) + { + return false; + } return true; } diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 6443440c81..e37109c148 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -879,6 +879,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings throw new Exception("ListingsId required"); } + await AddMetadata(info, new List(), cancellationToken).ConfigureAwait(false); + var token = await GetToken(info, cancellationToken); if (string.IsNullOrWhiteSpace(token)) @@ -886,8 +888,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings throw new Exception("token required"); } - ClearPairCache(listingsId); - var httpOptions = new HttpRequestOptions() { Url = ApiUrl + "/lineups/" + listingsId, @@ -921,10 +921,18 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings } channelNumber = channelNumber.TrimStart('0'); + var name = channelNumber; + var station = GetStation(listingsId, channelNumber, null); + + if (station != null) + { + name = station.name; + } + list.Add(new ChannelInfo { Number = channelNumber, - Name = map.channel + Name = name }); } } diff --git a/MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs b/MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs index cac9fe9835..2092f830a7 100644 --- a/MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs +++ b/MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs @@ -5,6 +5,6 @@ namespace MediaBrowser.Server.Implementations.Persistence { public interface IDbConnector { - Task Connect(string dbPath); + Task Connect(string dbPath, int? cacheSize = null); } } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs index dd2f15cfd7..2f3f34aa4c 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs @@ -23,7 +23,7 @@ namespace MediaBrowser.Server.Implementations.Persistence /// The logger. /// Task{IDbConnection}. /// dbPath - public static async Task ConnectToDb(string dbPath, ILogger logger) + public static async Task ConnectToDb(string dbPath, int? cacheSize, ILogger logger) { if (string.IsNullOrEmpty(dbPath)) { @@ -35,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.Persistence var connectionstr = new SQLiteConnectionStringBuilder { PageSize = 4096, - CacheSize = 2000, + CacheSize = cacheSize ?? 2000, SyncMode = SynchronizationModes.Normal, DataSource = dbPath, JournalMode = SQLiteJournalModeEnum.Wal diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index a4cb0c48b0..071951018d 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -127,7 +127,7 @@ namespace MediaBrowser.Server.Implementations.Persistence { var dbFile = Path.Combine(_config.ApplicationPaths.DataPath, "library.db"); - _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false); + _connection = await dbConnector.Connect(dbFile, 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))"; diff --git a/MediaBrowser.Server.Mono/Native/DbConnector.cs b/MediaBrowser.Server.Mono/Native/DbConnector.cs index 3230f92f9c..7553dbe1ac 100644 --- a/MediaBrowser.Server.Mono/Native/DbConnector.cs +++ b/MediaBrowser.Server.Mono/Native/DbConnector.cs @@ -16,9 +16,9 @@ namespace MediaBrowser.Server.Mono.Native _logger = logger; } - public Task Connect(string dbPath) + public Task Connect(string dbPath, int? cacheSize = null) { - return SqliteExtensions.ConnectToDb(dbPath, _logger); + return SqliteExtensions.ConnectToDb(dbPath, cacheSize, _logger); } } } \ No newline at end of file diff --git a/MediaBrowser.ServerApplication/Native/DbConnector.cs b/MediaBrowser.ServerApplication/Native/DbConnector.cs index 48ba7d0e7c..6001ac3c07 100644 --- a/MediaBrowser.ServerApplication/Native/DbConnector.cs +++ b/MediaBrowser.ServerApplication/Native/DbConnector.cs @@ -16,11 +16,11 @@ namespace MediaBrowser.ServerApplication.Native _logger = logger; } - public async Task Connect(string dbPath) + public async Task Connect(string dbPath, int? cacheSize = null) { try { - return await SqliteExtensions.ConnectToDb(dbPath, _logger).ConfigureAwait(false); + return await SqliteExtensions.ConnectToDb(dbPath, cacheSize, _logger).ConfigureAwait(false); } catch (Exception ex) { -- cgit v1.2.3 From 4c7f292ba884c16b9e95eb319f3664469189d22c Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 11 Jun 2016 11:55:05 -0400 Subject: use individual connections --- .../Notifications/SqliteNotificationsRepository.cs | 443 +++++------ .../Persistence/BaseSqliteRepository.cs | 16 +- .../Persistence/IDbConnector.cs | 2 +- .../SqliteDisplayPreferencesRepository.cs | 256 +++--- .../Persistence/SqliteExtensions.cs | 20 +- .../SqliteFileOrganizationRepository.cs | 4 +- .../Persistence/SqliteItemRepository.cs | 6 +- .../Persistence/SqliteUserDataRepository.cs | 4 +- .../Persistence/SqliteUserRepository.cs | 201 +++-- .../Security/AuthenticationRepository.cs | 325 ++++---- .../Social/SharingRepository.cs | 171 ++-- .../Sync/SyncRepository.cs | 865 ++++++++++----------- 12 files changed, 1114 insertions(+), 1199 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs') diff --git a/MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs b/MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs index 10e8c5699e..6c3bc3050e 100644 --- a/MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs +++ b/MediaBrowser.Server.Implementations/Notifications/SqliteNotificationsRepository.cs @@ -15,30 +15,20 @@ namespace MediaBrowser.Server.Implementations.Notifications { public class SqliteNotificationsRepository : BaseSqliteRepository, INotificationsRepository { - private IDbConnection _connection; - private readonly IServerApplicationPaths _appPaths; + public SqliteNotificationsRepository(ILogManager logManager, IServerApplicationPaths appPaths, IDbConnector dbConnector) : base(logManager, dbConnector) + { + DbFilePath = Path.Combine(appPaths.DataPath, "notifications.db"); + } public event EventHandler NotificationAdded; public event EventHandler NotificationsMarkedRead; public event EventHandler NotificationUpdated; - private IDbCommand _replaceNotificationCommand; - private IDbCommand _markReadCommand; - private IDbCommand _markAllReadCommand; - - public SqliteNotificationsRepository(ILogManager logManager, IServerApplicationPaths appPaths) - : base(logManager) + public async Task Initialize() { - _appPaths = appPaths; - } - - public async Task Initialize(IDbConnector dbConnector) - { - var dbFile = Path.Combine(_appPaths.DataPath, "notifications.db"); - - _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false); - - string[] queries = { + using (var connection = await CreateConnection().ConfigureAwait(false)) + { + string[] queries = { "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)", @@ -50,39 +40,8 @@ namespace MediaBrowser.Server.Implementations.Notifications "pragma shrink_memory" }; - _connection.RunQueries(queries, Logger); - - PrepareStatements(); - } - - private void PrepareStatements() - { - _replaceNotificationCommand = _connection.CreateCommand(); - _replaceNotificationCommand.CommandText = "replace into Notifications (Id, UserId, Date, Name, Description, Url, Level, IsRead, Category, RelatedId) values (@Id, @UserId, @Date, @Name, @Description, @Url, @Level, @IsRead, @Category, @RelatedId)"; - - _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Id"); - _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@UserId"); - _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Date"); - _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Name"); - _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Description"); - _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Url"); - _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Level"); - _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@IsRead"); - _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@Category"); - _replaceNotificationCommand.Parameters.Add(_replaceNotificationCommand, "@RelatedId"); - - _markReadCommand = _connection.CreateCommand(); - _markReadCommand.CommandText = "update Notifications set IsRead=@IsRead where Id=@Id and UserId=@UserId"; - - _markReadCommand.Parameters.Add(_replaceNotificationCommand, "@UserId"); - _markReadCommand.Parameters.Add(_replaceNotificationCommand, "@IsRead"); - _markReadCommand.Parameters.Add(_replaceNotificationCommand, "@Id"); - - _markAllReadCommand = _connection.CreateCommand(); - _markAllReadCommand.CommandText = "update Notifications set IsRead=@IsRead where UserId=@UserId"; - - _markAllReadCommand.Parameters.Add(_replaceNotificationCommand, "@UserId"); - _markAllReadCommand.Parameters.Add(_replaceNotificationCommand, "@IsRead"); + connection.RunQueries(queries, Logger); + } } /// @@ -94,49 +53,52 @@ namespace MediaBrowser.Server.Implementations.Notifications { var result = new NotificationResult(); - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - var clauses = new List(); - - if (query.IsRead.HasValue) + using (var cmd = connection.CreateCommand()) { - clauses.Add("IsRead=@IsRead"); - cmd.Parameters.Add(cmd, "@IsRead", DbType.Boolean).Value = query.IsRead.Value; - } + var clauses = new List(); - clauses.Add("UserId=@UserId"); - cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = new Guid(query.UserId); + if (query.IsRead.HasValue) + { + clauses.Add("IsRead=@IsRead"); + cmd.Parameters.Add(cmd, "@IsRead", DbType.Boolean).Value = query.IsRead.Value; + } - var whereClause = " where " + string.Join(" And ", clauses.ToArray()); + clauses.Add("UserId=@UserId"); + cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = new Guid(query.UserId); - cmd.CommandText = string.Format("select count(Id) from Notifications{0};select Id,UserId,Date,Name,Description,Url,Level,IsRead,Category,RelatedId from Notifications{0} order by IsRead asc, Date desc", whereClause); + var whereClause = " where " + string.Join(" And ", clauses.ToArray()); - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) - { - if (reader.Read()) - { - result.TotalRecordCount = reader.GetInt32(0); - } + cmd.CommandText = string.Format("select count(Id) from Notifications{0};select Id,UserId,Date,Name,Description,Url,Level,IsRead,Category,RelatedId from Notifications{0} order by IsRead asc, Date desc", whereClause); - if (reader.NextResult()) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) { - var notifications = GetNotifications(reader); - - if (query.StartIndex.HasValue) + if (reader.Read()) { - notifications = notifications.Skip(query.StartIndex.Value); + result.TotalRecordCount = reader.GetInt32(0); } - if (query.Limit.HasValue) + if (reader.NextResult()) { - notifications = notifications.Take(query.Limit.Value); - } + var notifications = GetNotifications(reader); - result.Notifications = notifications.ToArray(); + if (query.StartIndex.HasValue) + { + notifications = notifications.Skip(query.StartIndex.Value); + } + + if (query.Limit.HasValue) + { + notifications = notifications.Take(query.Limit.Value); + } + + result.Notifications = notifications.ToArray(); + } } - } - return result; + return result; + } } } @@ -144,31 +106,34 @@ namespace MediaBrowser.Server.Implementations.Notifications { var result = new NotificationsSummary(); - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = "select Level from Notifications where UserId=@UserId and IsRead=@IsRead"; - - cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = new Guid(userId); - cmd.Parameters.Add(cmd, "@IsRead", DbType.Boolean).Value = false; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) + using (var cmd = connection.CreateCommand()) { - var levels = new List(); + cmd.CommandText = "select Level from Notifications where UserId=@UserId and IsRead=@IsRead"; - while (reader.Read()) + cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = new Guid(userId); + cmd.Parameters.Add(cmd, "@IsRead", DbType.Boolean).Value = false; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) { - levels.Add(GetLevel(reader, 0)); - } + var levels = new List(); - result.UnreadCount = levels.Count; + while (reader.Read()) + { + levels.Add(GetLevel(reader, 0)); + } - if (levels.Count > 0) - { - result.MaxUnreadNotificationLevel = levels.Max(); + result.UnreadCount = levels.Count; + + if (levels.Count > 0) + { + result.MaxUnreadNotificationLevel = levels.Max(); + } } - } - return result; + return result; + } } } @@ -179,10 +144,14 @@ namespace MediaBrowser.Server.Implementations.Notifications /// IEnumerable{Notification}. private IEnumerable GetNotifications(IDataReader reader) { + var list = new List(); + while (reader.Read()) { - yield return GetNotification(reader); + list.Add(GetNotification(reader)); } + + return list; } private Notification GetNotification(IDataReader reader) @@ -273,59 +242,74 @@ namespace MediaBrowser.Server.Implementations.Notifications cancellationToken.ThrowIfCancellationRequested(); - await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); - - IDbTransaction transaction = null; - - try + using (var connection = await CreateConnection().ConfigureAwait(false)) { - transaction = _connection.BeginTransaction(); + using (var replaceNotificationCommand = connection.CreateCommand()) + { + replaceNotificationCommand.CommandText = "replace into Notifications (Id, UserId, Date, Name, Description, Url, Level, IsRead, Category, RelatedId) values (@Id, @UserId, @Date, @Name, @Description, @Url, @Level, @IsRead, @Category, @RelatedId)"; + + replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Id"); + replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@UserId"); + replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Date"); + replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Name"); + replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Description"); + replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Url"); + replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Level"); + replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@IsRead"); + replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@Category"); + replaceNotificationCommand.Parameters.Add(replaceNotificationCommand, "@RelatedId"); + + IDbTransaction transaction = null; + + try + { + transaction = connection.BeginTransaction(); - _replaceNotificationCommand.GetParameter(0).Value = new Guid(notification.Id); - _replaceNotificationCommand.GetParameter(1).Value = new Guid(notification.UserId); - _replaceNotificationCommand.GetParameter(2).Value = notification.Date.ToUniversalTime(); - _replaceNotificationCommand.GetParameter(3).Value = notification.Name; - _replaceNotificationCommand.GetParameter(4).Value = notification.Description; - _replaceNotificationCommand.GetParameter(5).Value = notification.Url; - _replaceNotificationCommand.GetParameter(6).Value = notification.Level.ToString(); - _replaceNotificationCommand.GetParameter(7).Value = notification.IsRead; - _replaceNotificationCommand.GetParameter(8).Value = string.Empty; - _replaceNotificationCommand.GetParameter(9).Value = string.Empty; + replaceNotificationCommand.GetParameter(0).Value = new Guid(notification.Id); + replaceNotificationCommand.GetParameter(1).Value = new Guid(notification.UserId); + replaceNotificationCommand.GetParameter(2).Value = notification.Date.ToUniversalTime(); + replaceNotificationCommand.GetParameter(3).Value = notification.Name; + replaceNotificationCommand.GetParameter(4).Value = notification.Description; + replaceNotificationCommand.GetParameter(5).Value = notification.Url; + replaceNotificationCommand.GetParameter(6).Value = notification.Level.ToString(); + replaceNotificationCommand.GetParameter(7).Value = notification.IsRead; + replaceNotificationCommand.GetParameter(8).Value = string.Empty; + replaceNotificationCommand.GetParameter(9).Value = string.Empty; - _replaceNotificationCommand.Transaction = transaction; + replaceNotificationCommand.Transaction = transaction; - _replaceNotificationCommand.ExecuteNonQuery(); + replaceNotificationCommand.ExecuteNonQuery(); - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) - { - transaction.Rollback(); - } + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) + { + transaction.Rollback(); + } - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save notification:", e); + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save notification:", e); - if (transaction != null) - { - transaction.Rollback(); - } + if (transaction != null) + { + transaction.Rollback(); + } - throw; - } - finally - { - if (transaction != null) - { - transaction.Dispose(); + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + } } - - WriteLock.Release(); } } @@ -366,51 +350,58 @@ namespace MediaBrowser.Server.Implementations.Notifications { cancellationToken.ThrowIfCancellationRequested(); - await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); + using (var connection = await CreateConnection().ConfigureAwait(false)) + { + using (var markAllReadCommand = connection.CreateCommand()) + { + markAllReadCommand.CommandText = "update Notifications set IsRead=@IsRead where UserId=@UserId"; - IDbTransaction transaction = null; + markAllReadCommand.Parameters.Add(markAllReadCommand, "@UserId"); + markAllReadCommand.Parameters.Add(markAllReadCommand, "@IsRead"); - try - { - cancellationToken.ThrowIfCancellationRequested(); + IDbTransaction transaction = null; - transaction = _connection.BeginTransaction(); + try + { + cancellationToken.ThrowIfCancellationRequested(); - _markAllReadCommand.GetParameter(0).Value = new Guid(userId); - _markAllReadCommand.GetParameter(1).Value = isRead; + transaction = connection.BeginTransaction(); - _markAllReadCommand.ExecuteNonQuery(); + markAllReadCommand.GetParameter(0).Value = new Guid(userId); + markAllReadCommand.GetParameter(1).Value = isRead; - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) - { - transaction.Rollback(); - } + markAllReadCommand.ExecuteNonQuery(); - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save notification:", e); + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) + { + transaction.Rollback(); + } - if (transaction != null) - { - transaction.Rollback(); - } + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save notification:", e); - throw; - } - finally - { - if (transaction != null) - { - transaction.Dispose(); - } + if (transaction != null) + { + transaction.Rollback(); + } - WriteLock.Release(); + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + } + } } } @@ -418,72 +409,66 @@ namespace MediaBrowser.Server.Implementations.Notifications { cancellationToken.ThrowIfCancellationRequested(); - await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); - - IDbTransaction transaction = null; - - try + using (var connection = await CreateConnection().ConfigureAwait(false)) { - cancellationToken.ThrowIfCancellationRequested(); + using (var markReadCommand = connection.CreateCommand()) + { + markReadCommand.CommandText = "update Notifications set IsRead=@IsRead where Id=@Id and UserId=@UserId"; - transaction = _connection.BeginTransaction(); + markReadCommand.Parameters.Add(markReadCommand, "@UserId"); + markReadCommand.Parameters.Add(markReadCommand, "@IsRead"); + markReadCommand.Parameters.Add(markReadCommand, "@Id"); - _markReadCommand.GetParameter(0).Value = new Guid(userId); - _markReadCommand.GetParameter(1).Value = isRead; + IDbTransaction transaction = null; - foreach (var id in notificationIdList) - { - _markReadCommand.GetParameter(2).Value = id; + try + { + cancellationToken.ThrowIfCancellationRequested(); - _markReadCommand.Transaction = transaction; + transaction = connection.BeginTransaction(); - _markReadCommand.ExecuteNonQuery(); - } + markReadCommand.GetParameter(0).Value = new Guid(userId); + markReadCommand.GetParameter(1).Value = isRead; - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) - { - transaction.Rollback(); - } + foreach (var id in notificationIdList) + { + markReadCommand.GetParameter(2).Value = id; - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save notification:", e); + markReadCommand.Transaction = transaction; - if (transaction != null) - { - transaction.Rollback(); - } + markReadCommand.ExecuteNonQuery(); + } - throw; - } - finally - { - if (transaction != null) - { - transaction.Dispose(); - } + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) + { + transaction.Rollback(); + } - WriteLock.Release(); - } - } + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save notification:", e); - protected override void CloseConnection() - { - if (_connection != null) - { - if (_connection.IsOpen()) - { - _connection.Close(); - } + if (transaction != null) + { + transaction.Rollback(); + } - _connection.Dispose(); - _connection = null; + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + } + } } } } diff --git a/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs b/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs index 3959078449..f9c892b76a 100644 --- a/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/BaseSqliteRepository.cs @@ -9,13 +9,22 @@ 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; - protected BaseSqliteRepository(ILogManager logManager) + protected string DbFilePath { get; set; } + + protected BaseSqliteRepository(ILogManager logManager, IDbConnector dbConnector) { + DbConnector = dbConnector; Logger = logManager.GetLogger(GetType().Name); } + protected Task CreateConnection(bool isReadOnly = false) + { + return DbConnector.Connect(DbFilePath, false, true); + } + private bool _disposed; protected void CheckDisposed() { @@ -84,6 +93,9 @@ namespace MediaBrowser.Server.Implementations.Persistence } } - protected abstract void CloseConnection(); + protected virtual void CloseConnection() + { + + } } } diff --git a/MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs b/MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs index 2092f830a7..596cf8407a 100644 --- a/MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs +++ b/MediaBrowser.Server.Implementations/Persistence/IDbConnector.cs @@ -5,6 +5,6 @@ namespace MediaBrowser.Server.Implementations.Persistence { public interface IDbConnector { - Task Connect(string dbPath, int? cacheSize = null); + Task Connect(string dbPath, bool isReadOnly, bool enablePooling = false, int? cacheSize = null); } } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs index 6077cfdba4..1a6a88ebe2 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteDisplayPreferencesRepository.cs @@ -18,12 +18,11 @@ namespace MediaBrowser.Server.Implementations.Persistence /// public class SqliteDisplayPreferencesRepository : BaseSqliteRepository, IDisplayPreferencesRepository { - private IDbConnection _connection; - - public SqliteDisplayPreferencesRepository(ILogManager logManager, IJsonSerializer jsonSerializer, IApplicationPaths appPaths) : base(logManager) + public SqliteDisplayPreferencesRepository(ILogManager logManager, IJsonSerializer jsonSerializer, IApplicationPaths appPaths, IDbConnector dbConnector) + : base(logManager, dbConnector) { _jsonSerializer = jsonSerializer; - _appPaths = appPaths; + DbFilePath = Path.Combine(appPaths.DataPath, "displaypreferences.db"); } /// @@ -43,22 +42,15 @@ namespace MediaBrowser.Server.Implementations.Persistence /// private readonly IJsonSerializer _jsonSerializer; - /// - /// The _app paths - /// - private readonly IApplicationPaths _appPaths; - /// /// Opens the connection to the database /// /// Task. - public async Task Initialize(IDbConnector dbConnector) + public async Task Initialize() { - var dbFile = Path.Combine(_appPaths.DataPath, "displaypreferences.db"); - - _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false); - - string[] queries = { + using (var connection = await CreateConnection().ConfigureAwait(false)) + { + 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)", @@ -69,7 +61,8 @@ namespace MediaBrowser.Server.Implementations.Persistence "pragma shrink_memory" }; - _connection.RunQueries(queries, Logger); + connection.RunQueries(queries, Logger); + } } /// @@ -96,58 +89,57 @@ namespace MediaBrowser.Server.Implementations.Persistence var serialized = _jsonSerializer.SerializeToBytes(displayPreferences); - 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 userdisplaypreferences (id, userid, client, data) values (@1, @2, @3, @4)"; + transaction = connection.BeginTransaction(); + + using (var cmd = connection.CreateCommand()) + { + cmd.CommandText = "replace into userdisplaypreferences (id, userid, client, data) values (@1, @2, @3, @4)"; - cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = new Guid(displayPreferences.Id); - cmd.Parameters.Add(cmd, "@2", DbType.Guid).Value = userId; - cmd.Parameters.Add(cmd, "@3", DbType.String).Value = client; - cmd.Parameters.Add(cmd, "@4", DbType.Binary).Value = serialized; + cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = new Guid(displayPreferences.Id); + cmd.Parameters.Add(cmd, "@2", DbType.Guid).Value = userId; + cmd.Parameters.Add(cmd, "@3", DbType.String).Value = client; + cmd.Parameters.Add(cmd, "@4", DbType.Binary).Value = serialized; - cmd.Transaction = transaction; + cmd.Transaction = transaction; - cmd.ExecuteNonQuery(); - } + cmd.ExecuteNonQuery(); + } - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + transaction.Commit(); + } + catch (OperationCanceledException) { - transaction.Rollback(); + if (transaction != null) + { + transaction.Rollback(); + } + + throw; } + catch (Exception e) + { + Logger.ErrorException("Failed to save display preferences:", e); - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save display preferences:", e); + if (transaction != null) + { + transaction.Rollback(); + } - if (transaction != null) - { - transaction.Rollback(); + throw; } - - throw; - } - finally - { - if (transaction != null) + finally { - transaction.Dispose(); + if (transaction != null) + { + transaction.Dispose(); + } } - - WriteLock.Release(); } } @@ -168,64 +160,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; - foreach (var displayPreference in displayPreferences) + try { + transaction = connection.BeginTransaction(); - var serialized = _jsonSerializer.SerializeToBytes(displayPreference); - - using (var cmd = _connection.CreateCommand()) + foreach (var displayPreference in displayPreferences) { - cmd.CommandText = "replace into userdisplaypreferences (id, userid, client, data) values (@1, @2, @3, @4)"; - cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = new Guid(displayPreference.Id); - cmd.Parameters.Add(cmd, "@2", DbType.Guid).Value = userId; - cmd.Parameters.Add(cmd, "@3", DbType.String).Value = displayPreference.Client; - cmd.Parameters.Add(cmd, "@4", DbType.Binary).Value = serialized; + var serialized = _jsonSerializer.SerializeToBytes(displayPreference); - cmd.Transaction = transaction; + using (var cmd = connection.CreateCommand()) + { + cmd.CommandText = "replace into userdisplaypreferences (id, userid, client, data) values (@1, @2, @3, @4)"; - cmd.ExecuteNonQuery(); + cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = new Guid(displayPreference.Id); + cmd.Parameters.Add(cmd, "@2", DbType.Guid).Value = userId; + cmd.Parameters.Add(cmd, "@3", DbType.String).Value = displayPreference.Client; + cmd.Parameters.Add(cmd, "@4", DbType.Binary).Value = serialized; + + cmd.Transaction = transaction; + + cmd.ExecuteNonQuery(); + } } - } - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + transaction.Commit(); + } + catch (OperationCanceledException) { - transaction.Rollback(); + if (transaction != null) + { + transaction.Rollback(); + } + + throw; } + catch (Exception e) + { + Logger.ErrorException("Failed to save display preferences:", e); - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save display preferences:", e); + if (transaction != null) + { + transaction.Rollback(); + } - if (transaction != null) - { - transaction.Rollback(); + throw; } - - throw; - } - finally - { - if (transaction != null) + finally { - transaction.Dispose(); + if (transaction != null) + { + transaction.Dispose(); + } } - - WriteLock.Release(); } } @@ -246,28 +237,33 @@ namespace MediaBrowser.Server.Implementations.Persistence var guidId = displayPreferencesId.GetMD5(); - var cmd = _connection.CreateCommand(); - cmd.CommandText = "select data from userdisplaypreferences where id = @id and userId=@userId and client=@client"; - - cmd.Parameters.Add(cmd, "@id", DbType.Guid).Value = guidId; - cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; - cmd.Parameters.Add(cmd, "@client", DbType.String).Value = client; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) + using (var connection = CreateConnection(true).Result) { - if (reader.Read()) + using (var cmd = connection.CreateCommand()) { - using (var stream = reader.GetMemoryStream(0)) + cmd.CommandText = "select data from userdisplaypreferences where id = @id and userId=@userId and client=@client"; + + cmd.Parameters.Add(cmd, "@id", DbType.Guid).Value = guidId; + cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; + cmd.Parameters.Add(cmd, "@client", DbType.String).Value = client; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) { - return _jsonSerializer.DeserializeFromStream(stream); + if (reader.Read()) + { + using (var stream = reader.GetMemoryStream(0)) + { + return _jsonSerializer.DeserializeFromStream(stream); + } + } } + + return new DisplayPreferences + { + Id = guidId.ToString("N") + }; } } - - return new DisplayPreferences - { - Id = guidId.ToString("N") - }; } /// @@ -278,36 +274,30 @@ namespace MediaBrowser.Server.Implementations.Persistence /// item public IEnumerable GetAllDisplayPreferences(Guid userId) { + var list = new List(); - var cmd = _connection.CreateCommand(); - cmd.CommandText = "select data from userdisplaypreferences where userId=@userId"; - - cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; - - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + using (var connection = CreateConnection(true).Result) { - while (reader.Read()) + using (var cmd = connection.CreateCommand()) { - using (var stream = reader.GetMemoryStream(0)) + cmd.CommandText = "select data from userdisplaypreferences where userId=@userId"; + + cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) { - yield return _jsonSerializer.DeserializeFromStream(stream); + while (reader.Read()) + { + using (var stream = reader.GetMemoryStream(0)) + { + list.Add(_jsonSerializer.DeserializeFromStream(stream)); + } + } } } } - } - - protected override void CloseConnection() - { - if (_connection != null) - { - if (_connection.IsOpen()) - { - _connection.Close(); - } - _connection.Dispose(); - _connection = null; - } + return list; } public Task SaveDisplayPreferences(DisplayPreferences displayPreferences, string userId, string client, CancellationToken cancellationToken) diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs index 2f3f34aa4c..cc9e3ebccf 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs @@ -19,11 +19,7 @@ namespace MediaBrowser.Server.Implementations.Persistence /// /// Connects to db. /// - /// The db path. - /// The logger. - /// Task{IDbConnection}. - /// dbPath - public static async Task ConnectToDb(string dbPath, int? cacheSize, ILogger logger) + public static async Task ConnectToDb(string dbPath, bool isReadOnly, bool enablePooling, int? cacheSize, ILogger logger) { if (string.IsNullOrEmpty(dbPath)) { @@ -38,7 +34,9 @@ namespace MediaBrowser.Server.Implementations.Persistence CacheSize = cacheSize ?? 2000, SyncMode = SynchronizationModes.Normal, DataSource = dbPath, - JournalMode = SQLiteJournalModeEnum.Wal + JournalMode = SQLiteJournalModeEnum.Wal, + Pooling = enablePooling, + ReadOnly = isReadOnly }; var connection = new SQLiteConnection(connectionstr.ConnectionString); @@ -47,15 +45,5 @@ namespace MediaBrowser.Server.Implementations.Persistence return connection; } - - public static void BindFunction(this SQLiteConnection connection, SQLiteFunction function) - { - var attributes = function.GetType().GetCustomAttributes(typeof(SQLiteFunctionAttribute), true).Cast().ToArray(); - if (attributes.Length == 0) - { - throw new InvalidOperationException("SQLiteFunction doesn't have SQLiteFunctionAttribute"); - } - connection.BindFunction(attributes[0], function); - } } } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs index 037776997e..8a4ba6460d 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteFileOrganizationRepository.cs @@ -26,7 +26,7 @@ namespace MediaBrowser.Server.Implementations.Persistence private IDbCommand _deleteResultCommand; private IDbCommand _deleteAllCommand; - public SqliteFileOrganizationRepository(ILogManager logManager, IServerApplicationPaths appPaths) : base(logManager) + public SqliteFileOrganizationRepository(ILogManager logManager, IServerApplicationPaths appPaths, IDbConnector connector) : base(logManager, connector) { _appPaths = appPaths; } @@ -39,7 +39,7 @@ namespace MediaBrowser.Server.Implementations.Persistence { var dbFile = Path.Combine(_appPaths.DataPath, "fileorganization.db"); - _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false); + _connection = await dbConnector.Connect(dbFile, false).ConfigureAwait(false); string[] queries = { diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 071951018d..9bfdd879da 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -99,8 +99,8 @@ namespace MediaBrowser.Server.Implementations.Persistence /// /// Initializes a new instance of the class. /// - public SqliteItemRepository(IServerConfigurationManager config, IJsonSerializer jsonSerializer, ILogManager logManager) - : base(logManager) + public SqliteItemRepository(IServerConfigurationManager config, IJsonSerializer jsonSerializer, ILogManager logManager, IDbConnector connector) + : base(logManager, connector) { if (config == null) { @@ -127,7 +127,7 @@ namespace MediaBrowser.Server.Implementations.Persistence { var dbFile = Path.Combine(_config.ApplicationPaths.DataPath, "library.db"); - _connection = await dbConnector.Connect(dbFile, 6000).ConfigureAwait(false); + _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))"; diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs index bfdb9e0c7a..d81f4ad37b 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs @@ -18,7 +18,7 @@ namespace MediaBrowser.Server.Implementations.Persistence private IDbConnection _connection; private readonly IApplicationPaths _appPaths; - public SqliteUserDataRepository(ILogManager logManager, IApplicationPaths appPaths) : base(logManager) + public SqliteUserDataRepository(ILogManager logManager, IApplicationPaths appPaths, IDbConnector connector) : base(logManager, connector) { _appPaths = appPaths; } @@ -43,7 +43,7 @@ namespace MediaBrowser.Server.Implementations.Persistence { var dbFile = Path.Combine(_appPaths.DataPath, "userdata_v2.db"); - _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false); + _connection = await dbConnector.Connect(dbFile, false).ConfigureAwait(false); string[] queries = { diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs index f7ca39a548..4c07a60181 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserRepository.cs @@ -17,14 +17,13 @@ namespace MediaBrowser.Server.Implementations.Persistence /// public class SqliteUserRepository : BaseSqliteRepository, IUserRepository { - private IDbConnection _connection; - private readonly IServerApplicationPaths _appPaths; private readonly IJsonSerializer _jsonSerializer; - public SqliteUserRepository(ILogManager logManager, IServerApplicationPaths appPaths, IJsonSerializer jsonSerializer) : base(logManager) + public SqliteUserRepository(ILogManager logManager, IServerApplicationPaths appPaths, IJsonSerializer jsonSerializer, IDbConnector dbConnector) : base(logManager, dbConnector) { - _appPaths = appPaths; _jsonSerializer = jsonSerializer; + + DbFilePath = Path.Combine(appPaths.DataPath, "users.db"); } /// @@ -43,13 +42,11 @@ namespace MediaBrowser.Server.Implementations.Persistence /// Opens the connection to the database /// /// Task. - public async Task Initialize(IDbConnector dbConnector) + public async Task Initialize() { - var dbFile = Path.Combine(_appPaths.DataPath, "users.db"); - - _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false); - - string[] queries = { + using (var connection = await CreateConnection().ConfigureAwait(false)) + { + string[] queries = { "create table if not exists users (guid GUID primary key, data BLOB)", "create index if not exists idx_users on users(guid)", @@ -61,7 +58,8 @@ namespace MediaBrowser.Server.Implementations.Persistence "pragma shrink_memory" }; - _connection.RunQueries(queries, Logger); + connection.RunQueries(queries, Logger); + } } /// @@ -84,55 +82,54 @@ 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 users (guid, data) values (@1, @2)"; - cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = user.Id; - cmd.Parameters.Add(cmd, "@2", DbType.Binary).Value = serialized; + transaction = connection.BeginTransaction(); - cmd.Transaction = transaction; + using (var cmd = connection.CreateCommand()) + { + cmd.CommandText = "replace into users (guid, data) values (@1, @2)"; + cmd.Parameters.Add(cmd, "@1", DbType.Guid).Value = user.Id; + cmd.Parameters.Add(cmd, "@2", DbType.Binary).Value = serialized; - cmd.ExecuteNonQuery(); - } + cmd.Transaction = transaction; - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + cmd.ExecuteNonQuery(); + } + + transaction.Commit(); + } + catch (OperationCanceledException) { - transaction.Rollback(); + if (transaction != null) + { + transaction.Rollback(); + } + + throw; } + catch (Exception e) + { + Logger.ErrorException("Failed to save user:", e); - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save user:", e); + if (transaction != null) + { + transaction.Rollback(); + } - if (transaction != null) - { - transaction.Rollback(); + throw; } - - throw; - } - finally - { - if (transaction != null) + finally { - transaction.Dispose(); + if (transaction != null) + { + transaction.Dispose(); + } } - - WriteLock.Release(); } } @@ -142,25 +139,32 @@ namespace MediaBrowser.Server.Implementations.Persistence /// IEnumerable{User}. public IEnumerable RetrieveAllUsers() { - using (var cmd = _connection.CreateCommand()) - { - cmd.CommandText = "select guid,data from users"; + var list = new List(); - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + using (var connection = CreateConnection(true).Result) + { + using (var cmd = connection.CreateCommand()) { - while (reader.Read()) - { - var id = reader.GetGuid(0); + cmd.CommandText = "select guid,data from users"; - using (var stream = reader.GetMemoryStream(1)) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) { - var user = _jsonSerializer.DeserializeFromStream(stream); - user.Id = id; - yield return user; + var id = reader.GetGuid(0); + + using (var stream = reader.GetMemoryStream(1)) + { + var user = _jsonSerializer.DeserializeFromStream(stream); + user.Id = id; + list.Add(user); + } } } } } + + return list; } /// @@ -179,69 +183,54 @@ 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 = "delete from users where guid=@guid"; - - cmd.Parameters.Add(cmd, "@guid", DbType.Guid).Value = user.Id; + transaction = connection.BeginTransaction(); - cmd.Transaction = transaction; + using (var cmd = connection.CreateCommand()) + { + cmd.CommandText = "delete from users where guid=@guid"; - cmd.ExecuteNonQuery(); - } + cmd.Parameters.Add(cmd, "@guid", DbType.Guid).Value = user.Id; - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) - { - transaction.Rollback(); - } + cmd.Transaction = transaction; - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to delete user:", e); + cmd.ExecuteNonQuery(); + } - if (transaction != null) - { - transaction.Rollback(); + transaction.Commit(); } - - throw; - } - finally - { - if (transaction != null) + catch (OperationCanceledException) { - transaction.Dispose(); + if (transaction != null) + { + transaction.Rollback(); + } + + throw; } + catch (Exception e) + { + Logger.ErrorException("Failed to delete user:", e); - WriteLock.Release(); - } - } + if (transaction != null) + { + transaction.Rollback(); + } - protected override void CloseConnection() - { - if (_connection != null) - { - if (_connection.IsOpen()) + throw; + } + finally { - _connection.Close(); + if (transaction != null) + { + transaction.Dispose(); + } } - - _connection.Dispose(); - _connection = null; } } } diff --git a/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs b/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs index e8d9814ecb..3013510de1 100644 --- a/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs +++ b/MediaBrowser.Server.Implementations/Security/AuthenticationRepository.cs @@ -15,25 +15,21 @@ namespace MediaBrowser.Server.Implementations.Security { public class AuthenticationRepository : BaseSqliteRepository, IAuthenticationRepository { - private IDbConnection _connection; private readonly IServerApplicationPaths _appPaths; private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - private IDbCommand _saveInfoCommand; - - public AuthenticationRepository(ILogManager logManager, IServerApplicationPaths appPaths) - : base(logManager) + public AuthenticationRepository(ILogManager logManager, IServerApplicationPaths appPaths, IDbConnector connector) + : base(logManager, connector) { _appPaths = appPaths; + DbFilePath = Path.Combine(appPaths.DataPath, "authentication.db"); } - public async Task Initialize(IDbConnector dbConnector) + public async Task Initialize() { - var dbFile = Path.Combine(_appPaths.DataPath, "authentication.db"); - - _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false); - - string[] queries = { + using (var connection = await CreateConnection().ConfigureAwait(false)) + { + 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)", @@ -44,28 +40,10 @@ namespace MediaBrowser.Server.Implementations.Security "pragma shrink_memory" }; - _connection.RunQueries(queries, Logger); - - _connection.AddColumn(Logger, "AccessTokens", "AppVersion", "TEXT"); + connection.RunQueries(queries, Logger); - PrepareStatements(); - } - - private void PrepareStatements() - { - _saveInfoCommand = _connection.CreateCommand(); - _saveInfoCommand.CommandText = "replace into AccessTokens (Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, IsActive, DateCreated, DateRevoked) values (@Id, @AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @IsActive, @DateCreated, @DateRevoked)"; - - _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@Id"); - _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@AccessToken"); - _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@DeviceId"); - _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@AppName"); - _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@AppVersion"); - _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@DeviceName"); - _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@UserId"); - _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@IsActive"); - _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@DateCreated"); - _saveInfoCommand.Parameters.Add(_saveInfoCommand, "@DateRevoked"); + connection.AddColumn(Logger, "AccessTokens", "AppVersion", "TEXT"); + } } public Task Create(AuthenticationInfo info, CancellationToken cancellationToken) @@ -84,61 +62,76 @@ namespace MediaBrowser.Server.Implementations.Security cancellationToken.ThrowIfCancellationRequested(); - await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); - - IDbTransaction transaction = null; - - try + using (var connection = await CreateConnection().ConfigureAwait(false)) { - transaction = _connection.BeginTransaction(); + using (var saveInfoCommand = connection.CreateCommand()) + { + saveInfoCommand.CommandText = "replace into AccessTokens (Id, AccessToken, DeviceId, AppName, AppVersion, DeviceName, UserId, IsActive, DateCreated, DateRevoked) values (@Id, @AccessToken, @DeviceId, @AppName, @AppVersion, @DeviceName, @UserId, @IsActive, @DateCreated, @DateRevoked)"; + + saveInfoCommand.Parameters.Add(saveInfoCommand, "@Id"); + saveInfoCommand.Parameters.Add(saveInfoCommand, "@AccessToken"); + saveInfoCommand.Parameters.Add(saveInfoCommand, "@DeviceId"); + saveInfoCommand.Parameters.Add(saveInfoCommand, "@AppName"); + saveInfoCommand.Parameters.Add(saveInfoCommand, "@AppVersion"); + saveInfoCommand.Parameters.Add(saveInfoCommand, "@DeviceName"); + saveInfoCommand.Parameters.Add(saveInfoCommand, "@UserId"); + saveInfoCommand.Parameters.Add(saveInfoCommand, "@IsActive"); + saveInfoCommand.Parameters.Add(saveInfoCommand, "@DateCreated"); + saveInfoCommand.Parameters.Add(saveInfoCommand, "@DateRevoked"); + + IDbTransaction transaction = null; + + try + { + transaction = connection.BeginTransaction(); - var index = 0; + var index = 0; - _saveInfoCommand.GetParameter(index++).Value = new Guid(info.Id); - _saveInfoCommand.GetParameter(index++).Value = info.AccessToken; - _saveInfoCommand.GetParameter(index++).Value = info.DeviceId; - _saveInfoCommand.GetParameter(index++).Value = info.AppName; - _saveInfoCommand.GetParameter(index++).Value = info.AppVersion; - _saveInfoCommand.GetParameter(index++).Value = info.DeviceName; - _saveInfoCommand.GetParameter(index++).Value = info.UserId; - _saveInfoCommand.GetParameter(index++).Value = info.IsActive; - _saveInfoCommand.GetParameter(index++).Value = info.DateCreated; - _saveInfoCommand.GetParameter(index++).Value = info.DateRevoked; + saveInfoCommand.GetParameter(index++).Value = new Guid(info.Id); + saveInfoCommand.GetParameter(index++).Value = info.AccessToken; + saveInfoCommand.GetParameter(index++).Value = info.DeviceId; + saveInfoCommand.GetParameter(index++).Value = info.AppName; + saveInfoCommand.GetParameter(index++).Value = info.AppVersion; + saveInfoCommand.GetParameter(index++).Value = info.DeviceName; + saveInfoCommand.GetParameter(index++).Value = info.UserId; + saveInfoCommand.GetParameter(index++).Value = info.IsActive; + saveInfoCommand.GetParameter(index++).Value = info.DateCreated; + saveInfoCommand.GetParameter(index++).Value = info.DateRevoked; - _saveInfoCommand.Transaction = transaction; + saveInfoCommand.Transaction = transaction; - _saveInfoCommand.ExecuteNonQuery(); + saveInfoCommand.ExecuteNonQuery(); - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) - { - transaction.Rollback(); - } + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) + { + transaction.Rollback(); + } - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save record:", e); + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save record:", e); - if (transaction != null) - { - transaction.Rollback(); - } + if (transaction != null) + { + transaction.Rollback(); + } - throw; - } - finally - { - if (transaction != null) - { - transaction.Dispose(); + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + } } - - WriteLock.Release(); } } @@ -151,101 +144,104 @@ namespace MediaBrowser.Server.Implementations.Security throw new ArgumentNullException("query"); } - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = BaseSelectText; - - var whereClauses = new List(); - - var startIndex = query.StartIndex ?? 0; - - if (!string.IsNullOrWhiteSpace(query.AccessToken)) + using (var cmd = connection.CreateCommand()) { - whereClauses.Add("AccessToken=@AccessToken"); - cmd.Parameters.Add(cmd, "@AccessToken", DbType.String).Value = query.AccessToken; - } + cmd.CommandText = BaseSelectText; - if (!string.IsNullOrWhiteSpace(query.UserId)) - { - whereClauses.Add("UserId=@UserId"); - cmd.Parameters.Add(cmd, "@UserId", DbType.String).Value = query.UserId; - } + var whereClauses = new List(); - if (!string.IsNullOrWhiteSpace(query.DeviceId)) - { - whereClauses.Add("DeviceId=@DeviceId"); - cmd.Parameters.Add(cmd, "@DeviceId", DbType.String).Value = query.DeviceId; - } + var startIndex = query.StartIndex ?? 0; - if (query.IsActive.HasValue) - { - whereClauses.Add("IsActive=@IsActive"); - cmd.Parameters.Add(cmd, "@IsActive", DbType.Boolean).Value = query.IsActive.Value; - } + if (!string.IsNullOrWhiteSpace(query.AccessToken)) + { + whereClauses.Add("AccessToken=@AccessToken"); + cmd.Parameters.Add(cmd, "@AccessToken", DbType.String).Value = query.AccessToken; + } - if (query.HasUser.HasValue) - { - if (query.HasUser.Value) + if (!string.IsNullOrWhiteSpace(query.UserId)) { - whereClauses.Add("UserId not null"); + whereClauses.Add("UserId=@UserId"); + cmd.Parameters.Add(cmd, "@UserId", DbType.String).Value = query.UserId; } - else + + if (!string.IsNullOrWhiteSpace(query.DeviceId)) { - whereClauses.Add("UserId is null"); + whereClauses.Add("DeviceId=@DeviceId"); + cmd.Parameters.Add(cmd, "@DeviceId", DbType.String).Value = query.DeviceId; } - } - var whereTextWithoutPaging = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + if (query.IsActive.HasValue) + { + whereClauses.Add("IsActive=@IsActive"); + cmd.Parameters.Add(cmd, "@IsActive", DbType.Boolean).Value = query.IsActive.Value; + } - if (startIndex > 0) - { - var pagingWhereText = whereClauses.Count == 0 ? + if (query.HasUser.HasValue) + { + if (query.HasUser.Value) + { + whereClauses.Add("UserId not null"); + } + else + { + whereClauses.Add("UserId is null"); + } + } + + var whereTextWithoutPaging = whereClauses.Count == 0 ? string.Empty : " where " + string.Join(" AND ", whereClauses.ToArray()); - whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM AccessTokens {0} ORDER BY DateCreated LIMIT {1})", - pagingWhereText, - startIndex.ToString(_usCulture))); - } + if (startIndex > 0) + { + var pagingWhereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); + + whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM AccessTokens {0} ORDER BY DateCreated LIMIT {1})", + pagingWhereText, + startIndex.ToString(_usCulture))); + } - var whereText = 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; + cmd.CommandText += whereText; - cmd.CommandText += " ORDER BY DateCreated"; + cmd.CommandText += " ORDER BY DateCreated"; - if (query.Limit.HasValue) - { - cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture); - } + if (query.Limit.HasValue) + { + cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture); + } - cmd.CommandText += "; select count (Id) from AccessTokens" + whereTextWithoutPaging; + cmd.CommandText += "; select count (Id) from AccessTokens" + whereTextWithoutPaging; - var list = new List(); - var count = 0; + var list = new List(); + var count = 0; - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) - { - while (reader.Read()) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) { - list.Add(Get(reader)); + while (reader.Read()) + { + list.Add(Get(reader)); + } + + if (reader.NextResult() && reader.Read()) + { + count = reader.GetInt32(0); + } } - if (reader.NextResult() && reader.Read()) + return new QueryResult() { - count = reader.GetInt32(0); - } + Items = list.ToArray(), + TotalRecordCount = count + }; } - - return new QueryResult() - { - Items = list.ToArray(), - TotalRecordCount = count - }; } } @@ -256,24 +252,27 @@ namespace MediaBrowser.Server.Implementations.Security throw new ArgumentNullException("id"); } - var guid = new Guid(id); - - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = BaseSelectText + " where Id=@Id"; - - cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid; + var guid = new Guid(id); - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) + using (var cmd = connection.CreateCommand()) { - if (reader.Read()) + cmd.CommandText = BaseSelectText + " where Id=@Id"; + + cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) { - return Get(reader); + if (reader.Read()) + { + return Get(reader); + } } } - } - return null; + return null; + } } private AuthenticationInfo Get(IDataReader reader) @@ -319,19 +318,5 @@ namespace MediaBrowser.Server.Implementations.Security return info; } - - protected override void CloseConnection() - { - if (_connection != null) - { - if (_connection.IsOpen()) - { - _connection.Close(); - } - - _connection.Dispose(); - _connection = null; - } - } } } diff --git a/MediaBrowser.Server.Implementations/Social/SharingRepository.cs b/MediaBrowser.Server.Implementations/Social/SharingRepository.cs index 317743eb1b..8a895037e7 100644 --- a/MediaBrowser.Server.Implementations/Social/SharingRepository.cs +++ b/MediaBrowser.Server.Implementations/Social/SharingRepository.cs @@ -12,27 +12,21 @@ namespace MediaBrowser.Server.Implementations.Social { public class SharingRepository : BaseSqliteRepository { - private IDbConnection _connection; - private IDbCommand _saveShareCommand; - private readonly IApplicationPaths _appPaths; - - public SharingRepository(ILogManager logManager, IApplicationPaths appPaths) - : base(logManager) + public SharingRepository(ILogManager logManager, IApplicationPaths appPaths, IDbConnector dbConnector) + : base(logManager, dbConnector) { - _appPaths = appPaths; + DbFilePath = Path.Combine(appPaths.DataPath, "shares.db"); } /// /// Opens the connection to the database /// /// Task. - public async Task Initialize(IDbConnector dbConnector) + public async Task Initialize() { - var dbFile = Path.Combine(_appPaths.DataPath, "shares.db"); - - _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false); - - string[] queries = { + using (var connection = await CreateConnection().ConfigureAwait(false)) + { + string[] queries = { "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)", @@ -43,23 +37,8 @@ namespace MediaBrowser.Server.Implementations.Social "pragma shrink_memory" }; - _connection.RunQueries(queries, Logger); - - PrepareStatements(); - } - - /// - /// Prepares the statements. - /// - private void PrepareStatements() - { - _saveShareCommand = _connection.CreateCommand(); - _saveShareCommand.CommandText = "replace into Shares (Id, ItemId, UserId, ExpirationDate) values (@Id, @ItemId, @UserId, @ExpirationDate)"; - - _saveShareCommand.Parameters.Add(_saveShareCommand, "@Id"); - _saveShareCommand.Parameters.Add(_saveShareCommand, "@ItemId"); - _saveShareCommand.Parameters.Add(_saveShareCommand, "@UserId"); - _saveShareCommand.Parameters.Add(_saveShareCommand, "@ExpirationDate"); + connection.RunQueries(queries, Logger); + } } public async Task CreateShare(SocialShareInfo info) @@ -77,53 +56,62 @@ namespace MediaBrowser.Server.Implementations.Social cancellationToken.ThrowIfCancellationRequested(); - await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); - - IDbTransaction transaction = null; - - try + using (var connection = await CreateConnection().ConfigureAwait(false)) { - transaction = _connection.BeginTransaction(); - - _saveShareCommand.GetParameter(0).Value = new Guid(info.Id); - _saveShareCommand.GetParameter(1).Value = info.ItemId; - _saveShareCommand.GetParameter(2).Value = info.UserId; - _saveShareCommand.GetParameter(3).Value = info.ExpirationDate; - - _saveShareCommand.Transaction = transaction; - - _saveShareCommand.ExecuteNonQuery(); - - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + using (var saveShareCommand = connection.CreateCommand()) { - transaction.Rollback(); + saveShareCommand.CommandText = "replace into Shares (Id, ItemId, UserId, ExpirationDate) values (@Id, @ItemId, @UserId, @ExpirationDate)"; + + saveShareCommand.Parameters.Add(saveShareCommand, "@Id"); + saveShareCommand.Parameters.Add(saveShareCommand, "@ItemId"); + saveShareCommand.Parameters.Add(saveShareCommand, "@UserId"); + saveShareCommand.Parameters.Add(saveShareCommand, "@ExpirationDate"); + + IDbTransaction transaction = null; + + try + { + transaction = connection.BeginTransaction(); + + saveShareCommand.GetParameter(0).Value = new Guid(info.Id); + saveShareCommand.GetParameter(1).Value = info.ItemId; + saveShareCommand.GetParameter(2).Value = info.UserId; + saveShareCommand.GetParameter(3).Value = info.ExpirationDate; + + saveShareCommand.Transaction = transaction; + + saveShareCommand.ExecuteNonQuery(); + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save share:", e); + + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + } } - - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save share:", e); - - if (transaction != null) - { - transaction.Rollback(); - } - - throw; - } - finally - { - if (transaction != null) - { - transaction.Dispose(); - } - - WriteLock.Release(); } } @@ -134,20 +122,23 @@ namespace MediaBrowser.Server.Implementations.Social throw new ArgumentNullException("id"); } - var cmd = _connection.CreateCommand(); - cmd.CommandText = "select Id, ItemId, UserId, ExpirationDate from Shares where id = @id"; + using (var connection = CreateConnection(true).Result) + { + var cmd = connection.CreateCommand(); + cmd.CommandText = "select Id, ItemId, UserId, ExpirationDate from Shares where id = @id"; - cmd.Parameters.Add(cmd, "@id", DbType.Guid).Value = new Guid(id); + cmd.Parameters.Add(cmd, "@id", DbType.Guid).Value = new Guid(id); - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) - { - if (reader.Read()) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) { - return GetSocialShareInfo(reader); + if (reader.Read()) + { + return GetSocialShareInfo(reader); + } } - } - return null; + return null; + } } private SocialShareInfo GetSocialShareInfo(IDataReader reader) @@ -164,21 +155,7 @@ namespace MediaBrowser.Server.Implementations.Social public async Task DeleteShare(string id) { - - } - - protected override void CloseConnection() - { - if (_connection != null) - { - if (_connection.IsOpen()) - { - _connection.Close(); - } - _connection.Dispose(); - _connection = null; - } } } } diff --git a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs index 739d1ab6e6..5b623cf2ad 100644 --- a/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs +++ b/MediaBrowser.Server.Implementations/Sync/SyncRepository.cs @@ -18,34 +18,22 @@ namespace MediaBrowser.Server.Implementations.Sync { public class SyncRepository : BaseSqliteRepository, ISyncRepository { - private IDbConnection _connection; private readonly CultureInfo _usCulture = new CultureInfo("en-US"); - private IDbCommand _insertJobCommand; - private IDbCommand _updateJobCommand; - private IDbCommand _deleteJobCommand; - - private IDbCommand _deleteJobItemsCommand; - private IDbCommand _insertJobItemCommand; - private IDbCommand _updateJobItemCommand; - private readonly IJsonSerializer _json; - private readonly IServerApplicationPaths _appPaths; - public SyncRepository(ILogManager logManager, IJsonSerializer json, IServerApplicationPaths appPaths) - : base(logManager) + public SyncRepository(ILogManager logManager, IJsonSerializer json, IServerApplicationPaths appPaths, IDbConnector connector) + : base(logManager, connector) { _json = json; - _appPaths = appPaths; + DbFilePath = Path.Combine(appPaths.DataPath, "sync14.db"); } - public async Task Initialize(IDbConnector dbConnector) + public async Task Initialize() { - var dbFile = Path.Combine(_appPaths.DataPath, "sync14.db"); - - _connection = await dbConnector.Connect(dbFile).ConfigureAwait(false); - - string[] queries = { + using (var connection = await CreateConnection().ConfigureAwait(false)) + { + string[] queries = { "create table if not exists SyncJobs (Id GUID PRIMARY KEY, TargetId TEXT NOT NULL, Name TEXT NOT NULL, Profile TEXT, Quality TEXT, Bitrate INT, Status TEXT NOT NULL, Progress FLOAT, UserId TEXT NOT NULL, ItemIds TEXT NOT NULL, Category TEXT, ParentId TEXT, UnwatchedOnly BIT, ItemLimit INT, SyncNewContent BIT, DateCreated DateTime, DateLastModified DateTime, ItemCount int)", "create index if not exists idx_SyncJobs on SyncJobs(Id)", @@ -61,114 +49,12 @@ namespace MediaBrowser.Server.Implementations.Sync "pragma shrink_memory" }; - _connection.RunQueries(queries, Logger); - - _connection.AddColumn(Logger, "SyncJobs", "Profile", "TEXT"); - _connection.AddColumn(Logger, "SyncJobs", "Bitrate", "INT"); - _connection.AddColumn(Logger, "SyncJobItems", "ItemDateModifiedTicks", "BIGINT"); + connection.RunQueries(queries, Logger); - PrepareStatements(); - } - - private void PrepareStatements() - { - // _deleteJobCommand - _deleteJobCommand = _connection.CreateCommand(); - _deleteJobCommand.CommandText = "delete from SyncJobs where Id=@Id"; - _deleteJobCommand.Parameters.Add(_deleteJobCommand, "@Id"); - - // _deleteJobItemsCommand - _deleteJobItemsCommand = _connection.CreateCommand(); - _deleteJobItemsCommand.CommandText = "delete from SyncJobItems where JobId=@JobId"; - _deleteJobItemsCommand.Parameters.Add(_deleteJobItemsCommand, "@JobId"); - - // _insertJobCommand - _insertJobCommand = _connection.CreateCommand(); - _insertJobCommand.CommandText = "insert into SyncJobs (Id, TargetId, Name, Profile, Quality, Bitrate, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount) values (@Id, @TargetId, @Name, @Profile, @Quality, @Bitrate, @Status, @Progress, @UserId, @ItemIds, @Category, @ParentId, @UnwatchedOnly, @ItemLimit, @SyncNewContent, @DateCreated, @DateLastModified, @ItemCount)"; - - _insertJobCommand.Parameters.Add(_insertJobCommand, "@Id"); - _insertJobCommand.Parameters.Add(_insertJobCommand, "@TargetId"); - _insertJobCommand.Parameters.Add(_insertJobCommand, "@Name"); - _insertJobCommand.Parameters.Add(_insertJobCommand, "@Profile"); - _insertJobCommand.Parameters.Add(_insertJobCommand, "@Quality"); - _insertJobCommand.Parameters.Add(_insertJobCommand, "@Bitrate"); - _insertJobCommand.Parameters.Add(_insertJobCommand, "@Status"); - _insertJobCommand.Parameters.Add(_insertJobCommand, "@Progress"); - _insertJobCommand.Parameters.Add(_insertJobCommand, "@UserId"); - _insertJobCommand.Parameters.Add(_insertJobCommand, "@ItemIds"); - _insertJobCommand.Parameters.Add(_insertJobCommand, "@Category"); - _insertJobCommand.Parameters.Add(_insertJobCommand, "@ParentId"); - _insertJobCommand.Parameters.Add(_insertJobCommand, "@UnwatchedOnly"); - _insertJobCommand.Parameters.Add(_insertJobCommand, "@ItemLimit"); - _insertJobCommand.Parameters.Add(_insertJobCommand, "@SyncNewContent"); - _insertJobCommand.Parameters.Add(_insertJobCommand, "@DateCreated"); - _insertJobCommand.Parameters.Add(_insertJobCommand, "@DateLastModified"); - _insertJobCommand.Parameters.Add(_insertJobCommand, "@ItemCount"); - - // _updateJobCommand - _updateJobCommand = _connection.CreateCommand(); - _updateJobCommand.CommandText = "update SyncJobs set TargetId=@TargetId,Name=@Name,Profile=@Profile,Quality=@Quality,Bitrate=@Bitrate,Status=@Status,Progress=@Progress,UserId=@UserId,ItemIds=@ItemIds,Category=@Category,ParentId=@ParentId,UnwatchedOnly=@UnwatchedOnly,ItemLimit=@ItemLimit,SyncNewContent=@SyncNewContent,DateCreated=@DateCreated,DateLastModified=@DateLastModified,ItemCount=@ItemCount where Id=@Id"; - - _updateJobCommand.Parameters.Add(_updateJobCommand, "@Id"); - _updateJobCommand.Parameters.Add(_updateJobCommand, "@TargetId"); - _updateJobCommand.Parameters.Add(_updateJobCommand, "@Name"); - _updateJobCommand.Parameters.Add(_updateJobCommand, "@Profile"); - _updateJobCommand.Parameters.Add(_updateJobCommand, "@Quality"); - _updateJobCommand.Parameters.Add(_updateJobCommand, "@Bitrate"); - _updateJobCommand.Parameters.Add(_updateJobCommand, "@Status"); - _updateJobCommand.Parameters.Add(_updateJobCommand, "@Progress"); - _updateJobCommand.Parameters.Add(_updateJobCommand, "@UserId"); - _updateJobCommand.Parameters.Add(_updateJobCommand, "@ItemIds"); - _updateJobCommand.Parameters.Add(_updateJobCommand, "@Category"); - _updateJobCommand.Parameters.Add(_updateJobCommand, "@ParentId"); - _updateJobCommand.Parameters.Add(_updateJobCommand, "@UnwatchedOnly"); - _updateJobCommand.Parameters.Add(_updateJobCommand, "@ItemLimit"); - _updateJobCommand.Parameters.Add(_updateJobCommand, "@SyncNewContent"); - _updateJobCommand.Parameters.Add(_updateJobCommand, "@DateCreated"); - _updateJobCommand.Parameters.Add(_updateJobCommand, "@DateLastModified"); - _updateJobCommand.Parameters.Add(_updateJobCommand, "@ItemCount"); - - // _insertJobItemCommand - _insertJobItemCommand = _connection.CreateCommand(); - _insertJobItemCommand.CommandText = "insert into SyncJobItems (Id, ItemId, ItemName, MediaSourceId, JobId, TemporaryPath, OutputPath, Status, TargetId, DateCreated, Progress, AdditionalFiles, MediaSource, IsMarkedForRemoval, JobItemIndex, ItemDateModifiedTicks) values (@Id, @ItemId, @ItemName, @MediaSourceId, @JobId, @TemporaryPath, @OutputPath, @Status, @TargetId, @DateCreated, @Progress, @AdditionalFiles, @MediaSource, @IsMarkedForRemoval, @JobItemIndex, @ItemDateModifiedTicks)"; - - _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@Id"); - _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@ItemId"); - _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@ItemName"); - _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@MediaSourceId"); - _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@JobId"); - _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@TemporaryPath"); - _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@OutputPath"); - _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@Status"); - _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@TargetId"); - _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@DateCreated"); - _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@Progress"); - _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@AdditionalFiles"); - _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@MediaSource"); - _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@IsMarkedForRemoval"); - _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@JobItemIndex"); - _insertJobItemCommand.Parameters.Add(_insertJobItemCommand, "@ItemDateModifiedTicks"); - - // _updateJobItemCommand - _updateJobItemCommand = _connection.CreateCommand(); - _updateJobItemCommand.CommandText = "update SyncJobItems set ItemId=@ItemId,ItemName=@ItemName,MediaSourceId=@MediaSourceId,JobId=@JobId,TemporaryPath=@TemporaryPath,OutputPath=@OutputPath,Status=@Status,TargetId=@TargetId,DateCreated=@DateCreated,Progress=@Progress,AdditionalFiles=@AdditionalFiles,MediaSource=@MediaSource,IsMarkedForRemoval=@IsMarkedForRemoval,JobItemIndex=@JobItemIndex,ItemDateModifiedTicks=@ItemDateModifiedTicks where Id=@Id"; - - _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@Id"); - _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@ItemId"); - _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@ItemName"); - _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@MediaSourceId"); - _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@JobId"); - _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@TemporaryPath"); - _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@OutputPath"); - _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@Status"); - _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@TargetId"); - _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@DateCreated"); - _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@Progress"); - _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@AdditionalFiles"); - _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@MediaSource"); - _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@IsMarkedForRemoval"); - _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@JobItemIndex"); - _updateJobItemCommand.Parameters.Add(_updateJobItemCommand, "@ItemDateModifiedTicks"); + connection.AddColumn(Logger, "SyncJobs", "Profile", "TEXT"); + connection.AddColumn(Logger, "SyncJobs", "Bitrate", "INT"); + connection.AddColumn(Logger, "SyncJobItems", "ItemDateModifiedTicks", "BIGINT"); + } } private const string BaseJobSelectText = "select Id, TargetId, Name, Profile, Quality, Bitrate, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount from SyncJobs"; @@ -182,7 +68,7 @@ namespace MediaBrowser.Server.Implementations.Sync } CheckDisposed(); - + var guid = new Guid(id); if (guid == Guid.Empty) @@ -190,22 +76,25 @@ namespace MediaBrowser.Server.Implementations.Sync throw new ArgumentNullException("id"); } - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = BaseJobSelectText + " where Id=@Id"; + using (var cmd = connection.CreateCommand()) + { + cmd.CommandText = BaseJobSelectText + " where Id=@Id"; - cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid; + cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid; - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) - { - if (reader.Read()) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) { - return GetJob(reader); + if (reader.Read()) + { + return GetJob(reader); + } } } - } - return null; + return null; + } } private SyncJob GetJob(IDataReader reader) @@ -283,15 +172,15 @@ namespace MediaBrowser.Server.Implementations.Sync public Task Create(SyncJob job) { - return InsertOrUpdate(job, _insertJobCommand); + return InsertOrUpdate(job, true); } public Task Update(SyncJob job) { - return InsertOrUpdate(job, _updateJobCommand); + return InsertOrUpdate(job, false); } - private async Task InsertOrUpdate(SyncJob job, IDbCommand cmd) + private async Task InsertOrUpdate(SyncJob job, bool insert) { if (job == null) { @@ -299,70 +188,119 @@ namespace MediaBrowser.Server.Implementations.Sync } CheckDisposed(); - - await WriteLock.WaitAsync().ConfigureAwait(false); - - IDbTransaction transaction = null; - try + using (var connection = await CreateConnection().ConfigureAwait(false)) { - transaction = _connection.BeginTransaction(); - - var index = 0; - - cmd.GetParameter(index++).Value = new Guid(job.Id); - cmd.GetParameter(index++).Value = job.TargetId; - cmd.GetParameter(index++).Value = job.Name; - cmd.GetParameter(index++).Value = job.Profile; - cmd.GetParameter(index++).Value = job.Quality; - cmd.GetParameter(index++).Value = job.Bitrate; - cmd.GetParameter(index++).Value = job.Status.ToString(); - cmd.GetParameter(index++).Value = job.Progress; - cmd.GetParameter(index++).Value = job.UserId; - cmd.GetParameter(index++).Value = string.Join(",", job.RequestedItemIds.ToArray()); - cmd.GetParameter(index++).Value = job.Category; - cmd.GetParameter(index++).Value = job.ParentId; - cmd.GetParameter(index++).Value = job.UnwatchedOnly; - cmd.GetParameter(index++).Value = job.ItemLimit; - cmd.GetParameter(index++).Value = job.SyncNewContent; - cmd.GetParameter(index++).Value = job.DateCreated; - cmd.GetParameter(index++).Value = job.DateLastModified; - cmd.GetParameter(index++).Value = job.ItemCount; - - cmd.Transaction = transaction; + using (var cmd = connection.CreateCommand()) + { + if (insert) + { + cmd.CommandText = "insert into SyncJobs (Id, TargetId, Name, Profile, Quality, Bitrate, Status, Progress, UserId, ItemIds, Category, ParentId, UnwatchedOnly, ItemLimit, SyncNewContent, DateCreated, DateLastModified, ItemCount) values (@Id, @TargetId, @Name, @Profile, @Quality, @Bitrate, @Status, @Progress, @UserId, @ItemIds, @Category, @ParentId, @UnwatchedOnly, @ItemLimit, @SyncNewContent, @DateCreated, @DateLastModified, @ItemCount)"; + + cmd.Parameters.Add(cmd, "@Id"); + cmd.Parameters.Add(cmd, "@TargetId"); + cmd.Parameters.Add(cmd, "@Name"); + cmd.Parameters.Add(cmd, "@Profile"); + cmd.Parameters.Add(cmd, "@Quality"); + cmd.Parameters.Add(cmd, "@Bitrate"); + cmd.Parameters.Add(cmd, "@Status"); + cmd.Parameters.Add(cmd, "@Progress"); + cmd.Parameters.Add(cmd, "@UserId"); + cmd.Parameters.Add(cmd, "@ItemIds"); + cmd.Parameters.Add(cmd, "@Category"); + cmd.Parameters.Add(cmd, "@ParentId"); + cmd.Parameters.Add(cmd, "@UnwatchedOnly"); + cmd.Parameters.Add(cmd, "@ItemLimit"); + cmd.Parameters.Add(cmd, "@SyncNewContent"); + cmd.Parameters.Add(cmd, "@DateCreated"); + cmd.Parameters.Add(cmd, "@DateLastModified"); + cmd.Parameters.Add(cmd, "@ItemCount"); + } + else + { + cmd.CommandText = "update SyncJobs set TargetId=@TargetId,Name=@Name,Profile=@Profile,Quality=@Quality,Bitrate=@Bitrate,Status=@Status,Progress=@Progress,UserId=@UserId,ItemIds=@ItemIds,Category=@Category,ParentId=@ParentId,UnwatchedOnly=@UnwatchedOnly,ItemLimit=@ItemLimit,SyncNewContent=@SyncNewContent,DateCreated=@DateCreated,DateLastModified=@DateLastModified,ItemCount=@ItemCount where Id=@Id"; + + cmd.Parameters.Add(cmd, "@Id"); + cmd.Parameters.Add(cmd, "@TargetId"); + cmd.Parameters.Add(cmd, "@Name"); + cmd.Parameters.Add(cmd, "@Profile"); + cmd.Parameters.Add(cmd, "@Quality"); + cmd.Parameters.Add(cmd, "@Bitrate"); + cmd.Parameters.Add(cmd, "@Status"); + cmd.Parameters.Add(cmd, "@Progress"); + cmd.Parameters.Add(cmd, "@UserId"); + cmd.Parameters.Add(cmd, "@ItemIds"); + cmd.Parameters.Add(cmd, "@Category"); + cmd.Parameters.Add(cmd, "@ParentId"); + cmd.Parameters.Add(cmd, "@UnwatchedOnly"); + cmd.Parameters.Add(cmd, "@ItemLimit"); + cmd.Parameters.Add(cmd, "@SyncNewContent"); + cmd.Parameters.Add(cmd, "@DateCreated"); + cmd.Parameters.Add(cmd, "@DateLastModified"); + cmd.Parameters.Add(cmd, "@ItemCount"); + } - cmd.ExecuteNonQuery(); + IDbTransaction transaction = null; - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) - { - transaction.Rollback(); - } + try + { + transaction = connection.BeginTransaction(); + + var index = 0; + + cmd.GetParameter(index++).Value = new Guid(job.Id); + cmd.GetParameter(index++).Value = job.TargetId; + cmd.GetParameter(index++).Value = job.Name; + cmd.GetParameter(index++).Value = job.Profile; + cmd.GetParameter(index++).Value = job.Quality; + cmd.GetParameter(index++).Value = job.Bitrate; + cmd.GetParameter(index++).Value = job.Status.ToString(); + cmd.GetParameter(index++).Value = job.Progress; + cmd.GetParameter(index++).Value = job.UserId; + cmd.GetParameter(index++).Value = string.Join(",", job.RequestedItemIds.ToArray()); + cmd.GetParameter(index++).Value = job.Category; + cmd.GetParameter(index++).Value = job.ParentId; + cmd.GetParameter(index++).Value = job.UnwatchedOnly; + cmd.GetParameter(index++).Value = job.ItemLimit; + cmd.GetParameter(index++).Value = job.SyncNewContent; + cmd.GetParameter(index++).Value = job.DateCreated; + cmd.GetParameter(index++).Value = job.DateLastModified; + cmd.GetParameter(index++).Value = job.ItemCount; + + cmd.Transaction = transaction; + + cmd.ExecuteNonQuery(); + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) + { + transaction.Rollback(); + } - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save record:", e); + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save record:", e); - if (transaction != null) - { - transaction.Rollback(); - } + if (transaction != null) + { + transaction.Rollback(); + } - throw; - } - finally - { - if (transaction != null) - { - transaction.Dispose(); + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + } } - - WriteLock.Release(); } } @@ -374,56 +312,66 @@ namespace MediaBrowser.Server.Implementations.Sync } CheckDisposed(); - - await WriteLock.WaitAsync().ConfigureAwait(false); - IDbTransaction transaction = null; - - try - { - transaction = _connection.BeginTransaction(); - - var index = 0; - - _deleteJobCommand.GetParameter(index++).Value = new Guid(id); - _deleteJobCommand.Transaction = transaction; - _deleteJobCommand.ExecuteNonQuery(); - - index = 0; - _deleteJobItemsCommand.GetParameter(index++).Value = id; - _deleteJobItemsCommand.Transaction = transaction; - _deleteJobItemsCommand.ExecuteNonQuery(); - - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) - { - transaction.Rollback(); - } - - throw; - } - catch (Exception e) + using (var connection = await CreateConnection().ConfigureAwait(false)) { - Logger.ErrorException("Failed to save record:", e); - - if (transaction != null) + using (var deleteJobCommand = connection.CreateCommand()) { - transaction.Rollback(); - } - - throw; - } - finally - { - if (transaction != null) - { - transaction.Dispose(); + using (var deleteJobItemsCommand = connection.CreateCommand()) + { + IDbTransaction transaction = null; + + try + { + // _deleteJobCommand + deleteJobCommand.CommandText = "delete from SyncJobs where Id=@Id"; + deleteJobCommand.Parameters.Add(deleteJobCommand, "@Id"); + + transaction = connection.BeginTransaction(); + + deleteJobCommand.GetParameter(0).Value = new Guid(id); + deleteJobCommand.Transaction = transaction; + deleteJobCommand.ExecuteNonQuery(); + + // _deleteJobItemsCommand + deleteJobItemsCommand.CommandText = "delete from SyncJobItems where JobId=@JobId"; + deleteJobItemsCommand.Parameters.Add(deleteJobItemsCommand, "@JobId"); + + deleteJobItemsCommand.GetParameter(0).Value = id; + deleteJobItemsCommand.Transaction = transaction; + deleteJobItemsCommand.ExecuteNonQuery(); + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save record:", e); + + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + } + } } - - WriteLock.Release(); } } @@ -435,83 +383,86 @@ namespace MediaBrowser.Server.Implementations.Sync } CheckDisposed(); - - using (var cmd = _connection.CreateCommand()) + + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = BaseJobSelectText; + using (var cmd = connection.CreateCommand()) + { + cmd.CommandText = BaseJobSelectText; - var whereClauses = new List(); + var whereClauses = new List(); - if (query.Statuses.Length > 0) - { - var statuses = string.Join(",", query.Statuses.Select(i => "'" + i.ToString() + "'").ToArray()); + if (query.Statuses.Length > 0) + { + var statuses = string.Join(",", query.Statuses.Select(i => "'" + i.ToString() + "'").ToArray()); - whereClauses.Add(string.Format("Status in ({0})", statuses)); - } - if (!string.IsNullOrWhiteSpace(query.TargetId)) - { - whereClauses.Add("TargetId=@TargetId"); - cmd.Parameters.Add(cmd, "@TargetId", DbType.String).Value = query.TargetId; - } - if (!string.IsNullOrWhiteSpace(query.UserId)) - { - whereClauses.Add("UserId=@UserId"); - cmd.Parameters.Add(cmd, "@UserId", DbType.String).Value = query.UserId; - } - if (query.SyncNewContent.HasValue) - { - whereClauses.Add("SyncNewContent=@SyncNewContent"); - cmd.Parameters.Add(cmd, "@SyncNewContent", DbType.Boolean).Value = query.SyncNewContent.Value; - } + whereClauses.Add(string.Format("Status in ({0})", statuses)); + } + if (!string.IsNullOrWhiteSpace(query.TargetId)) + { + whereClauses.Add("TargetId=@TargetId"); + cmd.Parameters.Add(cmd, "@TargetId", DbType.String).Value = query.TargetId; + } + if (!string.IsNullOrWhiteSpace(query.UserId)) + { + whereClauses.Add("UserId=@UserId"); + cmd.Parameters.Add(cmd, "@UserId", DbType.String).Value = query.UserId; + } + if (query.SyncNewContent.HasValue) + { + whereClauses.Add("SyncNewContent=@SyncNewContent"); + cmd.Parameters.Add(cmd, "@SyncNewContent", DbType.Boolean).Value = query.SyncNewContent.Value; + } - cmd.CommandText += " mainTable"; + cmd.CommandText += " mainTable"; - var whereTextWithoutPaging = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + var whereTextWithoutPaging = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); - var startIndex = query.StartIndex ?? 0; - if (startIndex > 0) - { - whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM SyncJobs ORDER BY (Select Max(DateLastModified) from SyncJobs where TargetId=mainTable.TargetId) DESC, DateLastModified DESC LIMIT {0})", - startIndex.ToString(_usCulture))); - } + var startIndex = query.StartIndex ?? 0; + if (startIndex > 0) + { + whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM SyncJobs ORDER BY (Select Max(DateLastModified) from SyncJobs where TargetId=mainTable.TargetId) DESC, DateLastModified DESC LIMIT {0})", + startIndex.ToString(_usCulture))); + } - if (whereClauses.Count > 0) - { - cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); - } + if (whereClauses.Count > 0) + { + cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); + } - cmd.CommandText += " ORDER BY (Select Max(DateLastModified) from SyncJobs where TargetId=mainTable.TargetId) DESC, DateLastModified DESC"; + cmd.CommandText += " ORDER BY (Select Max(DateLastModified) from SyncJobs where TargetId=mainTable.TargetId) DESC, DateLastModified DESC"; - if (query.Limit.HasValue) - { - cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture); - } + if (query.Limit.HasValue) + { + cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture); + } - cmd.CommandText += "; select count (Id) from SyncJobs" + whereTextWithoutPaging; + cmd.CommandText += "; select count (Id) from SyncJobs" + whereTextWithoutPaging; - var list = new List(); - var count = 0; + var list = new List(); + var count = 0; - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) - { - while (reader.Read()) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) { - list.Add(GetJob(reader)); + while (reader.Read()) + { + list.Add(GetJob(reader)); + } + + if (reader.NextResult() && reader.Read()) + { + count = reader.GetInt32(0); + } } - if (reader.NextResult() && reader.Read()) + return new QueryResult() { - count = reader.GetInt32(0); - } + Items = list.ToArray(), + TotalRecordCount = count + }; } - - return new QueryResult() - { - Items = list.ToArray(), - TotalRecordCount = count - }; } } @@ -523,25 +474,28 @@ namespace MediaBrowser.Server.Implementations.Sync } CheckDisposed(); - + var guid = new Guid(id); - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = BaseJobItemSelectText + " where Id=@Id"; + using (var cmd = connection.CreateCommand()) + { + cmd.CommandText = BaseJobItemSelectText + " where Id=@Id"; - cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid; + cmd.Parameters.Add(cmd, "@Id", DbType.Guid).Value = guid; - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) - { - if (reader.Read()) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult | CommandBehavior.SingleRow)) { - return GetJobItem(reader); + if (reader.Read()) + { + return GetJobItem(reader); + } } } - } - return null; + return null; + } } private QueryResult GetJobItemReader(SyncJobItemQuery query, string baseSelectText, Func itemFactory) @@ -551,81 +505,84 @@ namespace MediaBrowser.Server.Implementations.Sync throw new ArgumentNullException("query"); } - using (var cmd = _connection.CreateCommand()) + using (var connection = CreateConnection(true).Result) { - cmd.CommandText = baseSelectText; + using (var cmd = connection.CreateCommand()) + { + cmd.CommandText = baseSelectText; - var whereClauses = new List(); + var whereClauses = new List(); - if (!string.IsNullOrWhiteSpace(query.JobId)) - { - whereClauses.Add("JobId=@JobId"); - cmd.Parameters.Add(cmd, "@JobId", DbType.String).Value = query.JobId; - } - if (!string.IsNullOrWhiteSpace(query.ItemId)) - { - whereClauses.Add("ItemId=@ItemId"); - cmd.Parameters.Add(cmd, "@ItemId", DbType.String).Value = query.ItemId; - } - if (!string.IsNullOrWhiteSpace(query.TargetId)) - { - whereClauses.Add("TargetId=@TargetId"); - cmd.Parameters.Add(cmd, "@TargetId", DbType.String).Value = query.TargetId; - } + if (!string.IsNullOrWhiteSpace(query.JobId)) + { + whereClauses.Add("JobId=@JobId"); + cmd.Parameters.Add(cmd, "@JobId", DbType.String).Value = query.JobId; + } + if (!string.IsNullOrWhiteSpace(query.ItemId)) + { + whereClauses.Add("ItemId=@ItemId"); + cmd.Parameters.Add(cmd, "@ItemId", DbType.String).Value = query.ItemId; + } + if (!string.IsNullOrWhiteSpace(query.TargetId)) + { + whereClauses.Add("TargetId=@TargetId"); + cmd.Parameters.Add(cmd, "@TargetId", DbType.String).Value = query.TargetId; + } - if (query.Statuses.Length > 0) - { - var statuses = string.Join(",", query.Statuses.Select(i => "'" + i.ToString() + "'").ToArray()); + if (query.Statuses.Length > 0) + { + var statuses = string.Join(",", query.Statuses.Select(i => "'" + i.ToString() + "'").ToArray()); - whereClauses.Add(string.Format("Status in ({0})", statuses)); - } + whereClauses.Add(string.Format("Status in ({0})", statuses)); + } - var whereTextWithoutPaging = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + var whereTextWithoutPaging = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); - var startIndex = query.StartIndex ?? 0; - if (startIndex > 0) - { - whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM SyncJobItems ORDER BY JobItemIndex, DateCreated LIMIT {0})", - startIndex.ToString(_usCulture))); - } + var startIndex = query.StartIndex ?? 0; + if (startIndex > 0) + { + whereClauses.Add(string.Format("Id NOT IN (SELECT Id FROM SyncJobItems ORDER BY JobItemIndex, DateCreated LIMIT {0})", + startIndex.ToString(_usCulture))); + } - if (whereClauses.Count > 0) - { - cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); - } + if (whereClauses.Count > 0) + { + cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); + } - cmd.CommandText += " ORDER BY JobItemIndex, DateCreated"; + cmd.CommandText += " ORDER BY JobItemIndex, DateCreated"; - if (query.Limit.HasValue) - { - cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture); - } + if (query.Limit.HasValue) + { + cmd.CommandText += " LIMIT " + query.Limit.Value.ToString(_usCulture); + } - cmd.CommandText += "; select count (Id) from SyncJobItems" + whereTextWithoutPaging; + cmd.CommandText += "; select count (Id) from SyncJobItems" + whereTextWithoutPaging; - var list = new List(); - var count = 0; + var list = new List(); + var count = 0; - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) - { - while (reader.Read()) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) { - list.Add(itemFactory(reader)); + while (reader.Read()) + { + list.Add(itemFactory(reader)); + } + + if (reader.NextResult() && reader.Read()) + { + count = reader.GetInt32(0); + } } - if (reader.NextResult() && reader.Read()) + return new QueryResult() { - count = reader.GetInt32(0); - } + Items = list.ToArray(), + TotalRecordCount = count + }; } - - return new QueryResult() - { - Items = list.ToArray(), - TotalRecordCount = count - }; } } @@ -641,15 +598,15 @@ namespace MediaBrowser.Server.Implementations.Sync public Task Create(SyncJobItem jobItem) { - return InsertOrUpdate(jobItem, _insertJobItemCommand); + return InsertOrUpdate(jobItem, true); } public Task Update(SyncJobItem jobItem) { - return InsertOrUpdate(jobItem, _updateJobItemCommand); + return InsertOrUpdate(jobItem, false); } - private async Task InsertOrUpdate(SyncJobItem jobItem, IDbCommand cmd) + private async Task InsertOrUpdate(SyncJobItem jobItem, bool insert) { if (jobItem == null) { @@ -657,68 +614,114 @@ namespace MediaBrowser.Server.Implementations.Sync } CheckDisposed(); - - await WriteLock.WaitAsync().ConfigureAwait(false); - IDbTransaction transaction = null; - - try + using (var connection = await CreateConnection().ConfigureAwait(false)) { - transaction = _connection.BeginTransaction(); - - var index = 0; - - cmd.GetParameter(index++).Value = new Guid(jobItem.Id); - cmd.GetParameter(index++).Value = jobItem.ItemId; - cmd.GetParameter(index++).Value = jobItem.ItemName; - cmd.GetParameter(index++).Value = jobItem.MediaSourceId; - cmd.GetParameter(index++).Value = jobItem.JobId; - cmd.GetParameter(index++).Value = jobItem.TemporaryPath; - cmd.GetParameter(index++).Value = jobItem.OutputPath; - cmd.GetParameter(index++).Value = jobItem.Status.ToString(); - cmd.GetParameter(index++).Value = jobItem.TargetId; - cmd.GetParameter(index++).Value = jobItem.DateCreated; - cmd.GetParameter(index++).Value = jobItem.Progress; - cmd.GetParameter(index++).Value = _json.SerializeToString(jobItem.AdditionalFiles); - cmd.GetParameter(index++).Value = jobItem.MediaSource == null ? null : _json.SerializeToString(jobItem.MediaSource); - cmd.GetParameter(index++).Value = jobItem.IsMarkedForRemoval; - cmd.GetParameter(index++).Value = jobItem.JobItemIndex; - cmd.GetParameter(index++).Value = jobItem.ItemDateModifiedTicks; - - cmd.Transaction = transaction; + using (var cmd = connection.CreateCommand()) + { + if (insert) + { + cmd.CommandText = "insert into SyncJobItems (Id, ItemId, ItemName, MediaSourceId, JobId, TemporaryPath, OutputPath, Status, TargetId, DateCreated, Progress, AdditionalFiles, MediaSource, IsMarkedForRemoval, JobItemIndex, ItemDateModifiedTicks) values (@Id, @ItemId, @ItemName, @MediaSourceId, @JobId, @TemporaryPath, @OutputPath, @Status, @TargetId, @DateCreated, @Progress, @AdditionalFiles, @MediaSource, @IsMarkedForRemoval, @JobItemIndex, @ItemDateModifiedTicks)"; + + cmd.Parameters.Add(cmd, "@Id"); + cmd.Parameters.Add(cmd, "@ItemId"); + cmd.Parameters.Add(cmd, "@ItemName"); + cmd.Parameters.Add(cmd, "@MediaSourceId"); + cmd.Parameters.Add(cmd, "@JobId"); + cmd.Parameters.Add(cmd, "@TemporaryPath"); + cmd.Parameters.Add(cmd, "@OutputPath"); + cmd.Parameters.Add(cmd, "@Status"); + cmd.Parameters.Add(cmd, "@TargetId"); + cmd.Parameters.Add(cmd, "@DateCreated"); + cmd.Parameters.Add(cmd, "@Progress"); + cmd.Parameters.Add(cmd, "@AdditionalFiles"); + cmd.Parameters.Add(cmd, "@MediaSource"); + cmd.Parameters.Add(cmd, "@IsMarkedForRemoval"); + cmd.Parameters.Add(cmd, "@JobItemIndex"); + cmd.Parameters.Add(cmd, "@ItemDateModifiedTicks"); + } + else + { + // cmd + cmd.CommandText = "update SyncJobItems set ItemId=@ItemId,ItemName=@ItemName,MediaSourceId=@MediaSourceId,JobId=@JobId,TemporaryPath=@TemporaryPath,OutputPath=@OutputPath,Status=@Status,TargetId=@TargetId,DateCreated=@DateCreated,Progress=@Progress,AdditionalFiles=@AdditionalFiles,MediaSource=@MediaSource,IsMarkedForRemoval=@IsMarkedForRemoval,JobItemIndex=@JobItemIndex,ItemDateModifiedTicks=@ItemDateModifiedTicks where Id=@Id"; + + cmd.Parameters.Add(cmd, "@Id"); + cmd.Parameters.Add(cmd, "@ItemId"); + cmd.Parameters.Add(cmd, "@ItemName"); + cmd.Parameters.Add(cmd, "@MediaSourceId"); + cmd.Parameters.Add(cmd, "@JobId"); + cmd.Parameters.Add(cmd, "@TemporaryPath"); + cmd.Parameters.Add(cmd, "@OutputPath"); + cmd.Parameters.Add(cmd, "@Status"); + cmd.Parameters.Add(cmd, "@TargetId"); + cmd.Parameters.Add(cmd, "@DateCreated"); + cmd.Parameters.Add(cmd, "@Progress"); + cmd.Parameters.Add(cmd, "@AdditionalFiles"); + cmd.Parameters.Add(cmd, "@MediaSource"); + cmd.Parameters.Add(cmd, "@IsMarkedForRemoval"); + cmd.Parameters.Add(cmd, "@JobItemIndex"); + cmd.Parameters.Add(cmd, "@ItemDateModifiedTicks"); + } - cmd.ExecuteNonQuery(); + IDbTransaction transaction = null; - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) - { - transaction.Rollback(); - } + try + { + transaction = connection.BeginTransaction(); + + var index = 0; + + cmd.GetParameter(index++).Value = new Guid(jobItem.Id); + cmd.GetParameter(index++).Value = jobItem.ItemId; + cmd.GetParameter(index++).Value = jobItem.ItemName; + cmd.GetParameter(index++).Value = jobItem.MediaSourceId; + cmd.GetParameter(index++).Value = jobItem.JobId; + cmd.GetParameter(index++).Value = jobItem.TemporaryPath; + cmd.GetParameter(index++).Value = jobItem.OutputPath; + cmd.GetParameter(index++).Value = jobItem.Status.ToString(); + cmd.GetParameter(index++).Value = jobItem.TargetId; + cmd.GetParameter(index++).Value = jobItem.DateCreated; + cmd.GetParameter(index++).Value = jobItem.Progress; + cmd.GetParameter(index++).Value = _json.SerializeToString(jobItem.AdditionalFiles); + cmd.GetParameter(index++).Value = jobItem.MediaSource == null ? null : _json.SerializeToString(jobItem.MediaSource); + cmd.GetParameter(index++).Value = jobItem.IsMarkedForRemoval; + cmd.GetParameter(index++).Value = jobItem.JobItemIndex; + cmd.GetParameter(index++).Value = jobItem.ItemDateModifiedTicks; + + cmd.Transaction = transaction; + + cmd.ExecuteNonQuery(); + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) + { + transaction.Rollback(); + } - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save record:", e); + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save record:", e); - if (transaction != null) - { - transaction.Rollback(); - } + if (transaction != null) + { + transaction.Rollback(); + } - throw; - } - finally - { - if (transaction != null) - { - transaction.Dispose(); + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + } } - - WriteLock.Release(); } } @@ -809,19 +812,5 @@ namespace MediaBrowser.Server.Implementations.Sync return item; } - - protected override void CloseConnection() - { - if (_connection != null) - { - if (_connection.IsOpen()) - { - _connection.Close(); - } - - _connection.Dispose(); - _connection = null; - } - } } } -- cgit v1.2.3 From da6e94396fb417077010d3a2e5f3282bf06234c3 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 11 Jun 2016 16:12:01 -0400 Subject: update connection pooling --- .../Chapters/IChapterManager.cs | 2 +- .../Persistence/IItemRepository.cs | 4 +- MediaBrowser.Providers/Chapters/ChapterManager.cs | 2 +- .../Activity/ActivityRepository.cs | 7 +- .../Library/LibraryManager.cs | 10 +- .../LiveTv/LiveTvManager.cs | 2 +- .../Notifications/SqliteNotificationsRepository.cs | 7 +- .../Persistence/BaseSqliteRepository.cs | 12 +- .../SqliteDisplayPreferencesRepository.cs | 7 +- .../Persistence/SqliteExtensions.cs | 13 +- .../SqliteFileOrganizationRepository.cs | 7 +- .../Persistence/SqliteItemRepository.cs | 2855 ++++++++++---------- .../Persistence/SqliteUserDataRepository.cs | 7 +- .../Persistence/SqliteUserRepository.cs | 3 - .../Security/AuthenticationRepository.cs | 7 +- .../Social/SharingRepository.cs | 3 - .../Sync/SyncRepository.cs | 3 - 17 files changed, 1533 insertions(+), 1418 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs') 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"); - - _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))"; + 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))"; - 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.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", "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", "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", "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", "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"); - - string[] postQueries = - { + connection.RunQueries(queries, Logger); + + 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", "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", "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", "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", "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"); + + 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(); - - 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; - } + transaction = connection.BeginTransaction(); - _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 + using (var saveItemCommand = connection.CreateCommand()) { - _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 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); - 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.Parameters.Add(saveItemCommand, "@" + i.ToString(CultureInfo.InvariantCulture)); + } + saveItemCommand.CommandText += ")"; - var hasSeries = item as IHasSeries; - if (hasSeries != null) - { - _saveItemCommand.GetParameter(index++).Value = hasSeries.SeriesName; - } - else - { - _saveItemCommand.GetParameter(index++).Value = null; + 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.Transaction = transaction; - - _saveItemCommand.ExecuteNonQuery(); - - if (item.SupportsAncestors) + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) { - UpdateAncestors(item.Id, item.GetAncestorIds().Distinct().ToList(), transaction); + transaction.Rollback(); } - 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); + throw; } - - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + catch (Exception e) { - transaction.Rollback(); - } + Logger.ErrorException("Failed to save items:", e); - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save items:", e); + if (transaction != null) + { + transaction.Rollback(); + } - if (transaction != null) - { - transaction.Rollback(); + throw; } - - throw; - } - finally - { - if (transaction != null) + 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"; + 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; + cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = id; - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) - { - while (reader.Read()) + 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"; + 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; + 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()) + 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,90 +1359,89 @@ 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(); - - // First delete chapters - _deleteChaptersCommand.GetParameter(0).Value = id; + IDbTransaction transaction = null; - _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"); + + 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++; + } + } + } - index++; + transaction.Commit(); } - - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + catch (OperationCanceledException) { - transaction.Rollback(); + if (transaction != null) + { + transaction.Rollback(); + } + + throw; } + catch (Exception e) + { + Logger.ErrorException("Failed to save chapters:", e); - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save chapters:", e); + if (transaction != null) + { + transaction.Rollback(); + } - if (transaction != null) - { - transaction.Rollback(); + throw; } - - throw; - } - finally - { - if (transaction != null) + finally { - transaction.Dispose(); + if (transaction != null) + { + transaction.Dispose(); + } } - - WriteLock.Release(); } } - protected override void CloseConnection() + private bool EnableJoinUserData(InternalItemsQuery query) { - if (_connection != null) - { - if (_connection.IsOpen()) - { - _connection.Close(); - } - - _connection.Dispose(); - _connection = null; - } - } - - private bool EnableJoinUserData(InternalItemsQuery query) - { - if (query.User == null) + if (query.User == null) { return false; } @@ -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); + using (var cmd = connection.CreateCommand()) + { + cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns, cmd)) + " from TypedBaseItems"; + cmd.CommandText += GetJoinUserDataText(query); - var whereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + if (EnableJoinUserData(query)) + { + cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; + } - cmd.CommandText += whereText; + var whereClauses = GetWhereClauses(query, cmd); - if (EnableGroupByPresentationUniqueKey(query)) - { - cmd.CommandText += " Group by PresentationUniqueKey"; - } + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); - cmd.CommandText += GetOrderByText(query); + cmd.CommandText += whereText; - if (query.Limit.HasValue || query.StartIndex.HasValue) - { - var limit = query.Limit ?? int.MaxValue; + if (EnableGroupByPresentationUniqueKey(query)) + { + cmd.CommandText += " Group by PresentationUniqueKey"; + } - cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + cmd.CommandText += GetOrderByText(query); - if (query.StartIndex.HasValue) + if (query.Limit.HasValue || query.StartIndex.HasValue) { - cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); - } - } + var limit = query.Limit ?? int.MaxValue; - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) - { - LogQueryTime("GetItemList", cmd, now); + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); - while (reader.Read()) + if (query.StartIndex.HasValue) + { + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + } + } + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) { - var item = GetItem(reader); - if (item != null) + LogQueryTime("GetItemList", cmd, now); + + while (reader.Read()) { - yield return item; + 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); + using (var cmd = connection.CreateCommand()) + { + 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 whereTextWithoutPaging = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + var whereClauses = GetWhereClauses(query, cmd); - var whereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + var whereTextWithoutPaging = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); - cmd.CommandText += whereText; + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); - if (EnableGroupByPresentationUniqueKey(query)) - { - cmd.CommandText += " Group by PresentationUniqueKey"; - } + cmd.CommandText += whereText; + + if (EnableGroupByPresentationUniqueKey(query)) + { + cmd.CommandText += " Group by PresentationUniqueKey"; + } - cmd.CommandText += GetOrderByText(query); + cmd.CommandText += GetOrderByText(query); - if (query.Limit.HasValue || query.StartIndex.HasValue) - { - var limit = query.Limit ?? int.MaxValue; + if (query.Limit.HasValue || query.StartIndex.HasValue) + { + var limit = query.Limit ?? int.MaxValue; + + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); - cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + if (query.StartIndex.HasValue) + { + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + } + } - if (query.StartIndex.HasValue) + if (EnableGroupByPresentationUniqueKey(query)) { - cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems"; + } + else + { + cmd.CommandText += "; select count (guid) from TypedBaseItems"; } - } - 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; - cmd.CommandText += GetJoinUserDataText(query); - cmd.CommandText += whereTextWithoutPaging; + var list = new List(); + var count = 0; - var list = new List(); - var count = 0; + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) + { + LogQueryTime("GetItems", cmd, now); - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) - { - LogQueryTime("GetItems", cmd, now); + while (reader.Read()) + { + var item = GetItem(reader); + if (item != null) + { + list.Add(item); + } + } - while (reader.Read()) - { - var item = GetItem(reader); - if (item != null) + if (reader.NextResult() && reader.Read()) { - list.Add(item); + count = reader.GetInt32(0); } } - if (reader.NextResult() && reader.Read()) + return new QueryResult() { - count = reader.GetInt32(0); - } + Items = list.ToArray(), + TotalRecordCount = count + }; } - - 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); + using (var cmd = connection.CreateCommand()) + { + cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" }, cmd)) + " from TypedBaseItems"; + cmd.CommandText += GetJoinUserDataText(query); - var whereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + if (EnableJoinUserData(query)) + { + cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; + } - cmd.CommandText += whereText; + var whereClauses = GetWhereClauses(query, cmd); - if (EnableGroupByPresentationUniqueKey(query)) - { - cmd.CommandText += " Group by PresentationUniqueKey"; - } + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); - cmd.CommandText += GetOrderByText(query); + cmd.CommandText += whereText; - if (query.Limit.HasValue || query.StartIndex.HasValue) - { - var limit = query.Limit ?? int.MaxValue; + if (EnableGroupByPresentationUniqueKey(query)) + { + cmd.CommandText += " Group by PresentationUniqueKey"; + } - cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + cmd.CommandText += GetOrderByText(query); - if (query.StartIndex.HasValue) + if (query.Limit.HasValue || query.StartIndex.HasValue) { - cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); - } - } + var limit = query.Limit ?? int.MaxValue; - var list = new List(); + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) - { - LogQueryTime("GetItemIdsList", cmd, now); + if (query.StartIndex.HasValue) + { + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + } + } + + var list = new List(); - while (reader.Read()) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) { - list.Add(reader.GetGuid(0)); + LogQueryTime("GetItemIdsList", cmd, now); + + while (reader.Read()) + { + list.Add(reader.GetGuid(0)); + } } - } - return list; + 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"; + using (var cmd = connection.CreateCommand()) + { + cmd.CommandText = "select guid,path from TypedBaseItems"; - var whereClauses = GetWhereClauses(query, cmd); + var whereClauses = GetWhereClauses(query, cmd); - var whereTextWithoutPaging = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + 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()); + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); - cmd.CommandText += whereText; + cmd.CommandText += whereText; - if (EnableGroupByPresentationUniqueKey(query)) - { - cmd.CommandText += " Group by PresentationUniqueKey"; - } + if (EnableGroupByPresentationUniqueKey(query)) + { + cmd.CommandText += " Group by PresentationUniqueKey"; + } - cmd.CommandText += GetOrderByText(query); + cmd.CommandText += GetOrderByText(query); - if (query.Limit.HasValue || query.StartIndex.HasValue) - { - var limit = query.Limit ?? int.MaxValue; + if (query.Limit.HasValue || query.StartIndex.HasValue) + { + var limit = query.Limit ?? int.MaxValue; - cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); - if (query.StartIndex.HasValue) - { - cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + if (query.StartIndex.HasValue) + { + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + } } - } - cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging; + cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging; - var list = new List>(); - var count = 0; + var list = new List>(); + var count = 0; - Logger.Debug(cmd.CommandText); + Logger.Debug(cmd.CommandText); - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) - { - while (reader.Read()) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) { - var id = reader.GetGuid(0); - string path = null; + 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.IsDBNull(1)) + if (reader.NextResult() && reader.Read()) { - path = reader.GetString(1); + count = reader.GetInt32(0); } - list.Add(new Tuple(id, path)); } - if (reader.NextResult() && reader.Read()) + return new QueryResult>() { - count = reader.GetInt32(0); - } + Items = list.ToArray(), + TotalRecordCount = count + }; } - - 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; + 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 += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + cmd.CommandText += whereText; - if (query.StartIndex.HasValue) + if (EnableGroupByPresentationUniqueKey(query)) { - cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + cmd.CommandText += " Group by PresentationUniqueKey"; } - } - if (EnableGroupByPresentationUniqueKey(query)) - { - cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems"; - } - else - { - cmd.CommandText += "; select count (guid) from TypedBaseItems"; - } + cmd.CommandText += GetOrderByText(query); - cmd.CommandText += GetJoinUserDataText(query); - cmd.CommandText += whereText; + if (query.Limit.HasValue || query.StartIndex.HasValue) + { + var limit = query.Limit ?? int.MaxValue; - var list = new List(); - var count = 0; + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) - { - LogQueryTime("GetItemIds", cmd, now); + if (query.StartIndex.HasValue) + { + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); + } + } - while (reader.Read()) + if (EnableGroupByPresentationUniqueKey(query)) + { + cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems"; + } + else { - list.Add(reader.GetGuid(0)); + cmd.CommandText += "; select count (guid) from TypedBaseItems"; } - if (reader.NextResult() && reader.Read()) + cmd.CommandText += GetJoinUserDataText(query); + cmd.CommandText += whereText; + + var list = new List(); + var count = 0; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) { - count = reader.GetInt32(0); + 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 - }; + 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()) + 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)) { - var id = reader.GetGuid(0); - string value = reader.IsDBNull(2) ? null : reader.GetString(2); + while (reader.Read()) + { + 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) - { - return; - } + Logger.Debug("UpdateInheritedTags - {0} rows", newValues.Count); + if (newValues.Count == 0) + { + return; + } - await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); + IDbTransaction transaction = null; - IDbTransaction transaction = null; + try + { + transaction = connection.BeginTransaction(); - try - { - 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"); - foreach (var item in newValues) - { - _updateInheritedTagsCommand.GetParameter(0).Value = item.Item1; - _updateInheritedTagsCommand.GetParameter(1).Value = item.Item2; + if (newValues.Count > 1) + { + updateInheritedTagsCommand.Prepare(); + } - _updateInheritedTagsCommand.Transaction = transaction; - _updateInheritedTagsCommand.ExecuteNonQuery(); - } + foreach (var item in newValues) + { + updateInheritedTagsCommand.GetParameter(0).Value = item.Item1; + updateInheritedTagsCommand.GetParameter(1).Value = item.Item2; - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + updateInheritedTagsCommand.Transaction = transaction; + updateInheritedTagsCommand.ExecuteNonQuery(); + } + } + + transaction.Commit(); + } + catch (OperationCanceledException) { - transaction.Rollback(); + if (transaction != null) + { + transaction.Rollback(); + } + + throw; } + catch (Exception e) + { + Logger.ErrorException("Error running query:", e); - throw; - } - catch (Exception e) - { - Logger.ErrorException("Error running query:", e); + if (transaction != null) + { + transaction.Rollback(); + } - if (transaction != null) - { - transaction.Rollback(); + throw; } - - throw; - } - finally - { - if (transaction != null) + finally { - transaction.Dispose(); + if (transaction != null) + { + transaction.Dispose(); + } } - - WriteLock.Release(); } } @@ -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()) + 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)) { - var id = reader.GetGuid(0); - var newValue = reader.GetInt32(2); + while (reader.Read()) + { + 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) - { - return; - } + Logger.Debug("UpdateInheritedParentalRatings - {0} rows", newValues.Count); + if (newValues.Count == 0) + { + return; + } - await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); + using (var updateInheritedRatingCommand = connection.CreateCommand()) + { + 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; + IDbTransaction transaction = null; - try - { - transaction = _connection.BeginTransaction(); + try + { + transaction = connection.BeginTransaction(); - foreach (var item in newValues) - { - _updateInheritedRatingCommand.GetParameter(0).Value = item.Item1; - _updateInheritedRatingCommand.GetParameter(1).Value = item.Item2; + foreach (var item in newValues) + { + updateInheritedRatingCommand.GetParameter(0).Value = item.Item1; + updateInheritedRatingCommand.GetParameter(1).Value = item.Item2; - _updateInheritedRatingCommand.Transaction = transaction; - _updateInheritedRatingCommand.ExecuteNonQuery(); - } + updateInheritedRatingCommand.Transaction = transaction; + updateInheritedRatingCommand.ExecuteNonQuery(); + } - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) - { - transaction.Rollback(); - } + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) + { + transaction.Rollback(); + } - throw; - } - catch (Exception e) - { - Logger.ErrorException("Error running query:", e); + throw; + } + catch (Exception e) + { + Logger.ErrorException("Error running query:", e); - if (transaction != null) - { - transaction.Rollback(); - } + if (transaction != null) + { + transaction.Rollback(); + } - throw; - } - finally - { - if (transaction != null) - { - transaction.Dispose(); + 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(); + try + { + transaction = connection.BeginTransaction(); - // Delete chapters - _deleteChaptersCommand.GetParameter(0).Value = id; - _deleteChaptersCommand.Transaction = transaction; - _deleteChaptersCommand.ExecuteNonQuery(); + // Delete people + DeletePeople(connection, transaction, id); + DeleteChapters(connection, transaction, id); + DeleteMediaStreams(connection, transaction, id); - // Delete media streams - _deleteStreamsCommand.GetParameter(0).Value = id; - _deleteStreamsCommand.Transaction = transaction; - _deleteStreamsCommand.ExecuteNonQuery(); + // Delete ancestors + DeleteAncestors(connection, transaction, id); - // Delete ancestors - _deleteAncestorsCommand.GetParameter(0).Value = id; - _deleteAncestorsCommand.Transaction = transaction; - _deleteAncestorsCommand.ExecuteNonQuery(); + // Delete user data keys + DeleteUserDataKeys(connection, transaction, id); - // Delete user data keys - _deleteUserDataKeysCommand.GetParameter(0).Value = id; - _deleteUserDataKeysCommand.Transaction = transaction; - _deleteUserDataKeysCommand.ExecuteNonQuery(); + // Delete item values + DeleteItemValues(connection, transaction, id); - // Delete item values - _deleteItemValuesCommand.GetParameter(0).Value = id; - _deleteItemValuesCommand.Transaction = transaction; - _deleteItemValuesCommand.ExecuteNonQuery(); + // Delete provider ids + DeleteProviderIds(connection, transaction, id); - // Delete provider ids - _deleteProviderIdsCommand.GetParameter(0).Value = id; - _deleteProviderIdsCommand.Transaction = transaction; - _deleteProviderIdsCommand.ExecuteNonQuery(); + DeleteImages(connection, transaction, id); - // Delete images - _deleteImagesCommand.GetParameter(0).Value = id; - _deleteImagesCommand.Transaction = transaction; - _deleteImagesCommand.ExecuteNonQuery(); + // Delete the item + using (var deleteItemCommand = connection.CreateCommand()) + { + deleteItemCommand.CommandText = "delete from TypedBaseItems where guid=@Id"; + deleteItemCommand.Parameters.Add(deleteItemCommand, "@Id"); - // Delete the item - _deleteItemCommand.GetParameter(0).Value = id; - _deleteItemCommand.Transaction = transaction; - _deleteItemCommand.ExecuteNonQuery(); + deleteItemCommand.GetParameter(0).Value = id; + deleteItemCommand.Transaction = transaction; + deleteItemCommand.ExecuteNonQuery(); + } - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + transaction.Commit(); + } + catch (OperationCanceledException) { - transaction.Rollback(); + if (transaction != null) + { + transaction.Rollback(); + } + + throw; } + catch (Exception e) + { + Logger.ErrorException("Failed to save children:", e); - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save children:", e); + if (transaction != null) + { + transaction.Rollback(); + } - if (transaction != null) - { - transaction.Rollback(); + throw; } - - throw; - } - finally - { - if (transaction != null) + finally { - transaction.Dispose(); + if (transaction != null) + { + transaction.Dispose(); + } } - - WriteLock.Release(); } } @@ -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"; + using (var cmd = connection.CreateCommand()) + { + cmd.CommandText = "select Distinct Name from People"; - var whereClauses = GetPeopleWhereClauses(query, cmd); + var whereClauses = GetPeopleWhereClauses(query, cmd); - if (whereClauses.Count > 0) - { - cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); - } + if (whereClauses.Count > 0) + { + cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); + } - cmd.CommandText += " order by ListOrder"; + cmd.CommandText += " order by ListOrder"; - var list = new List(); + var list = new List(); - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) - { - while (reader.Read()) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) { - list.Add(reader.GetString(0)); + while (reader.Read()) + { + list.Add(reader.GetString(0)); + } } - } - return list; + 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"; + using (var cmd = connection.CreateCommand()) + { + cmd.CommandText = "select ItemId, Name, Role, PersonType, SortOrder from People"; - var whereClauses = GetPeopleWhereClauses(query, cmd); + var whereClauses = GetPeopleWhereClauses(query, cmd); - if (whereClauses.Count > 0) - { - cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); - } + if (whereClauses.Count > 0) + { + cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); + } - cmd.CommandText += " order by ListOrder"; + cmd.CommandText += " order by ListOrder"; - var list = new List(); + var list = new List(); - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) - { - while (reader.Read()) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) { - list.Add(GetPerson(reader)); + while (reader.Read()) + { + list.Add(GetPerson(reader)); + } } - } - return list; + 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"); + + if (ancestorIds.Count > 1) + { + saveAncestorCommand.Prepare(); + } + + 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.Transaction = transaction; - _saveAncestorCommand.ExecuteNonQuery(); + 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; - - _deleteImagesCommand.ExecuteNonQuery(); + DeleteImages(connection, transaction, itemId); - 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)) - { - _saveImagesCommand.GetParameter(3).Value = null; - } - else + using (var saveImagesCommand = connection.CreateCommand()) { - _saveImagesCommand.GetParameter(3).Value = image.DateModified; + 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(4).Value = image.IsPlaceholder; - _saveImagesCommand.GetParameter(5).Value = 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"); - _saveImagesCommand.Transaction = transaction; + deleteProviderIdsCommand.GetParameter(0).Value = itemId; + deleteProviderIdsCommand.Transaction = transaction; - _saveImagesCommand.ExecuteNonQuery(); - index++; + deleteProviderIdsCommand.ExecuteNonQuery(); } } - private void UpdateProviderIds(Guid itemId, Dictionary values, IDbTransaction transaction) + 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); + + if (values.Count > 0) + { + 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"); + + 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; - _deleteProviderIdsCommand.ExecuteNonQuery(); + saveProviderIdsCommand.ExecuteNonQuery(); + } + } + } + } - foreach (var pair in values) + private void DeleteItemValues(IDbConnection connection, IDbTransaction transaction, Guid itemId) + { + using (var deleteItemValuesCommand = connection.CreateCommand()) { - _saveProviderIdsCommand.GetParameter(0).Value = itemId; - _saveProviderIdsCommand.GetParameter(1).Value = pair.Key; - _saveProviderIdsCommand.GetParameter(2).Value = pair.Value; - _saveProviderIdsCommand.Transaction = transaction; + deleteItemValuesCommand.CommandText = "delete from ItemValues where ItemId=@Id"; + deleteItemValuesCommand.Parameters.Add(deleteItemValuesCommand, "@Id"); + + // First delete + deleteItemValuesCommand.GetParameter(0).Value = itemId; + deleteItemValuesCommand.Transaction = transaction; - _saveProviderIdsCommand.ExecuteNonQuery(); + deleteItemValuesCommand.ExecuteNonQuery(); } } - private void UpdateItemValues(Guid itemId, List> values, IDbTransaction transaction) + 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); + + if (values.Count > 0) + { + 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"); + + 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; - _deleteItemValuesCommand.ExecuteNonQuery(); + saveItemValuesCommand.ExecuteNonQuery(); + } + } + } + } - foreach (var pair in values) + private void DeleteUserDataKeys(IDbConnection connection, IDbTransaction transaction, Guid itemId) + { + using (var deleteUserDataKeysCommand = connection.CreateCommand()) { - _saveItemValuesCommand.GetParameter(0).Value = itemId; - _saveItemValuesCommand.GetParameter(1).Value = pair.Item1; - _saveItemValuesCommand.GetParameter(2).Value = pair.Item2; - _saveItemValuesCommand.Transaction = transaction; + // user data + deleteUserDataKeysCommand.CommandText = "delete from UserDataKeys where ItemId=@Id"; + deleteUserDataKeysCommand.Parameters.Add(deleteUserDataKeysCommand, "@Id"); + + deleteUserDataKeysCommand.GetParameter(0).Value = itemId; + deleteUserDataKeysCommand.Transaction = transaction; - _saveItemValuesCommand.ExecuteNonQuery(); + deleteUserDataKeysCommand.ExecuteNonQuery(); } } - private void UpdateUserDataKeys(Guid itemId, List keys, IDbTransaction transaction) + 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) + { + 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"); + + 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()) { - _saveUserDataKeysCommand.GetParameter(0).Value = itemId; - _saveUserDataKeysCommand.GetParameter(1).Value = key; - _saveUserDataKeysCommand.GetParameter(2).Value = index; - index++; - _saveUserDataKeysCommand.Transaction = transaction; + deletePeopleCommand.CommandText = "delete from People where ItemId=@Id"; + deletePeopleCommand.Parameters.Add(deletePeopleCommand, "@Id"); - _saveUserDataKeysCommand.ExecuteNonQuery(); + + 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(); - - // First delete - _deletePeopleCommand.GetParameter(0).Value = itemId; - _deletePeopleCommand.Transaction = transaction; + IDbTransaction transaction = null; - _deletePeopleCommand.ExecuteNonQuery(); + try + { + transaction = connection.BeginTransaction(); - var listIndex = 0; + // First delete + DeletePeople(connection, transaction, itemId); - foreach (var person in people) - { - cancellationToken.ThrowIfCancellationRequested(); + var listIndex = 0; - _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; + 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++; + } + } + } - _savePersonCommand.Transaction = transaction; + transaction.Commit(); - _savePersonCommand.ExecuteNonQuery(); - listIndex++; } - - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + catch (OperationCanceledException) { - transaction.Rollback(); + if (transaction != null) + { + transaction.Rollback(); + } + + throw; } + catch (Exception e) + { + Logger.ErrorException("Failed to save people:", e); - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save people:", e); + if (transaction != null) + { + transaction.Rollback(); + } - if (transaction != null) - { - transaction.Rollback(); + throw; } - - throw; - } - finally - { - if (transaction != null) + 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"; + 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; + 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.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; - } + if (query.Index.HasValue) + { + cmdText += " AND StreamIndex=@StreamIndex"; + cmd.Parameters.Add(cmd, "@StreamIndex", DbType.Int32).Value = query.Index.Value; + } - cmdText += " order by StreamIndex ASC"; + cmdText += " order by StreamIndex ASC"; - cmd.CommandText = cmdText; + cmd.CommandText = cmdText; - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) - { - while (reader.Read()) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) { - list.Add(GetMediaStream(reader)); + while (reader.Read()) + { + list.Add(GetMediaStream(reader)); + } } } + + return list; } + } - return list; + 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, IEnumerable streams, CancellationToken cancellationToken) + 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(); - - // First delete chapters - _deleteStreamsCommand.GetParameter(0).Value = id; - - _deleteStreamsCommand.Transaction = transaction; + IDbTransaction transaction = null; - _deleteStreamsCommand.ExecuteNonQuery(); - - foreach (var stream in streams) + try { - cancellationToken.ThrowIfCancellationRequested(); - - var index = 0; - - _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.IsInterlaced; - - _saveStreamCommand.GetParameter(index++).Value = stream.BitRate; - _saveStreamCommand.GetParameter(index++).Value = stream.Channels; - _saveStreamCommand.GetParameter(index++).Value = stream.SampleRate; + transaction = connection.BeginTransaction(); - _saveStreamCommand.GetParameter(index++).Value = stream.IsDefault; - _saveStreamCommand.GetParameter(index++).Value = stream.IsForced; - _saveStreamCommand.GetParameter(index++).Value = stream.IsExternal; + // First delete + DeleteMediaStreams(connection, transaction, id); - _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; + 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())); + + foreach (var col in _mediaStreamSaveColumns) + { + saveStreamCommand.Parameters.Add(saveStreamCommand, "@" + col); + } + + if (streams.Count > 1) + { + saveStreamCommand.Prepare(); + } + + foreach (var stream in streams) + { + cancellationToken.ThrowIfCancellationRequested(); + + var index = 0; + + 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.IsInterlaced; + + 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(); + } + } + } - _saveStreamCommand.Transaction = transaction; - _saveStreamCommand.ExecuteNonQuery(); + transaction.Commit(); } - - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) + catch (OperationCanceledException) { - transaction.Rollback(); + if (transaction != null) + { + transaction.Rollback(); + } + + throw; } + catch (Exception e) + { + Logger.ErrorException("Failed to save media streams:", e); - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save media streams:", e); + if (transaction != null) + { + transaction.Rollback(); + } - if (transaction != null) - { - transaction.Rollback(); + throw; } - - throw; - } - finally - { - if (transaction != null) + 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" }; -- cgit v1.2.3 From 383110f9af6b5ad79ddabb3c8db0bdb7d4b4db03 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sun, 12 Jun 2016 19:33:11 -0400 Subject: switch recordings to ts when preserving original audio --- MediaBrowser.Providers/TV/SeriesPostScanTask.cs | 39 +- .../LiveTv/EmbyTV/EncodedRecorder.cs | 2 +- .../Persistence/BaseSqliteRepository.cs | 40 +- .../Persistence/SqliteExtensions.cs | 6 +- .../Persistence/SqliteItemRepository.cs | 2851 ++++++++++---------- .../Persistence/SqliteUserDataRepository.cs | 322 +-- .../ApplicationHost.cs | 4 +- 7 files changed, 1595 insertions(+), 1669 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs') 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 ; - } + if (_libraryManager.IsScanRunning) + { + return; + } - var seriesList = _libraryManager.GetItemList(new InternalItemsQuery() - { - IncludeItemTypes = new[] { typeof(Series).Name }, - Recursive = true, - GroupByPresentationUniqueKey = false + var seriesList = _libraryManager.GetItemList(new InternalItemsQuery() + { + IncludeItemTypes = new[] { typeof(Series).Name }, + Recursive = true, + GroupByPresentationUniqueKey = false - }).Cast().ToList(); + }).Cast().ToList(); - var seriesGroups = SeriesPostScanTask.FindSeriesGroups(seriesList).Where(g => !string.IsNullOrEmpty(g.Key)).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); + await new MissingEpisodeProvider(_logger, _config, _libraryManager, _localization, _fileSystem) + .Run(seriesGroups, false, CancellationToken.None).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.ErrorException("Error in SeriesPostScanTask", ex); + } } 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); - - //AttachUserDataDb(connection); + var connection = await DbConnector.Connect(DbFilePath, false, false, 6000).ConfigureAwait(false); - //connection.RunQueries(new[] - //{ - // "pragma locking_mode=NORMAL" + connection.RunQueries(new[] + { + "pragma temp_store = memory" - //}, 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.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", "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", "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", "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", "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"); - - string[] postQueries = - { + _connection.RunQueries(queries, Logger); + + _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", "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", "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", "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", "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"); + + 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(); + + var index = 0; - using (var saveItemCommand = connection.CreateCommand()) + _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.GetParameter(index++).Value = hasStartDate.StartDate; + } + else + { + _saveItemCommand.GetParameter(index++).Value = null; + } - saveItemCommand.Parameters.Add(saveItemCommand, "@" + i.ToString(CultureInfo.InvariantCulture)); - } - saveItemCommand.CommandText += ")"; + _saveItemCommand.GetParameter(index++).Value = item.EndDate; + _saveItemCommand.GetParameter(index++).Value = item.ChannelId; - 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); - } + 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; } - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != 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 { - transaction.Rollback(); + _saveItemCommand.GetParameter(index++).Value = item.ParentId; } - throw; - } - catch (Exception e) - { - Logger.ErrorException("Failed to save items:", e); + _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 (transaction != null) + if (item.DateLastSaved == default(DateTime)) { - transaction.Rollback(); + _saveItemCommand.GetParameter(index++).Value = null; + } + else + { + _saveItemCommand.GetParameter(index++).Value = item.DateLastSaved; } - throw; - } - finally - { - if (transaction != null) + _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) { - transaction.Dispose(); + _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.CommandText = "select StartPositionTicks,Name,ImagePath from " + ChaptersTableName + " where ItemId = @ItemId order by ChapterIndex asc"; - cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = id; + cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = id; - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + 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.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; + 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 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"); - - 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++; - } - } - } + _saveChapterCommand.ExecuteNonQuery(); - transaction.Commit(); + index++; } - catch (OperationCanceledException) + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) { - if (transaction != null) - { - transaction.Rollback(); - } + transaction.Rollback(); + } + + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save chapters:", e); - throw; + if (transaction != null) + { + transaction.Rollback(); } - catch (Exception e) + + throw; + } + finally + { + if (transaction != null) { - Logger.ErrorException("Failed to save chapters:", e); + transaction.Dispose(); + } - if (transaction != null) - { - transaction.Rollback(); - } + WriteLock.Release(); + } + } - throw; - } - finally + protected override void CloseConnection() + { + if (_connection != null) + { + if (_connection.IsOpen()) { - if (transaction != null) - { - transaction.Dispose(); - } + _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()) - { - cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns, cmd)) + " from TypedBaseItems"; - cmd.CommandText += GetJoinUserDataText(query); + var whereClauses = GetWhereClauses(query, cmd); - 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()); - var whereClauses = GetWhereClauses(query, cmd); + cmd.CommandText += whereText; - var whereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + if (EnableGroupByPresentationUniqueKey(query)) + { + cmd.CommandText += " Group by PresentationUniqueKey"; + } - cmd.CommandText += whereText; + cmd.CommandText += GetOrderByText(query); - if (EnableGroupByPresentationUniqueKey(query)) - { - cmd.CommandText += " Group by PresentationUniqueKey"; - } + if (query.Limit.HasValue || query.StartIndex.HasValue) + { + var limit = query.Limit ?? int.MaxValue; - cmd.CommandText += GetOrderByText(query); + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); - if (query.Limit.HasValue || query.StartIndex.HasValue) + if (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 += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); } + } - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) - { - LogQueryTime("GetItemList", cmd, now); + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + LogQueryTime("GetItemList", cmd, now); - while (reader.Read()) + while (reader.Read()) + { + var item = GetItem(reader); + if (item != null) { - 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()) - { - 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 whereClauses = GetWhereClauses(query, cmd); - var whereTextWithoutPaging = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + 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()); + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); - cmd.CommandText += whereText; + cmd.CommandText += whereText; - if (EnableGroupByPresentationUniqueKey(query)) - { - cmd.CommandText += " Group by PresentationUniqueKey"; - } - - cmd.CommandText += GetOrderByText(query); + if (EnableGroupByPresentationUniqueKey(query)) + { + cmd.CommandText += " Group by PresentationUniqueKey"; + } - if (query.Limit.HasValue || query.StartIndex.HasValue) - { - var limit = query.Limit ?? int.MaxValue; + cmd.CommandText += GetOrderByText(query); - cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + if (query.Limit.HasValue || query.StartIndex.HasValue) + { + var limit = query.Limit ?? int.MaxValue; - if (query.StartIndex.HasValue) - { - cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); - } - } + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); - if (EnableGroupByPresentationUniqueKey(query)) + if (query.StartIndex.HasValue) { - cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems"; - } - else - { - cmd.CommandText += "; select count (guid) from TypedBaseItems"; + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); } + } - cmd.CommandText += GetJoinUserDataText(query); - cmd.CommandText += whereTextWithoutPaging; + if (EnableGroupByPresentationUniqueKey(query)) + { + cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems"; + } + else + { + cmd.CommandText += "; select count (guid) from TypedBaseItems"; + } - var list = new List(); - var count = 0; + cmd.CommandText += GetJoinUserDataText(query); + cmd.CommandText += whereTextWithoutPaging; - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) - { - LogQueryTime("GetItems", cmd, now); + var list = new List(); + var count = 0; - while (reader.Read()) - { - var item = GetItem(reader); - if (item != null) - { - list.Add(item); - } - } + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) + { + LogQueryTime("GetItems", cmd, now); - if (reader.NextResult() && reader.Read()) + while (reader.Read()) + { + var item = GetItem(reader); + if (item != null) { - count = reader.GetInt32(0); + list.Add(item); } } - return new QueryResult() + if (reader.NextResult() && reader.Read()) { - Items = list.ToArray(), - TotalRecordCount = count - }; + 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()) - { - cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" }, cmd)) + " from TypedBaseItems"; - cmd.CommandText += GetJoinUserDataText(query); + var whereClauses = GetWhereClauses(query, cmd); - 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()); - var whereClauses = GetWhereClauses(query, cmd); + cmd.CommandText += whereText; - var whereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + if (EnableGroupByPresentationUniqueKey(query)) + { + cmd.CommandText += " Group by PresentationUniqueKey"; + } - cmd.CommandText += whereText; + cmd.CommandText += GetOrderByText(query); - if (EnableGroupByPresentationUniqueKey(query)) - { - cmd.CommandText += " Group by PresentationUniqueKey"; - } + if (query.Limit.HasValue || query.StartIndex.HasValue) + { + var limit = query.Limit ?? int.MaxValue; - cmd.CommandText += GetOrderByText(query); + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); - if (query.Limit.HasValue || query.StartIndex.HasValue) + if (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 += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); } + } - var list = new List(); + var list = new List(); - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) - { - LogQueryTime("GetItemIdsList", cmd, now); + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + LogQueryTime("GetItemIdsList", cmd, now); - while (reader.Read()) - { - list.Add(reader.GetGuid(0)); - } + while (reader.Read()) + { + list.Add(reader.GetGuid(0)); } - - return list; } + + 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"; + cmd.CommandText = "select guid,path from TypedBaseItems"; - var whereClauses = GetWhereClauses(query, cmd); + var whereClauses = GetWhereClauses(query, cmd); - var whereTextWithoutPaging = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + 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()); + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); - cmd.CommandText += whereText; + cmd.CommandText += whereText; - if (EnableGroupByPresentationUniqueKey(query)) - { - cmd.CommandText += " Group by PresentationUniqueKey"; - } + if (EnableGroupByPresentationUniqueKey(query)) + { + cmd.CommandText += " Group by PresentationUniqueKey"; + } - cmd.CommandText += GetOrderByText(query); + cmd.CommandText += GetOrderByText(query); - if (query.Limit.HasValue || query.StartIndex.HasValue) - { - var limit = query.Limit ?? int.MaxValue; + if (query.Limit.HasValue || query.StartIndex.HasValue) + { + var limit = query.Limit ?? int.MaxValue; - cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); - if (query.StartIndex.HasValue) - { - cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); - } + if (query.StartIndex.HasValue) + { + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); } + } - cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging; + cmd.CommandText += "; select count (guid) from TypedBaseItems" + whereTextWithoutPaging; - var list = new List>(); - var count = 0; + var list = new List>(); + var count = 0; - Logger.Debug(cmd.CommandText); + Logger.Debug(cmd.CommandText); - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) + { + while (reader.Read()) { - 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)); - } + var id = reader.GetGuid(0); + string path = null; - if (reader.NextResult() && reader.Read()) + if (!reader.IsDBNull(1)) { - count = reader.GetInt32(0); + path = reader.GetString(1); } + list.Add(new Tuple(id, path)); } - return new QueryResult>() + if (reader.NextResult() && reader.Read()) { - Items = list.ToArray(), - TotalRecordCount = count - }; + 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()) - { - cmd.CommandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" }, cmd)) + " from TypedBaseItems"; + var whereText = whereClauses.Count == 0 ? + string.Empty : + " where " + string.Join(" AND ", whereClauses.ToArray()); - var whereClauses = GetWhereClauses(query, cmd); - cmd.CommandText += GetJoinUserDataText(query); + cmd.CommandText += whereText; - if (EnableJoinUserData(query)) - { - cmd.Parameters.Add(cmd, "@UserId", DbType.Guid).Value = query.User.Id; - } + if (EnableGroupByPresentationUniqueKey(query)) + { + cmd.CommandText += " Group by PresentationUniqueKey"; + } - var whereText = whereClauses.Count == 0 ? - string.Empty : - " where " + string.Join(" AND ", whereClauses.ToArray()); + cmd.CommandText += GetOrderByText(query); - cmd.CommandText += whereText; + if (query.Limit.HasValue || query.StartIndex.HasValue) + { + var limit = query.Limit ?? int.MaxValue; + + cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); - if (EnableGroupByPresentationUniqueKey(query)) + if (query.StartIndex.HasValue) { - cmd.CommandText += " Group by PresentationUniqueKey"; + cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); } + } - cmd.CommandText += GetOrderByText(query); + if (EnableGroupByPresentationUniqueKey(query)) + { + cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems"; + } + else + { + cmd.CommandText += "; select count (guid) from TypedBaseItems"; + } - if (query.Limit.HasValue || query.StartIndex.HasValue) - { - var limit = query.Limit ?? int.MaxValue; + cmd.CommandText += GetJoinUserDataText(query); + cmd.CommandText += whereText; - cmd.CommandText += " LIMIT " + limit.ToString(CultureInfo.InvariantCulture); + var list = new List(); + var count = 0; - if (query.StartIndex.HasValue) - { - cmd.CommandText += " OFFSET " + query.StartIndex.Value.ToString(CultureInfo.InvariantCulture); - } - } + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess)) + { + LogQueryTime("GetItemIds", cmd, now); - if (EnableGroupByPresentationUniqueKey(query)) + while (reader.Read()) { - cmd.CommandText += "; select count (distinct PresentationUniqueKey) from TypedBaseItems"; + list.Add(reader.GetGuid(0)); } - 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)) + if (reader.NextResult() && reader.Read()) { - LogQueryTime("GetItemIds", cmd, now); - - while (reader.Read()) - { - list.Add(reader.GetGuid(0)); - } - - if (reader.NextResult() && reader.Read()) - { - count = reader.GetInt32(0); - } + count = reader.GetInt32(0); } - - return new QueryResult() - { - Items = list.ToArray(), - TotalRecordCount = count - }; } + + 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) - { - return; - } - - IDbTransaction transaction = null; - - try - { - 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"); + Logger.Debug("UpdateInheritedTags - {0} rows", newValues.Count); + if (newValues.Count == 0) + { + return; + } - if (newValues.Count > 1) - { - updateInheritedTagsCommand.Prepare(); - } + await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); - foreach (var item in newValues) - { - updateInheritedTagsCommand.GetParameter(0).Value = item.Item1; - updateInheritedTagsCommand.GetParameter(1).Value = item.Item2; + IDbTransaction transaction = null; - updateInheritedTagsCommand.Transaction = transaction; - updateInheritedTagsCommand.ExecuteNonQuery(); - } - } + try + { + transaction = _connection.BeginTransaction(); - transaction.Commit(); - } - catch (OperationCanceledException) + foreach (var item in newValues) { - if (transaction != null) - { - transaction.Rollback(); - } + _updateInheritedTagsCommand.GetParameter(0).Value = item.Item1; + _updateInheritedTagsCommand.GetParameter(1).Value = item.Item2; - throw; + _updateInheritedTagsCommand.Transaction = transaction; + _updateInheritedTagsCommand.ExecuteNonQuery(); } - catch (Exception e) + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) { - Logger.ErrorException("Error running query:", e); + transaction.Rollback(); + } - if (transaction != null) - { - transaction.Rollback(); - } + throw; + } + catch (Exception e) + { + Logger.ErrorException("Error running query:", e); - throw; + if (transaction != null) + { + transaction.Rollback(); } - finally + + throw; + } + finally + { + if (transaction != null) { - 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"; + 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 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) - { - return; - } + Logger.Debug("UpdateInheritedParentalRatings - {0} rows", newValues.Count); + if (newValues.Count == 0) + { + return; + } - using (var updateInheritedRatingCommand = connection.CreateCommand()) - { - updateInheritedRatingCommand.CommandText = "Update TypedBaseItems set InheritedParentalRatingValue=@InheritedParentalRatingValue where Guid=@Guid"; - updateInheritedRatingCommand.Parameters.Add(updateInheritedRatingCommand, "@Guid"); - updateInheritedRatingCommand.Parameters.Add(updateInheritedRatingCommand, "@InheritedParentalRatingValue"); - updateInheritedRatingCommand.Prepare(); + await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); - IDbTransaction transaction = null; + IDbTransaction transaction = null; - try - { - transaction = connection.BeginTransaction(); + try + { + transaction = _connection.BeginTransaction(); - foreach (var item in newValues) - { - updateInheritedRatingCommand.GetParameter(0).Value = item.Item1; - updateInheritedRatingCommand.GetParameter(1).Value = item.Item2; + foreach (var item in newValues) + { + _updateInheritedRatingCommand.GetParameter(0).Value = item.Item1; + _updateInheritedRatingCommand.GetParameter(1).Value = item.Item2; - updateInheritedRatingCommand.Transaction = transaction; - updateInheritedRatingCommand.ExecuteNonQuery(); - } + _updateInheritedRatingCommand.Transaction = transaction; + _updateInheritedRatingCommand.ExecuteNonQuery(); + } - transaction.Commit(); - } - catch (OperationCanceledException) - { - if (transaction != null) - { - transaction.Rollback(); - } + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) + { + transaction.Rollback(); + } - throw; - } - catch (Exception e) - { - Logger.ErrorException("Error running query:", e); + throw; + } + catch (Exception e) + { + Logger.ErrorException("Error running query:", e); - if (transaction != null) - { - transaction.Rollback(); - } + if (transaction != null) + { + transaction.Rollback(); + } - throw; - } - finally - { - if (transaction != null) - { - transaction.Dispose(); - } - } + 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 - { - transaction = connection.BeginTransaction(); + // Delete people + _deletePeopleCommand.GetParameter(0).Value = id; + _deletePeopleCommand.Transaction = transaction; + _deletePeopleCommand.ExecuteNonQuery(); - // Delete people - DeletePeople(connection, transaction, id); - DeleteChapters(connection, transaction, id); - DeleteMediaStreams(connection, transaction, id); + // Delete chapters + _deleteChaptersCommand.GetParameter(0).Value = id; + _deleteChaptersCommand.Transaction = transaction; + _deleteChaptersCommand.ExecuteNonQuery(); - // Delete ancestors - DeleteAncestors(connection, transaction, id); + // Delete media streams + _deleteStreamsCommand.GetParameter(0).Value = id; + _deleteStreamsCommand.Transaction = transaction; + _deleteStreamsCommand.ExecuteNonQuery(); - // Delete user data keys - DeleteUserDataKeys(connection, transaction, id); + // Delete ancestors + _deleteAncestorsCommand.GetParameter(0).Value = id; + _deleteAncestorsCommand.Transaction = transaction; + _deleteAncestorsCommand.ExecuteNonQuery(); - // Delete item values - DeleteItemValues(connection, transaction, id); + // Delete user data keys + _deleteUserDataKeysCommand.GetParameter(0).Value = id; + _deleteUserDataKeysCommand.Transaction = transaction; + _deleteUserDataKeysCommand.ExecuteNonQuery(); - // Delete provider ids - DeleteProviderIds(connection, transaction, id); + // Delete item values + _deleteItemValuesCommand.GetParameter(0).Value = id; + _deleteItemValuesCommand.Transaction = transaction; + _deleteItemValuesCommand.ExecuteNonQuery(); - DeleteImages(connection, transaction, id); + // Delete provider ids + _deleteProviderIdsCommand.GetParameter(0).Value = id; + _deleteProviderIdsCommand.Transaction = transaction; + _deleteProviderIdsCommand.ExecuteNonQuery(); - // Delete the item - using (var deleteItemCommand = connection.CreateCommand()) - { - deleteItemCommand.CommandText = "delete from TypedBaseItems where guid=@Id"; - deleteItemCommand.Parameters.Add(deleteItemCommand, "@Id"); + // Delete images + _deleteImagesCommand.GetParameter(0).Value = id; + _deleteImagesCommand.Transaction = transaction; + _deleteImagesCommand.ExecuteNonQuery(); - deleteItemCommand.GetParameter(0).Value = id; - deleteItemCommand.Transaction = transaction; - deleteItemCommand.ExecuteNonQuery(); - } + // Delete the item + _deleteItemCommand.GetParameter(0).Value = id; + _deleteItemCommand.Transaction = transaction; + _deleteItemCommand.ExecuteNonQuery(); - transaction.Commit(); - } - catch (OperationCanceledException) + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) { - if (transaction != null) - { - transaction.Rollback(); - } - - throw; + transaction.Rollback(); } - catch (Exception e) - { - Logger.ErrorException("Failed to save children:", e); - if (transaction != null) - { - transaction.Rollback(); - } + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save children:", e); - throw; + if (transaction != null) + { + transaction.Rollback(); } - finally + + throw; + } + finally + { + if (transaction != null) { - 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"; + cmd.CommandText = "select Distinct Name from People"; - var whereClauses = GetPeopleWhereClauses(query, cmd); + var whereClauses = GetPeopleWhereClauses(query, cmd); - if (whereClauses.Count > 0) - { - cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); - } + if (whereClauses.Count > 0) + { + cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); + } - cmd.CommandText += " order by ListOrder"; + cmd.CommandText += " order by ListOrder"; - var list = new List(); + var list = new List(); - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) { - while (reader.Read()) - { - list.Add(reader.GetString(0)); - } + list.Add(reader.GetString(0)); } - - return list; } + + 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"; + cmd.CommandText = "select ItemId, Name, Role, PersonType, SortOrder from People"; - var whereClauses = GetPeopleWhereClauses(query, cmd); + var whereClauses = GetPeopleWhereClauses(query, cmd); - if (whereClauses.Count > 0) - { - cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); - } + if (whereClauses.Count > 0) + { + cmd.CommandText += " where " + string.Join(" AND ", whereClauses.ToArray()); + } - cmd.CommandText += " order by ListOrder"; + cmd.CommandText += " order by ListOrder"; - var list = new List(); + var list = new List(); - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) { - while (reader.Read()) - { - list.Add(GetPerson(reader)); - } + list.Add(GetPerson(reader)); } - - return list; } + + 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) - { - 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"); - - if (ancestorIds.Count > 1) - { - saveAncestorCommand.Prepare(); - } + _deleteAncestorsCommand.ExecuteNonQuery(); - foreach (var ancestorId in ancestorIds) - { - saveAncestorCommand.GetParameter(0).Value = itemId; - saveAncestorCommand.GetParameter(1).Value = ancestorId; - saveAncestorCommand.GetParameter(2).Value = ancestorId.ToString("N"); + 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.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) - { - using (var saveImagesCommand = connection.CreateCommand()) - { - 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"); + _deleteImagesCommand.ExecuteNonQuery(); - 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; + var index = 0; + foreach (var image in images) + { + _saveImagesCommand.GetParameter(0).Value = itemId; + _saveImagesCommand.GetParameter(1).Value = image.Type; + _saveImagesCommand.GetParameter(2).Value = image.Path; - saveImagesCommand.ExecuteNonQuery(); - index++; - } + if (image.DateModified == default(DateTime)) + { + _saveImagesCommand.GetParameter(3).Value = null; + } + else + { + _saveImagesCommand.GetParameter(3).Value = image.DateModified; } - } - } - 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"); + _saveImagesCommand.GetParameter(4).Value = image.IsPlaceholder; + _saveImagesCommand.GetParameter(5).Value = index; - deleteProviderIdsCommand.GetParameter(0).Value = itemId; - deleteProviderIdsCommand.Transaction = transaction; + _saveImagesCommand.Transaction = transaction; - deleteProviderIdsCommand.ExecuteNonQuery(); + _saveImagesCommand.ExecuteNonQuery(); + index++; } } - 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); - - if (values.Count > 0) - { - 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"); - - 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; + _deleteProviderIdsCommand.GetParameter(0).Value = itemId; + _deleteProviderIdsCommand.Transaction = transaction; - saveProviderIdsCommand.ExecuteNonQuery(); - } - } - } - } + _deleteProviderIdsCommand.ExecuteNonQuery(); - private void DeleteItemValues(IDbConnection connection, IDbTransaction transaction, Guid itemId) - { - using (var deleteItemValuesCommand = connection.CreateCommand()) + foreach (var pair in values) { - deleteItemValuesCommand.CommandText = "delete from ItemValues where ItemId=@Id"; - deleteItemValuesCommand.Parameters.Add(deleteItemValuesCommand, "@Id"); - - // First delete - deleteItemValuesCommand.GetParameter(0).Value = itemId; - deleteItemValuesCommand.Transaction = transaction; + _saveProviderIdsCommand.GetParameter(0).Value = itemId; + _saveProviderIdsCommand.GetParameter(1).Value = pair.Key; + _saveProviderIdsCommand.GetParameter(2).Value = pair.Value; + _saveProviderIdsCommand.Transaction = transaction; - deleteItemValuesCommand.ExecuteNonQuery(); + _saveProviderIdsCommand.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) - { - 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"); + _deleteItemValuesCommand.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 DeleteUserDataKeys(IDbConnection connection, IDbTransaction transaction, Guid itemId) - { - using (var deleteUserDataKeysCommand = connection.CreateCommand()) + foreach (var pair in values) { - // user data - deleteUserDataKeysCommand.CommandText = "delete from UserDataKeys where ItemId=@Id"; - deleteUserDataKeysCommand.Parameters.Add(deleteUserDataKeysCommand, "@Id"); - - deleteUserDataKeysCommand.GetParameter(0).Value = itemId; - deleteUserDataKeysCommand.Transaction = transaction; + _saveItemValuesCommand.GetParameter(0).Value = itemId; + _saveItemValuesCommand.GetParameter(1).Value = pair.Item1; + _saveItemValuesCommand.GetParameter(2).Value = pair.Item2; + _saveItemValuesCommand.Transaction = transaction; - deleteUserDataKeysCommand.ExecuteNonQuery(); + _saveItemValuesCommand.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"); - - if (keys.Count > 1) - { - saveUserDataKeysCommand.Prepare(); - } + _saveUserDataKeysCommand.GetParameter(0).Value = itemId; + _saveUserDataKeysCommand.GetParameter(1).Value = key; + _saveUserDataKeysCommand.GetParameter(2).Value = index; + index++; + _saveUserDataKeysCommand.Transaction = transaction; - 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)) - { - IDbTransaction transaction = null; + await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); - try - { - transaction = connection.BeginTransaction(); + IDbTransaction transaction = null; - // First delete - DeletePeople(connection, transaction, itemId); + try + { + transaction = _connection.BeginTransaction(); - var listIndex = 0; + // First delete + _deletePeopleCommand.GetParameter(0).Value = itemId; + _deletePeopleCommand.Transaction = transaction; - 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++; - } - } - } + _deletePeopleCommand.ExecuteNonQuery(); - transaction.Commit(); + var listIndex = 0; - } - catch (OperationCanceledException) + foreach (var person in people) { - if (transaction != null) - { - transaction.Rollback(); - } + 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; - throw; + _savePersonCommand.Transaction = transaction; + + _savePersonCommand.ExecuteNonQuery(); + listIndex++; } - catch (Exception e) + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) { - Logger.ErrorException("Failed to save people:", e); + transaction.Rollback(); + } - if (transaction != null) - { - transaction.Rollback(); - } + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save people:", e); - throw; + if (transaction != null) + { + 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"; + var cmdText = "select " + string.Join(",", _mediaStreamSaveColumns) + " from mediastreams where"; - cmdText += " ItemId=@ItemId"; - cmd.Parameters.Add(cmd, "@ItemId", DbType.Guid).Value = query.ItemId; + 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.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; - } + if (query.Index.HasValue) + { + cmdText += " AND StreamIndex=@StreamIndex"; + cmd.Parameters.Add(cmd, "@StreamIndex", DbType.Int32).Value = query.Index.Value; + } - cmdText += " order by StreamIndex ASC"; + cmdText += " order by StreamIndex ASC"; - cmd.CommandText = cmdText; + cmd.CommandText = cmdText; - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) { - while (reader.Read()) - { - list.Add(GetMediaStream(reader)); - } + list.Add(GetMediaStream(reader)); } } - - return list; } - } - - 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 - { - transaction = connection.BeginTransaction(); + // First delete chapters + _deleteStreamsCommand.GetParameter(0).Value = id; - // First delete - DeleteMediaStreams(connection, transaction, id); + _deleteStreamsCommand.Transaction = transaction; - 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())); - - foreach (var col in _mediaStreamSaveColumns) - { - saveStreamCommand.Parameters.Add(saveStreamCommand, "@" + col); - } - - if (streams.Count > 1) - { - saveStreamCommand.Prepare(); - } - - foreach (var stream in streams) - { - cancellationToken.ThrowIfCancellationRequested(); - - var index = 0; - - 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.IsInterlaced; - - 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(); - } - } - } + _deleteStreamsCommand.ExecuteNonQuery(); - transaction.Commit(); - } - catch (OperationCanceledException) + foreach (var stream in streams) { - if (transaction != null) - { - transaction.Rollback(); - } + cancellationToken.ThrowIfCancellationRequested(); + + var index = 0; + + _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; - throw; + _saveStreamCommand.GetParameter(index++).Value = stream.IsInterlaced; + + _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(); } - catch (Exception e) + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) { - Logger.ErrorException("Failed to save media streams:", e); + transaction.Rollback(); + } - if (transaction != null) - { - transaction.Rollback(); - } + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save media streams:", e); - throw; + if (transaction != null) + { + 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)) - { - IDbTransaction transaction = null; - - try - { - transaction = connection.BeginTransaction(); - - 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; + await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); - cmd.Transaction = transaction; + IDbTransaction transaction = null; - cmd.ExecuteNonQuery(); - } + try + { + transaction = _connection.BeginTransaction(); - transaction.Commit(); - } - catch (OperationCanceledException) + using (var cmd = _connection.CreateCommand()) { - if (transaction != null) - { - transaction.Rollback(); - } + 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)"; - throw; + 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.ExecuteNonQuery(); } - catch (Exception e) + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) { - Logger.ErrorException("Failed to save user data:", e); + transaction.Rollback(); + } - if (transaction != null) - { - transaction.Rollback(); - } + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save user data:", e); - throw; + if (transaction != null) + { + 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)) - { - IDbTransaction transaction = null; + await WriteLock.WaitAsync(cancellationToken).ConfigureAwait(false); - try - { - transaction = connection.BeginTransaction(); + IDbTransaction transaction = null; - foreach (var userItemData in userData) - { - 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.Transaction = transaction; - - cmd.ExecuteNonQuery(); - } - - cancellationToken.ThrowIfCancellationRequested(); - } + try + { + transaction = _connection.BeginTransaction(); - transaction.Commit(); - } - catch (OperationCanceledException) + foreach (var userItemData in userData) { - if (transaction != null) + using (var cmd = _connection.CreateCommand()) { - transaction.Rollback(); + 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.Transaction = transaction; + + cmd.ExecuteNonQuery(); } - throw; + cancellationToken.ThrowIfCancellationRequested(); } - catch (Exception e) + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) { - Logger.ErrorException("Failed to save user data:", e); + transaction.Rollback(); + } - if (transaction != null) - { - transaction.Rollback(); - } + throw; + } + catch (Exception e) + { + Logger.ErrorException("Failed to save user data:", e); - throw; + if (transaction != null) + { + transaction.Rollback(); } - finally + + throw; + } + finally + { + if (transaction != null) { - if (transaction != null) - { - transaction.Dispose(); - } + 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.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; + 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 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 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()); + 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 = "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.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; + cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; - 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 ReadRow(reader); - } + return ReadRow(reader); } - - return null; } + + 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.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; + cmd.Parameters.Add(cmd, "@userId", DbType.Guid).Value = userId; - using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + 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; } -- cgit v1.2.3 From 5f1bf17030853886feebfab97e7155571ea07a97 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 14 Jun 2016 00:15:13 -0400 Subject: update forms --- MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs') diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs index b1206c297a..40cac82c32 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs @@ -33,7 +33,9 @@ namespace MediaBrowser.Server.Implementations.Persistence SyncMode = SynchronizationModes.Normal, DataSource = dbPath, JournalMode = SQLiteJournalModeEnum.Wal, - Pooling = enablePooling, + + // This is causing crashing under linux + Pooling = Environment.OSVersion.Platform == PlatformID.Win32NT, ReadOnly = isReadOnly }; -- cgit v1.2.3 From 66c86ccc58d1022bdb65d63b47df82845ad921c7 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Tue, 14 Jun 2016 15:21:26 -0400 Subject: update pooling --- .../HttpServer/LoggerUtils.cs | 2 +- .../LiveTv/Listings/XmlTvListingsProvider.cs | 6 +- .../Persistence/SqliteExtensions.cs | 2 +- .../TV/TVSeriesManager.cs | 101 ++++++++++++--------- 4 files changed, 67 insertions(+), 44 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs') diff --git a/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs b/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs index ce81000254..bfbb228edf 100644 --- a/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs +++ b/MediaBrowser.Server.Implementations/HttpServer/LoggerUtils.cs @@ -35,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.HttpServer public static void LogResponse(ILogger logger, int statusCode, string url, string endPoint, TimeSpan duration) { var durationMs = duration.TotalMilliseconds; - var logSuffix = durationMs >= 1000 ? "ms (slow)" : "ms"; + var logSuffix = durationMs >= 1000 && durationMs < 60000 ? "ms (slow)" : "ms"; logger.Info("HTTP Response {0} to {1}. Time: {2}{3}. {4}", statusCode, endPoint, Convert.ToInt32(durationMs).ToString(CultureInfo.InvariantCulture), logSuffix, url); } diff --git a/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs index 1628ddc019..07affb865c 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs @@ -45,6 +45,8 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings private async Task GetXml(string path, CancellationToken cancellationToken) { + _logger.Info("xmltv path: {0}", path); + if (!path.StartsWith("http", StringComparison.OrdinalIgnoreCase)) { return path; @@ -161,7 +163,9 @@ namespace MediaBrowser.Server.Implementations.LiveTv.Listings { Id = c.Id, Name = c.DisplayName, - ImageUrl = c.Icon != null && !String.IsNullOrEmpty(c.Icon.Source) ? c.Icon.Source : null + ImageUrl = c.Icon != null && !String.IsNullOrEmpty(c.Icon.Source) ? c.Icon.Source : null, + Number = c.Id + }).ToList(); } } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs index 40cac82c32..73b3a22531 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs @@ -35,7 +35,7 @@ namespace MediaBrowser.Server.Implementations.Persistence JournalMode = SQLiteJournalModeEnum.Wal, // This is causing crashing under linux - Pooling = Environment.OSVersion.Platform == PlatformID.Win32NT, + Pooling = enablePooling && Environment.OSVersion.Platform == PlatformID.Win32NT, ReadOnly = isReadOnly }; diff --git a/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs b/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs index d57aea08e2..4aff3b6ef3 100644 --- a/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs +++ b/MediaBrowser.Server.Implementations/TV/TVSeriesManager.cs @@ -124,58 +124,77 @@ namespace MediaBrowser.Server.Implementations.TV /// Task{Episode}. private Tuple GetNextUp(Series series, User user) { - // Get them in display order, then reverse - var allEpisodes = series.GetEpisodes(user, false, false) - .Where(i => !i.ParentIndexNumber.HasValue || i.ParentIndexNumber.Value != 0) - .Reverse() - .ToList(); - - Episode lastWatched = null; - var lastWatchedDate = DateTime.MinValue; - Episode nextUp = null; - - var unplayedEpisodes = new List(); - - // Go back starting with the most recent episodes - foreach (var episode in allEpisodes) + var firstUnwatchedEpisode = _libraryManager.GetItemList(new InternalItemsQuery(user) { - var userData = _userDataManager.GetUserData(user, episode); - - if (userData.Played) - { - if (lastWatched != null || nextUp == null) - { - break; - } - - lastWatched = episode; - lastWatchedDate = userData.LastPlayedDate ?? DateTime.MinValue; - } - else - { - unplayedEpisodes.Add(episode); + AncestorWithPresentationUniqueKey = series.PresentationUniqueKey, + IncludeItemTypes = new[] { typeof(Episode).Name }, + SortBy = new[] { ItemSortBy.SortName }, + SortOrder = SortOrder.Ascending, + Limit = 1, + IsPlayed = false, + IsVirtualItem = false - nextUp = episode; - } - } + }).Cast().FirstOrDefault(); - if (lastWatched != null) + if (firstUnwatchedEpisode == null) { - return new Tuple(nextUp, lastWatchedDate, false); + return new Tuple(null, DateTime.MinValue, true); } - Episode firstEpisode = null; - // Find the first unplayed episode. Start from the back of the list since they're in reverse order - for (var i = unplayedEpisodes.Count - 1; i >= 0; i--) + var lastWatchedEpisode = _libraryManager.GetItemList(new InternalItemsQuery(user) { - var unplayedEpisode = unplayedEpisodes[i]; + AncestorWithPresentationUniqueKey = series.PresentationUniqueKey, + IncludeItemTypes = new[] { typeof(Episode).Name }, + SortBy = new[] { ItemSortBy.DatePlayed }, + SortOrder = SortOrder.Descending, + Limit = 1, + IsVirtualItem = false + + }).FirstOrDefault(); + + //// Get them in display order, then reverse + //var allEpisodes = series.GetEpisodes(user, false, false) + // .Where(i => !i.ParentIndexNumber.HasValue || i.ParentIndexNumber.Value != 0) + // .Reverse() + // .ToList(); + + //Episode lastWatched = null; + //var lastWatchedDate = DateTime.MinValue; + //Episode nextUp = null; + + //// Go back starting with the most recent episodes + //foreach (var episode in allEpisodes) + //{ + // var userData = _userDataManager.GetUserData(user, episode); + + // if (userData.Played) + // { + // if (lastWatched != null || nextUp == null) + // { + // break; + // } + + // lastWatched = episode; + // lastWatchedDate = userData.LastPlayedDate ?? DateTime.MinValue; + // } + // else + // { + // nextUp = episode; + // } + //} + + if (lastWatchedEpisode != null) + { + var userData = _userDataManager.GetUserData(user, lastWatchedEpisode); - firstEpisode = unplayedEpisode; - break; + if (userData.LastPlayedDate.HasValue) + { + return new Tuple(firstUnwatchedEpisode, userData.LastPlayedDate.Value, false); + } } // Return the first episode - return new Tuple(firstEpisode, DateTime.MinValue, true); + return new Tuple(firstUnwatchedEpisode, DateTime.MinValue, true); } private QueryResult GetResult(IEnumerable items, int? totalRecordLimit, NextUpQuery query) -- cgit v1.2.3 From 023b12a798d6bf475a3b20488c1921e7fdb68dc5 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Wed, 15 Jun 2016 14:56:37 -0400 Subject: update recording format --- MediaBrowser.Api/StartupWizardService.cs | 2 +- MediaBrowser.Controller/Entities/Folder.cs | 10 +++-- MediaBrowser.Controller/Entities/TV/Series.cs | 23 +++++++---- .../Dto/DtoService.cs | 37 +++++++++++------ .../LiveTv/EmbyTV/EncodedRecorder.cs | 21 +++++----- .../Persistence/SqliteExtensions.cs | 8 +++- .../Persistence/SqliteItemRepository.cs | 47 +++++++++++++++------- .../Persistence/SqliteUserDataRepository.cs | 13 ++++++ .../Migrations/DbMigration.cs | 20 +++++++++ 9 files changed, 129 insertions(+), 52 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs') diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs index 21f87a6117..f4aee080a7 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 = 91; + config.SchemaVersion = 92; } public void Post(UpdateStartupConfiguration request) diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index b2788abe06..3c8d8baece 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -1413,14 +1413,14 @@ namespace MediaBrowser.Controller.Entities return; } - var playedQueryResult = GetItems(new InternalItemsQuery(user) + var unplayedQueryResult = GetItems(new InternalItemsQuery(user) { Recursive = true, IsFolder = false, IsVirtualItem = false, EnableTotalRecordCount = true, Limit = 0, - IsPlayed = true + IsPlayed = false }).Result; @@ -1435,12 +1435,14 @@ namespace MediaBrowser.Controller.Entities }).Result; double recursiveItemCount = allItemsQueryResult.TotalRecordCount; - double playedCount = playedQueryResult.TotalRecordCount; + double unplayedCount = unplayedQueryResult.TotalRecordCount; if (recursiveItemCount > 0) { - dto.PlayedPercentage = (playedCount / recursiveItemCount) * 100; + var unplayedPercentage = (unplayedCount / recursiveItemCount) * 100; + dto.PlayedPercentage = 100 - unplayedPercentage; dto.Played = dto.PlayedPercentage.Value >= 100; + dto.UnplayedItemCount = unplayedQueryResult.TotalRecordCount; } } } diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index cc1378ae1a..1f341ba138 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -186,16 +186,25 @@ namespace MediaBrowser.Controller.Entities.TV var user = query.User; - Func filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); - - IEnumerable items; + if (query.Recursive) + { + query.AncestorWithPresentationUniqueKey = PresentationUniqueKey; + if (query.SortBy.Length == 0) + { + query.SortBy = new[] { ItemSortBy.SortName }; + } + if (query.IncludeItemTypes.Length == 0) + { + query.IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name }; + } + query.IsVirtualItem = false; + return Task.FromResult(LibraryManager.GetItemsResult(query)); + } - items = query.Recursive - ? GetSeasons(user).Cast().Concat(GetEpisodes(user)).Where(filter) - : GetSeasons(user).Where(filter); + Func filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); + var items = GetSeasons(user).Where(filter); var result = PostFilterAndSort(items, query); - return Task.FromResult(result); } diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index 2c31a8aae9..a2d895e2c1 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -469,22 +469,31 @@ namespace MediaBrowser.Server.Implementations.Dto { if (item.IsFolder) { - var userData = _userDataRepository.GetUserData(user, item); - - // Skip the user data manager because we've already looped through the recursive tree and don't want to do it twice - // TODO: Improve in future - dto.UserData = GetUserItemDataDto(userData); - var folder = (Folder)item; - if (item.SourceType == SourceType.Library) + if (fields.Contains(ItemFields.SyncInfo)) { - dto.ChildCount = GetChildCount(folder, user); + var userData = _userDataRepository.GetUserData(user, item); + + // Skip the user data manager because we've already looped through the recursive tree and don't want to do it twice + // TODO: Improve in future + dto.UserData = GetUserItemDataDto(userData); - if (folder.SupportsUserDataFromChildren) + if (item.SourceType == SourceType.Library && folder.SupportsUserDataFromChildren) { SetSpecialCounts(folder, user, dto, fields, syncProgress); } + + dto.UserData.Played = dto.UserData.PlayedPercentage.HasValue && dto.UserData.PlayedPercentage.Value >= 100; + } + else + { + dto.UserData = _userDataRepository.GetUserDataDto(item, user); + } + + if (item.SourceType == SourceType.Library) + { + dto.ChildCount = GetChildCount(folder, user); } if (fields.Contains(ItemFields.CumulativeRunTimeTicks)) @@ -496,8 +505,6 @@ namespace MediaBrowser.Server.Implementations.Dto { dto.DateLastMediaAdded = folder.DateLastMediaAdded; } - - dto.UserData.Played = dto.UserData.PlayedPercentage.HasValue && dto.UserData.PlayedPercentage.Value >= 100; } else @@ -1586,12 +1593,18 @@ namespace MediaBrowser.Server.Implementations.Dto /// Task. private void SetSpecialCounts(Folder folder, User user, BaseItemDto dto, List fields, Dictionary syncProgress) { + var addSyncInfo = fields.Contains(ItemFields.SyncInfo); + + if (!addSyncInfo) + { + return; + } + var recursiveItemCount = 0; var unplayed = 0; double totalPercentPlayed = 0; double totalSyncPercent = 0; - var addSyncInfo = fields.Contains(ItemFields.SyncInfo); var children = folder.GetItems(new InternalItemsQuery { diff --git a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs index ffd5b65e41..13158d3461 100644 --- a/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs +++ b/MediaBrowser.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs @@ -44,16 +44,6 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV public string GetOutputPath(MediaSourceInfo mediaSource, string targetFile) { - if (_liveTvOptions.EnableOriginalAudioWithEncodedRecordings) - { - // if the audio is aac_latm, stream copying to mp4 will fail - 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, ".ts"); - } - } - return Path.ChangeExtension(targetFile, ".mp4"); } @@ -159,9 +149,16 @@ namespace MediaBrowser.Server.Implementations.LiveTv.EmbyTV private string GetAudioArgs(MediaSourceInfo mediaSource) { - var copyAudio = new[] { "aac", "mp3" }; + // do not copy aac because many players have difficulty with aac_latm + var copyAudio = new[] { "mp3" }; var mediaStreams = mediaSource.MediaStreams ?? new List(); - if (_liveTvOptions.EnableOriginalAudioWithEncodedRecordings || mediaStreams.Any(i => i.Type == MediaStreamType.Audio && copyAudio.Contains(i.Codec, StringComparer.OrdinalIgnoreCase))) + var inputAudioCodec = mediaStreams.Where(i => i.Type == MediaStreamType.Audio).Select(i => i.Codec).FirstOrDefault() ?? string.Empty; + + if (copyAudio.Contains(inputAudioCodec, StringComparer.OrdinalIgnoreCase)) + { + return "-codec:a:0 copy"; + } + if (_liveTvOptions.EnableOriginalAudioWithEncodedRecordings && !string.Equals(inputAudioCodec, "aac", StringComparison.OrdinalIgnoreCase)) { return "-codec:a:0 copy"; } diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs index 73b3a22531..d5b582da56 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteExtensions.cs @@ -26,6 +26,8 @@ namespace MediaBrowser.Server.Implementations.Persistence throw new ArgumentNullException("dbPath"); } + SQLiteConnection.SetMemoryStatus(false); + var connectionstr = new SQLiteConnectionStringBuilder { PageSize = 4096, @@ -41,8 +43,10 @@ namespace MediaBrowser.Server.Implementations.Persistence var connectionString = connectionstr.ConnectionString; - //logger.Info("Sqlite {0} opening {1}", SQLiteConnection.SQLiteVersion, connectionString); - SQLiteConnection.SetMemoryStatus(false); + if (!enablePooling) + { + logger.Info("Sqlite {0} opening {1}", SQLiteConnection.SQLiteVersion, connectionString); + } var connection = new SQLiteConnection(connectionString); diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 02f5483c5a..04118cb855 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -94,7 +94,7 @@ namespace MediaBrowser.Server.Implementations.Persistence private IDbCommand _updateInheritedRatingCommand; private IDbCommand _updateInheritedTagsCommand; - public const int LatestSchemaVersion = 89; + public const int LatestSchemaVersion = 92; /// /// Initializes a new instance of the class. @@ -122,7 +122,7 @@ namespace MediaBrowser.Server.Implementations.Persistence protected override async Task CreateConnection(bool isReadOnly = false) { - var connection = await DbConnector.Connect(DbFilePath, false, false, 6000).ConfigureAwait(false); + var connection = await DbConnector.Connect(DbFilePath, false, false, 20000).ConfigureAwait(false); connection.RunQueries(new[] { @@ -1789,7 +1789,7 @@ namespace MediaBrowser.Server.Implementations.Persistence var slowThreshold = 1000; #if DEBUG - slowThreshold = 100; + slowThreshold = 80; #endif if (elapsed >= slowThreshold) @@ -1857,13 +1857,22 @@ namespace MediaBrowser.Server.Implementations.Persistence } } + cmd.CommandText += ";"; + + var isReturningZeroItems = query.Limit.HasValue && query.Limit <= 0; + + if (isReturningZeroItems) + { + cmd.CommandText = ""; + } + if (EnableGroupByPresentationUniqueKey(query)) { - cmd.CommandText += "; select count (distinct PresentationUniqueKey)" + GetFromText(); + cmd.CommandText += " select count (distinct PresentationUniqueKey)" + GetFromText(); } else { - cmd.CommandText += "; select count (guid)" + GetFromText(); + cmd.CommandText += " select count (guid)" + GetFromText(); } cmd.CommandText += GetJoinUserDataText(query); @@ -1876,18 +1885,28 @@ namespace MediaBrowser.Server.Implementations.Persistence { LogQueryTime("GetItems", cmd, now); - while (reader.Read()) + if (isReturningZeroItems) { - var item = GetItem(reader); - if (item != null) + if (reader.Read()) { - list.Add(item); + count = reader.GetInt32(0); } } - - if (reader.NextResult() && reader.Read()) + else { - count = reader.GetInt32(0); + while (reader.Read()) + { + var item = GetItem(reader); + if (item != null) + { + list.Add(item); + } + } + + if (reader.NextResult() && reader.Read()) + { + count = reader.GetInt32(0); + } } } @@ -2388,8 +2407,8 @@ namespace MediaBrowser.Server.Implementations.Persistence } if (query.ParentIndexNumberNotEquals.HasValue) { - whereClauses.Add("(ParentIndexNumber<>@ParentIndexNumber or ParentIndexNumber is null)"); - cmd.Parameters.Add(cmd, "@ParentIndexNumber", DbType.Int32).Value = query.ParentIndexNumberNotEquals.Value; + whereClauses.Add("(ParentIndexNumber<>@ParentIndexNumberNotEquals or ParentIndexNumber is null)"); + cmd.Parameters.Add(cmd, "@ParentIndexNumberNotEquals", DbType.Int32).Value = query.ParentIndexNumberNotEquals.Value; } if (query.MinEndDate.HasValue) { diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs index 6edacba535..f40006b443 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteUserDataRepository.cs @@ -39,6 +39,19 @@ namespace MediaBrowser.Server.Implementations.Persistence } } + protected override async Task CreateConnection(bool isReadOnly = false) + { + var connection = await DbConnector.Connect(DbFilePath, false, false, 10000).ConfigureAwait(false); + + connection.RunQueries(new[] + { + "pragma temp_store = memory" + + }, Logger); + + return connection; + } + /// /// Opens the connection to the database /// diff --git a/MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs b/MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs index 65517c09c2..f0cb9e84ee 100644 --- a/MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs +++ b/MediaBrowser.Server.Startup.Common/Migrations/DbMigration.cs @@ -18,6 +18,7 @@ namespace MediaBrowser.Server.Startup.Common.Migrations public void Run() { + // If a forced migration is required, do that now if (_config.Configuration.MigrationVersion < CleanDatabaseScheduledTask.MigrationVersion) { if (!_config.Configuration.IsStartupWizardCompleted) @@ -36,6 +37,25 @@ namespace MediaBrowser.Server.Startup.Common.Migrations _taskManager.Execute(); }); + + return; + } + + if (_config.Configuration.SchemaVersion < SqliteItemRepository.LatestSchemaVersion) + { + if (!_config.Configuration.IsStartupWizardCompleted) + { + _config.Configuration.SchemaVersion = SqliteItemRepository.LatestSchemaVersion; + _config.SaveConfiguration(); + return; + } + + Task.Run(async () => + { + await Task.Delay(1000).ConfigureAwait(false); + + _taskManager.Execute(); + }); } } } -- cgit v1.2.3