diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2013-06-20 12:44:24 -0400 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2013-06-20 12:44:24 -0400 |
| commit | 6bc263052d2b60abfd9023aed0640a37655b6e87 (patch) | |
| tree | 9802812f98e6d00954b82f7fc43f804460700525 | |
| parent | 6f15aeccd0946f19145cc063a8982d585b77df91 (diff) | |
move child definitions to db
15 files changed, 249 insertions, 47 deletions
diff --git a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs index 4c1ce8b99..a0c1a2f0f 100644 --- a/MediaBrowser.Common.Implementations/BaseApplicationHost.cs +++ b/MediaBrowser.Common.Implementations/BaseApplicationHost.cs @@ -408,6 +408,18 @@ namespace MediaBrowser.Common.Implementations } /// <summary> + /// Gets the export types. + /// </summary> + /// <typeparam name="T"></typeparam> + /// <returns>IEnumerable{Type}.</returns> + public IEnumerable<Type> GetExportTypes<T>() + { + var currentType = typeof(T); + + return AllConcreteTypes.AsParallel().Where(currentType.IsAssignableFrom); + } + + /// <summary> /// Gets the exports. /// </summary> /// <typeparam name="T"></typeparam> @@ -415,9 +427,7 @@ namespace MediaBrowser.Common.Implementations /// <returns>IEnumerable{``0}.</returns> public IEnumerable<T> GetExports<T>(bool manageLiftime = true) { - var currentType = typeof(T); - - var parts = AllConcreteTypes.AsParallel().Where(currentType.IsAssignableFrom).Select(CreateInstance).Cast<T>().ToArray(); + var parts = GetExportTypes<T>().Select(CreateInstance).Cast<T>().ToArray(); if (manageLiftime) { diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index cfabbbadb..0d7c1862a 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -143,6 +143,7 @@ namespace MediaBrowser.Controller.Entities public static IServerConfigurationManager ConfigurationManager { get; set; } public static IProviderManager ProviderManager { get; set; } public static ILocalizationManager LocalizationManager { get; set; } + public static IItemRepository ItemRepository { get; set; } /// <summary> /// Returns a <see cref="System.String" /> that represents this instance. diff --git a/MediaBrowser.Controller/Entities/ChildDefinition.cs b/MediaBrowser.Controller/Entities/ChildDefinition.cs new file mode 100644 index 000000000..e8d68b5ea --- /dev/null +++ b/MediaBrowser.Controller/Entities/ChildDefinition.cs @@ -0,0 +1,22 @@ +using System; + +namespace MediaBrowser.Controller.Entities +{ + /// <summary> + /// Class ChildDefinition + /// </summary> + public class ChildDefinition + { + /// <summary> + /// Gets or sets the item id. + /// </summary> + /// <value>The item id.</value> + public Guid ItemId { get; set; } + + /// <summary> + /// Gets or sets the type. + /// </summary> + /// <value>The type.</value> + public string Type { get; set; } + } +} diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index de965221b..762209f70 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -22,14 +22,7 @@ namespace MediaBrowser.Controller.Entities /// </summary> public class Folder : BaseItem { - private static TypeMapper _typeMapper = new TypeMapper(); - - public Folder() - { - ChildDefinitions = new ConcurrentDictionary<Guid, string>(); - } - - public ConcurrentDictionary<Guid, string> ChildDefinitions { get; set; } + private static readonly TypeMapper _typeMapper = new TypeMapper(); /// <summary> /// Gets a value indicating whether this instance is folder. @@ -118,14 +111,19 @@ namespace MediaBrowser.Controller.Entities item.DateModified = DateTime.Now; } - if (!_children.TryAdd(item.Id, item) || !ChildDefinitions.TryAdd(item.Id, item.GetType().FullName)) + if (!_children.TryAdd(item.Id, item)) { throw new InvalidOperationException("Unable to add " + item.Name); } await LibraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false); - await LibraryManager.UpdateItem(this, cancellationToken).ConfigureAwait(false); + await ItemRepository.SaveChildren(Id, _children.Values.ToList().Select(i => new ChildDefinition + { + ItemId = i.Id, + Type = i.GetType().FullName + + }), cancellationToken).ConfigureAwait(false); } /// <summary> @@ -153,18 +151,22 @@ namespace MediaBrowser.Controller.Entities public Task RemoveChild(BaseItem item, CancellationToken cancellationToken) { BaseItem removed; - string removedType; - if (!_children.TryRemove(item.Id, out removed) || !ChildDefinitions.TryRemove(item.Id, out removedType)) + if (!_children.TryRemove(item.Id, out removed)) { throw new InvalidOperationException("Unable to remove " + item.Name); } item.Parent = null; - + LibraryManager.ReportItemRemoved(item); - return LibraryManager.UpdateItem(this, cancellationToken); + return ItemRepository.SaveChildren(Id, _children.Values.ToList().Select(i => new ChildDefinition + { + ItemId = i.Id, + Type = i.GetType().FullName + + }), cancellationToken); } #region Indexing @@ -297,7 +299,7 @@ namespace MediaBrowser.Controller.Entities .Where(i => i != null) .Select(a => new IndexFolder(us, a, songs.Where(i => string.Equals(i.Artist, a.Name, StringComparison.OrdinalIgnoreCase) - ), currentIndexName)).Concat(indexFolders); + ), currentIndexName)).Concat(indexFolders); } return indexFolders; @@ -495,7 +497,7 @@ namespace MediaBrowser.Controller.Entities /// Gets or sets the actual children. /// </summary> /// <value>The actual children.</value> - protected virtual ConcurrentDictionary<Guid,BaseItem> ActualChildren + protected virtual ConcurrentDictionary<Guid, BaseItem> ActualChildren { get { @@ -558,10 +560,10 @@ namespace MediaBrowser.Controller.Entities /// We want this sychronous. /// </summary> /// <returns>ConcurrentBag{BaseItem}.</returns> - protected virtual ConcurrentDictionary<Guid,BaseItem> LoadChildren() + protected virtual ConcurrentDictionary<Guid, BaseItem> LoadChildren() { //just load our children from the repo - the library will be validated and maintained in other processes - return new ConcurrentDictionary<Guid,BaseItem>(GetCachedChildren().ToDictionary(i => i.Id)); + return new ConcurrentDictionary<Guid, BaseItem>(GetCachedChildren().ToDictionary(i => i.Id)); } /// <summary> @@ -709,9 +711,6 @@ namespace MediaBrowser.Controller.Entities } else { - string removedType; - ChildDefinitions.TryRemove(item.Id, out removedType); - LibraryManager.ReportItemRemoved(item); } } @@ -726,13 +725,16 @@ namespace MediaBrowser.Controller.Entities } else { - ChildDefinitions.TryAdd(item.Id, item.GetType().FullName); - Logger.Debug("** " + item.Name + " Added to library."); } } - await LibraryManager.UpdateItem(this, CancellationToken.None).ConfigureAwait(false); + await ItemRepository.SaveChildren(Id, _children.Values.ToList().Select(i => new ChildDefinition + { + ItemId = i.Id, + Type = i.GetType().FullName + + }), cancellationToken).ConfigureAwait(false); //force the indexes to rebuild next time IndexCache.Clear(); @@ -804,7 +806,7 @@ namespace MediaBrowser.Controller.Entities { lock (percentages) { - percentages[child.Id] = p/100; + percentages[child.Id] = p / 100; var percent = percentages.Values.Sum(); percent /= list.Count; @@ -862,7 +864,7 @@ namespace MediaBrowser.Controller.Entities /// <returns>IEnumerable{BaseItem}.</returns> protected IEnumerable<BaseItem> GetCachedChildren() { - var items = ChildDefinitions.ToList().Select(RetrieveChild).Where(i => i != null).ToList(); + var items = ItemRepository.GetChildren(Id).Select(RetrieveChild).Where(i => i != null).ToList(); foreach (var item in items) { @@ -877,9 +879,9 @@ namespace MediaBrowser.Controller.Entities /// </summary> /// <param name="child">The child.</param> /// <returns>BaseItem.</returns> - private BaseItem RetrieveChild(KeyValuePair<Guid,string> child) + private BaseItem RetrieveChild(ChildDefinition child) { - var type = child.Value; + var type = child.Type; var itemType = _typeMapper.GetType(type); @@ -889,7 +891,7 @@ namespace MediaBrowser.Controller.Entities return null; } - var item = LibraryManager.RetrieveItem(child.Key, itemType); + var item = LibraryManager.RetrieveItem(child.ItemId, itemType); return item is IByReferenceItem ? LibraryManager.GetOrAddByReferenceItem(item) : item; } diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index f49221ce8..bea2e9e69 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj @@ -74,6 +74,7 @@ <Compile Include="Dto\SessionInfoDtoBuilder.cs" /> <Compile Include="Entities\Audio\MusicAlbumDisc.cs" /> <Compile Include="Entities\Audio\MusicGenre.cs" /> + <Compile Include="Entities\ChildDefinition.cs" /> <Compile Include="Entities\IByReferenceItem.cs" /> <Compile Include="Entities\MusicVideo.cs" /> <Compile Include="Library\ILibraryPostScanTask.cs" /> diff --git a/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs b/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs index 4d7345f48..ecd8c1136 100644 --- a/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs +++ b/MediaBrowser.Controller/Persistence/IDisplayPreferencesRepository.cs @@ -11,6 +11,12 @@ namespace MediaBrowser.Controller.Persistence public interface IDisplayPreferencesRepository : IRepository { /// <summary> + /// Opens the connection to the repository + /// </summary> + /// <returns>Task.</returns> + Task Initialize(); + + /// <summary> /// Saves display preferences for an item /// </summary> /// <param name="displayPreferences">The display preferences.</param> diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index 534e64a3f..2331ec32f 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -14,6 +14,12 @@ namespace MediaBrowser.Controller.Persistence public interface IItemRepository : IRepository { /// <summary> + /// Opens the connection to the repository + /// </summary> + /// <returns>Task.</returns> + Task Initialize(); + + /// <summary> /// Saves an item /// </summary> /// <param name="item">The item.</param> @@ -75,6 +81,22 @@ namespace MediaBrowser.Controller.Persistence /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> Task SaveChapters(Guid id, IEnumerable<ChapterInfo> chapters, CancellationToken cancellationToken); + + /// <summary> + /// Gets the children. + /// </summary> + /// <param name="parentId">The parent id.</param> + /// <returns>IEnumerable{ChildDefinition}.</returns> + IEnumerable<ChildDefinition> GetChildren(Guid parentId); + + /// <summary> + /// Saves the children. + /// </summary> + /// <param name="parentId">The parent id.</param> + /// <param name="children">The children.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + Task SaveChildren(Guid parentId, IEnumerable<ChildDefinition> children, CancellationToken cancellationToken); } /// <summary> diff --git a/MediaBrowser.Controller/Persistence/IRepository.cs b/MediaBrowser.Controller/Persistence/IRepository.cs index 2d051aa82..f6367c384 100644 --- a/MediaBrowser.Controller/Persistence/IRepository.cs +++ b/MediaBrowser.Controller/Persistence/IRepository.cs @@ -9,12 +9,6 @@ namespace MediaBrowser.Controller.Persistence public interface IRepository : IDisposable { /// <summary> - /// Opens the connection to the repository - /// </summary> - /// <returns>Task.</returns> - Task Initialize(); - - /// <summary> /// Gets the name of the repository /// </summary> /// <value>The name.</value> diff --git a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs index ad111f4ed..bdeaf70dc 100644 --- a/MediaBrowser.Controller/Persistence/IUserDataRepository.cs +++ b/MediaBrowser.Controller/Persistence/IUserDataRepository.cs @@ -11,6 +11,12 @@ namespace MediaBrowser.Controller.Persistence public interface IUserDataRepository : IRepository { /// <summary> + /// Opens the connection to the repository + /// </summary> + /// <returns>Task.</returns> + Task Initialize(); + + /// <summary> /// Saves the user data. /// </summary> /// <param name="userId">The user id.</param> diff --git a/MediaBrowser.Controller/Persistence/IUserRepository.cs b/MediaBrowser.Controller/Persistence/IUserRepository.cs index 80961a369..0241b8c03 100644 --- a/MediaBrowser.Controller/Persistence/IUserRepository.cs +++ b/MediaBrowser.Controller/Persistence/IUserRepository.cs @@ -11,6 +11,12 @@ namespace MediaBrowser.Controller.Persistence public interface IUserRepository : IRepository { /// <summary> + /// Opens the connection to the repository + /// </summary> + /// <returns>Task.</returns> + Task Initialize(); + + /// <summary> /// Deletes the user. /// </summary> /// <param name="user">The user.</param> diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 34930b34e..fde1b77b3 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -64,6 +64,12 @@ <SpecificVersion>False</SpecificVersion> <HintPath>..\packages\ServiceStack.Common.3.9.54\lib\net35\ServiceStack.Interfaces.dll</HintPath> </Reference> + <Reference Include="ServiceStack.OrmLite"> + <HintPath>..\packages\ServiceStack.OrmLite.Sqlite32.3.9.54\lib\net40\ServiceStack.OrmLite.dll</HintPath> + </Reference> + <Reference Include="ServiceStack.OrmLite.SqliteNET"> + <HintPath>..\packages\ServiceStack.OrmLite.Sqlite32.3.9.54\lib\net40\ServiceStack.OrmLite.SqliteNET.dll</HintPath> + </Reference> <Reference Include="ServiceStack.OrmLite.SqlServer, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <SpecificVersion>False</SpecificVersion> <HintPath>..\packages\ServiceStack.OrmLite.SqlServer.3.9.43\lib\ServiceStack.OrmLite.SqlServer.dll</HintPath> diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteChapterRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteChapterRepository.cs index dd6343a67..cac612fc8 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteChapterRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteChapterRepository.cs @@ -27,16 +27,13 @@ namespace MediaBrowser.Server.Implementations.Persistence private SQLiteCommand _saveChapterCommand; /// <summary> - /// Initializes a new instance of the <see cref="SqliteItemRepository"/> class. + /// Initializes a new instance of the <see cref="SqliteItemRepository" /> class. /// </summary> /// <param name="appPaths">The app paths.</param> - /// <param name="jsonSerializer">The json serializer.</param> /// <param name="logManager">The log manager.</param> - /// <exception cref="System.ArgumentNullException"> - /// appPaths + /// <exception cref="System.ArgumentNullException">appPaths /// or - /// jsonSerializer - /// </exception> + /// jsonSerializer</exception> public SqliteChapterRepository(IApplicationPaths appPaths, ILogManager logManager) { if (appPaths == null) diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index b3251ddb9..f0597e4cc 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -56,6 +56,9 @@ namespace MediaBrowser.Server.Implementations.Persistence private SqliteChapterRepository _chapterRepository; + private SQLiteCommand _deleteChildrenCommand; + private SQLiteCommand _saveChildrenCommand; + /// <summary> /// Initializes a new instance of the <see cref="SqliteItemRepository"/> class. /// </summary> @@ -95,7 +98,7 @@ namespace MediaBrowser.Server.Implementations.Persistence public async Task Initialize() { var dbFile = Path.Combine(_appPaths.DataPath, "library.db"); - + _connection = await SqliteExtensions.ConnectToDb(dbFile).ConfigureAwait(false); string[] queries = { @@ -103,6 +106,9 @@ namespace MediaBrowser.Server.Implementations.Persistence "create table if not exists baseitems (guid GUID primary key, data BLOB)", "create index if not exists idx_baseitems on baseitems(guid)", + "create table if not exists ChildDefinitions (ParentId GUID, ItemId GUID, Type TEXT, PRIMARY KEY (ParentId, ItemId))", + "create index if not exists idx_baseitems on baseitems(ParentId,ItemId)", + //pragmas "pragma temp_store = memory" }; @@ -131,6 +137,22 @@ namespace MediaBrowser.Server.Implementations.Persistence _saveItemCommand.Parameters.Add(new SQLiteParameter("@1")); _saveItemCommand.Parameters.Add(new SQLiteParameter("@2")); + + _deleteChildrenCommand = new SQLiteCommand + { + CommandText = "delete from ChildDefinitions where ParentId=@ParentId" + }; + + _deleteChildrenCommand.Parameters.Add(new SQLiteParameter("@ParentId")); + + _saveChildrenCommand = new SQLiteCommand + { + CommandText = "replace into ChildDefinitions (ParentId, ItemId, Type) values (@ParentId, @ItemId, @Type)" + }; + + _saveChildrenCommand.Parameters.Add(new SQLiteParameter("@ParentId")); + _saveChildrenCommand.Parameters.Add(new SQLiteParameter("@ItemId")); + _saveChildrenCommand.Parameters.Add(new SQLiteParameter("@Type")); } /// <summary> @@ -401,5 +423,110 @@ namespace MediaBrowser.Server.Implementations.Persistence } } } + + public IEnumerable<ChildDefinition> GetChildren(Guid parentId) + { + if (parentId == Guid.Empty) + { + throw new ArgumentNullException("parentId"); + } + + using (var cmd = _connection.CreateCommand()) + { + cmd.CommandText = "select ItemId,Type from ChildDefinitions where ParentId = @ParentId"; + + cmd.Parameters.Add("@ParentId", DbType.Guid).Value = parentId; + + using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.SingleResult)) + { + while (reader.Read()) + { + yield return new ChildDefinition + { + ItemId = reader.GetGuid(0), + Type = reader.GetString(1) + }; + } + } + } + } + + public async Task SaveChildren(Guid parentId, IEnumerable<ChildDefinition> children, CancellationToken cancellationToken) + { + if (parentId == Guid.Empty) + { + throw new ArgumentNullException("parentId"); + } + + if (children == null) + { + throw new ArgumentNullException("children"); + } + + if (cancellationToken == null) + { + throw new ArgumentNullException("cancellationToken"); + } + + cancellationToken.ThrowIfCancellationRequested(); + + await _writeLock.WaitAsync(cancellationToken).ConfigureAwait(false); + + SQLiteTransaction transaction = null; + + try + { + transaction = _connection.BeginTransaction(); + + // First delete + _deleteChildrenCommand.Parameters[0].Value = parentId; + _deleteChildrenCommand.Transaction = transaction; + await _deleteChildrenCommand.ExecuteNonQueryAsync(cancellationToken); + + foreach (var chapter in children) + { + cancellationToken.ThrowIfCancellationRequested(); + + _saveChildrenCommand.Parameters[0].Value = parentId; + _saveChildrenCommand.Parameters[1].Value = chapter.ItemId; + _saveChildrenCommand.Parameters[2].Value = chapter.Type; + + _saveChildrenCommand.Transaction = transaction; + + await _saveChildrenCommand.ExecuteNonQueryAsync(cancellationToken); + } + + transaction.Commit(); + } + catch (OperationCanceledException) + { + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + catch (Exception e) + { + _logger.ErrorException("Failed to save children:", e); + + if (transaction != null) + { + transaction.Rollback(); + } + + throw; + } + finally + { + if (transaction != null) + { + transaction.Dispose(); + } + + _writeLock.Release(); + } + } } }
\ No newline at end of file diff --git a/MediaBrowser.Server.Implementations/packages.config b/MediaBrowser.Server.Implementations/packages.config index b3294492f..e13d18747 100644 --- a/MediaBrowser.Server.Implementations/packages.config +++ b/MediaBrowser.Server.Implementations/packages.config @@ -10,6 +10,7 @@ <package id="ServiceStack" version="3.9.54" targetFramework="net45" /> <package id="ServiceStack.Api.Swagger" version="3.9.54" targetFramework="net45" /> <package id="ServiceStack.Common" version="3.9.54" targetFramework="net45" /> + <package id="ServiceStack.OrmLite.Sqlite32" version="3.9.54" targetFramework="net45" /> <package id="ServiceStack.OrmLite.SqlServer" version="3.9.43" targetFramework="net45" /> <package id="ServiceStack.Redis" version="3.9.43" targetFramework="net45" /> <package id="ServiceStack.Text" version="3.9.54" targetFramework="net45" /> diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index 0df0d36f9..f50705834 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -109,7 +109,7 @@ namespace MediaBrowser.ServerApplication return "http://+:" + ServerConfigurationManager.Configuration.HttpServerPortNumber + "/" + WebApplicationName + "/"; } } - + /// <summary> /// Gets the configuration manager. /// </summary> @@ -359,6 +359,7 @@ namespace MediaBrowser.ServerApplication BaseItem.LibraryManager = LibraryManager; BaseItem.ProviderManager = ProviderManager; BaseItem.LocalizationManager = LocalizationManager; + BaseItem.ItemRepository = ItemRepository; User.XmlSerializer = XmlSerializer; User.UserManager = UserManager; LocalizedStrings.ApplicationPaths = ApplicationPaths; @@ -504,7 +505,7 @@ namespace MediaBrowser.ServerApplication // Include composable parts in the Providers assembly yield return typeof(ImagesByNameProvider).Assembly; - + // Common implementations yield return typeof(TaskManager).Assembly; |
