fixes #97 and creates a library dictionary cache to avoid FindById recursion

This commit is contained in:
Luke Pulverenti
2013-03-31 13:39:28 -04:00
parent b7c3bc592f
commit 9f06eb781f
22 changed files with 182 additions and 177 deletions

View File

@@ -4,6 +4,7 @@ using MediaBrowser.Common.ScheduledTasks;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Resolvers;
@@ -73,6 +74,8 @@ namespace MediaBrowser.Server.Implementations.Library
/// <param name="args">The <see cref="ChildrenChangedEventArgs" /> instance containing the event data.</param>
public void ReportLibraryChanged(ChildrenChangedEventArgs args)
{
UpdateLibraryCache(args);
EventHelper.QueueEventIfNotNull(LibraryChanged, this, args, _logger);
}
#endregion
@@ -109,7 +112,28 @@ namespace MediaBrowser.Server.Implementations.Library
/// (typically, multiple user roots). We store them here and be sure they all reference a
/// single instance.
/// </summary>
private ConcurrentDictionary<Guid, BaseItem> ByReferenceItems { get; set; }
private ConcurrentDictionary<Guid, BaseItem> ByReferenceItems { get; set; }
private ConcurrentDictionary<Guid, BaseItem> _libraryItemsCache;
private object _libraryItemsCacheSyncLock = new object();
private bool _libraryItemsCacheInitialized;
private ConcurrentDictionary<Guid, BaseItem> LibraryItemsCache
{
get
{
LazyInitializer.EnsureInitialized(ref _libraryItemsCache, ref _libraryItemsCacheInitialized, ref _libraryItemsCacheSyncLock, CreateLibraryItemsCache);
return _libraryItemsCache;
}
set
{
_libraryItemsCache = value;
if (value == null)
{
_libraryItemsCacheInitialized = false;
}
}
}
/// <summary>
/// Initializes a new instance of the <see cref="LibraryManager" /> class.
@@ -219,7 +243,7 @@ namespace MediaBrowser.Server.Implementations.Library
{
// Any number of configuration settings could change the way the library is refreshed, so do that now
_taskManager.CancelIfRunningAndQueue<RefreshMediaLibraryTask>();
if (refreshPeopleAfterUpdate)
{
_taskManager.CancelIfRunningAndQueue<PeopleValidationTask>();
@@ -227,6 +251,77 @@ namespace MediaBrowser.Server.Implementations.Library
});
}
/// <summary>
/// Creates the library items cache.
/// </summary>
/// <returns>ConcurrentDictionary{GuidBaseItem}.</returns>
private ConcurrentDictionary<Guid, BaseItem> CreateLibraryItemsCache()
{
var items = RootFolder.RecursiveChildren.ToList();
items.Add(RootFolder);
var specialFeatures = items.OfType<Movie>().SelectMany(i => i.SpecialFeatures).ToList();
var localTrailers = items.SelectMany(i => i.LocalTrailers).ToList();
items.AddRange(specialFeatures);
items.AddRange(localTrailers);
// Can't add these right now because there could be separate instances with the same id.
//items.AddRange(_userManager.Users.Select(i => i.RootFolder).Distinct().ToList());
items.AddRange(_userManager.Users.SelectMany(i => i.RootFolder.Children).Where(i => !(i is BasePluginFolder)).Distinct().ToList());
return new ConcurrentDictionary<Guid,BaseItem>(items.ToDictionary(i => i.Id));
}
/// <summary>
/// Updates the library cache.
/// </summary>
/// <param name="args">The <see cref="ChildrenChangedEventArgs"/> instance containing the event data.</param>
private void UpdateLibraryCache(ChildrenChangedEventArgs args)
{
UpdateItemInLibraryCache(args.Folder);
foreach (var item in args.ItemsAdded)
{
UpdateItemInLibraryCache(item);
}
foreach (var item in args.ItemsUpdated)
{
UpdateItemInLibraryCache(item);
}
}
/// <summary>
/// Updates the item in library cache.
/// </summary>
/// <param name="item">The item.</param>
private void UpdateItemInLibraryCache(BaseItem item)
{
LibraryItemsCache.AddOrUpdate(item.Id, item, delegate { return item; });
foreach (var trailer in item.LocalTrailers)
{
// Prevent access to foreach variable in closure
var trailer1 = trailer;
LibraryItemsCache.AddOrUpdate(trailer.Id, trailer, delegate { return trailer1; });
}
var movie = item as Movie;
if (movie != null)
{
foreach (var special in movie.SpecialFeatures)
{
// Prevent access to foreach variable in closure
Video special1 = special;
LibraryItemsCache.AddOrUpdate(special.Id, special, delegate { return special1; });
}
}
}
/// <summary>
/// Resolves the item.
/// </summary>
@@ -647,11 +742,6 @@ 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<double> { }, cancellationToken).ConfigureAwait(false);
//}
}
/// <summary>
@@ -708,32 +798,6 @@ namespace MediaBrowser.Server.Implementations.Library
});
}
/// <summary>
/// Finds a library item by Id and UserId.
/// </summary>
/// <param name="id">The id.</param>
/// <param name="userId">The user id.</param>
/// <param name="userManager">The user manager.</param>
/// <returns>BaseItem.</returns>
/// <exception cref="System.ArgumentNullException">id</exception>
public BaseItem GetItemById(Guid id, Guid userId)
{
if (id == Guid.Empty)
{
throw new ArgumentNullException("id");
}
if (userId == Guid.Empty)
{
throw new ArgumentNullException("userId");
}
var user = _userManager.GetUserById(userId);
var userRoot = user.RootFolder;
return userRoot.FindItemById(id, user);
}
/// <summary>
/// Gets the item by id.
/// </summary>
@@ -747,7 +811,11 @@ namespace MediaBrowser.Server.Implementations.Library
throw new ArgumentNullException("id");
}
return RootFolder.FindItemById(id, null);
BaseItem item;
LibraryItemsCache.TryGetValue(id, out item);
return item;
}
/// <summary>