From c02ac2a8ca0a01e6951d5ccca13e98a118057505 Mon Sep 17 00:00:00 2001 From: Eric Reed Date: Fri, 15 Mar 2013 15:08:49 -0400 Subject: [PATCH] Manage some items as single instance throughout #54 --- MediaBrowser.Controller/Entities/BaseItem.cs | 6 ++- .../Entities/BasePluginFolder.cs | 3 +- .../Entities/CollectionFolder.cs | 3 +- MediaBrowser.Controller/Entities/Folder.cs | 2 +- .../Library/ILibraryManager.cs | 7 ++++ .../Entities/IByReferenceItem.cs | 16 ++++++++ MediaBrowser.Model/MediaBrowser.Model.csproj | 1 + .../Library/LibraryManager.cs | 40 +++++++++++++++++-- 8 files changed, 70 insertions(+), 8 deletions(-) create mode 100644 MediaBrowser.Model/Entities/IByReferenceItem.cs diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 4f34f2b675..b7d2a75ec7 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -24,7 +24,11 @@ namespace MediaBrowser.Controller.Entities /// public abstract class BaseItem : IHasProviderIds { - /// + private Guid _testId = Guid.NewGuid(); + public Guid TestId + { + get { return _testId; } + } /// /// The trailer folder name /// public const string TrailerFolderName = "trailers"; diff --git a/MediaBrowser.Controller/Entities/BasePluginFolder.cs b/MediaBrowser.Controller/Entities/BasePluginFolder.cs index 7cabcf9f01..ca6cfd246f 100644 --- a/MediaBrowser.Controller/Entities/BasePluginFolder.cs +++ b/MediaBrowser.Controller/Entities/BasePluginFolder.cs @@ -1,5 +1,6 @@ using MediaBrowser.Common.Extensions; using System; +using MediaBrowser.Model.Entities; namespace MediaBrowser.Controller.Entities { @@ -7,7 +8,7 @@ namespace MediaBrowser.Controller.Entities /// Plugins derive from and export this class to create a folder that will appear in the root along /// with all the other actual physical folders in the system. /// - public abstract class BasePluginFolder : Folder, ICollectionFolder + public abstract class BasePluginFolder : Folder, ICollectionFolder, IByReferenceItem { /// /// Gets or sets the id. diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index a3db5ca26a..091cbdc3b5 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -1,4 +1,5 @@ using MediaBrowser.Common.Extensions; +using MediaBrowser.Model.Entities; using MediaBrowser.Model.Tasks; using System; using System.Collections.Concurrent; @@ -15,7 +16,7 @@ namespace MediaBrowser.Controller.Entities /// Specialized Folder class that points to a subset of the physical folders in the system. /// It is created from the user-specific folders within the system root /// - public class CollectionFolder : Folder, ICollectionFolder + public class CollectionFolder : Folder, ICollectionFolder, IByReferenceItem { /// /// Gets a value indicating whether this instance is virtual folder. diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index ef34742df4..9e50969201 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -811,7 +811,7 @@ namespace MediaBrowser.Controller.Entities /// IEnumerable{BaseItem}. protected virtual IEnumerable GetCachedChildren() { - return Kernel.Instance.ItemRepository.RetrieveChildren(this); + return Kernel.Instance.ItemRepository.RetrieveChildren(this).Select(i => i is IByReferenceItem ? LibraryManager.GetOrAddByReferenceItem(i) : i); } /// diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs index dd720d043f..a69e064604 100644 --- a/MediaBrowser.Controller/Library/ILibraryManager.cs +++ b/MediaBrowser.Controller/Library/ILibraryManager.cs @@ -181,5 +181,12 @@ namespace MediaBrowser.Controller.Library /// The search term. /// IEnumerable{BaseItem}. IEnumerable Search(IEnumerable items, string searchTerm); + + /// + /// Ensure supplied item has only one instance throughout + /// + /// + /// The proper instance to the item + BaseItem GetOrAddByReferenceItem(BaseItem item); } } \ No newline at end of file diff --git a/MediaBrowser.Model/Entities/IByReferenceItem.cs b/MediaBrowser.Model/Entities/IByReferenceItem.cs new file mode 100644 index 0000000000..7554ad36de --- /dev/null +++ b/MediaBrowser.Model/Entities/IByReferenceItem.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MediaBrowser.Model.Entities +{ + /// + /// This is a marker class that tells us that a particular item type may be physically resolved + /// more than once within the library and we need to be sure to resolve them all to the same + /// instance of that item. + /// + public interface IByReferenceItem + { + } +} diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index 36f585e5cd..5f76c49cac 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -45,6 +45,7 @@ + diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 549ea9be2a..71fe6e125b 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -105,6 +105,13 @@ namespace MediaBrowser.Server.Implementations.Library /// The configuration manager. private IServerConfigurationManager ConfigurationManager { get; set; } + /// + /// A collection of items that may be referenced from multiple physical places in the library + /// (typically, multiple user roots). We store them here and be sure they all reference a + /// single instance. + /// + private ConcurrentDictionary ByReferenceItems { get; set; } + /// /// Initializes a new instance of the class. /// @@ -120,6 +127,7 @@ namespace MediaBrowser.Server.Implementations.Library _taskManager = taskManager; _userManager = userManager; ConfigurationManager = configurationManager; + ByReferenceItems = new ConcurrentDictionary(); ConfigurationManager.ConfigurationUpdated += kernel_ConfigurationUpdated; @@ -232,11 +240,35 @@ namespace MediaBrowser.Server.Implementations.Library if (item != null) { ResolverHelper.SetInitialItemValues(item, args); + + // Now handle the issue with posibly having the same item referenced from multiple physical + // places within the library. Be sure we always end up with just one instance. + if (item is IByReferenceItem) + { + item = GetOrAddByReferenceItem(item); + } } return item; } + + /// + /// Ensure supplied item has only one instance throughout + /// + /// + /// The proper instance to the item + public BaseItem GetOrAddByReferenceItem(BaseItem item) + { + // Add this item to our list if not there already + if (!ByReferenceItems.TryAdd(item.Id, item)) + { + // Already there - return the existing reference + item = ByReferenceItems[item.Id]; + } + return item; + } + /// /// Resolves a path into a BaseItem /// @@ -617,10 +649,10 @@ namespace MediaBrowser.Server.Implementations.Library // Now validate the entire media library await RootFolder.ValidateChildren(progress, cancellationToken, recursive: true).ConfigureAwait(false); - foreach (var user in _userManager.Users) - { - await user.ValidateMediaLibrary(new Progress { }, cancellationToken).ConfigureAwait(false); - } + //foreach (var user in _userManager.Users) + //{ + // await user.ValidateMediaLibrary(new Progress { }, cancellationToken).ConfigureAwait(false); + //} } ///