changed ActualChildren to a ConcurrentDictionary to allow for easy add/removes

This commit is contained in:
Luke Pulverenti 2013-05-03 13:46:35 -04:00
parent b5d9cb9fab
commit b531735b0c
4 changed files with 77 additions and 27 deletions

View File

@ -69,7 +69,7 @@ namespace MediaBrowser.Controller.Entities
/// Our children are actually just references to the ones in the physical root... /// Our children are actually just references to the ones in the physical root...
/// </summary> /// </summary>
/// <value>The actual children.</value> /// <value>The actual children.</value>
protected override ConcurrentBag<BaseItem> ActualChildren protected override ConcurrentDictionary<Guid,BaseItem> ActualChildren
{ {
get get
{ {
@ -92,7 +92,7 @@ namespace MediaBrowser.Controller.Entities
.Where(i => folderIds.Contains(i.Id)) .Where(i => folderIds.Contains(i.Id))
.SelectMany(c => c.Children); .SelectMany(c => c.Children);
return new ConcurrentBag<BaseItem>(ourChildren); return new ConcurrentDictionary<Guid,BaseItem>(ourChildren.ToDictionary(i => i.Id));
} }
} }
} }

View File

@ -1,6 +1,5 @@
using MediaBrowser.Common.Extensions; using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Progress; using MediaBrowser.Common.Progress;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Localization;
using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Persistence;
@ -84,6 +83,50 @@ namespace MediaBrowser.Controller.Entities
return (userId + DisplayPreferencesId.ToString()).GetMD5(); return (userId + DisplayPreferencesId.ToString()).GetMD5();
} }
/// <summary>
/// Adds the child.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
/// <exception cref="System.InvalidOperationException">Unable to add + item.Name</exception>
public async Task AddChild(BaseItem item, CancellationToken cancellationToken)
{
if (!_children.TryAdd(item.Id, item))
{
throw new InvalidOperationException("Unable to add " + item.Name);
}
var newChildren = Children.ToList();
await LibraryManager.CreateItem(item, cancellationToken).ConfigureAwait(false);
await LibraryManager.SaveChildren(Id, newChildren, cancellationToken).ConfigureAwait(false);
}
/// <summary>
/// Removes the child.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
/// <exception cref="System.InvalidOperationException">Unable to remove + item.Name</exception>
public Task RemoveChild(BaseItem item, CancellationToken cancellationToken)
{
BaseItem removed;
if (!_children.TryRemove(item.Id, out removed))
{
throw new InvalidOperationException("Unable to remove " + item.Name);
}
var newChildren = Children.ToList();
LibraryManager.ReportItemRemoved(item);
return LibraryManager.SaveChildren(Id, newChildren, cancellationToken);
}
#region Indexing #region Indexing
/// <summary> /// <summary>
@ -400,7 +443,7 @@ namespace MediaBrowser.Controller.Entities
/// <summary> /// <summary>
/// The children /// The children
/// </summary> /// </summary>
private ConcurrentBag<BaseItem> _children; private ConcurrentDictionary<Guid, BaseItem> _children;
/// <summary> /// <summary>
/// The _children initialized /// The _children initialized
/// </summary> /// </summary>
@ -413,7 +456,7 @@ namespace MediaBrowser.Controller.Entities
/// Gets or sets the actual children. /// Gets or sets the actual children.
/// </summary> /// </summary>
/// <value>The actual children.</value> /// <value>The actual children.</value>
protected virtual ConcurrentBag<BaseItem> ActualChildren protected virtual ConcurrentDictionary<Guid,BaseItem> ActualChildren
{ {
get get
{ {
@ -436,11 +479,11 @@ namespace MediaBrowser.Controller.Entities
/// </summary> /// </summary>
/// <value>The children.</value> /// <value>The children.</value>
[IgnoreDataMember] [IgnoreDataMember]
public ConcurrentBag<BaseItem> Children public IEnumerable<BaseItem> Children
{ {
get get
{ {
return ActualChildren; return ActualChildren.Values;
} }
} }
@ -476,10 +519,10 @@ namespace MediaBrowser.Controller.Entities
/// We want this sychronous. /// We want this sychronous.
/// </summary> /// </summary>
/// <returns>ConcurrentBag{BaseItem}.</returns> /// <returns>ConcurrentBag{BaseItem}.</returns>
protected virtual ConcurrentBag<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 //just load our children from the repo - the library will be validated and maintained in other processes
return new ConcurrentBag<BaseItem>(GetCachedChildren()); return new ConcurrentDictionary<Guid,BaseItem>(GetCachedChildren().ToDictionary(i => i.Id));
} }
/// <summary> /// <summary>
@ -565,7 +608,7 @@ namespace MediaBrowser.Controller.Entities
progress.Report(5); progress.Report(5);
//build a dictionary of the current children we have now by Id so we can compare quickly and easily //build a dictionary of the current children we have now by Id so we can compare quickly and easily
var currentChildren = ActualChildren.ToDictionary(i => i.Id); var currentChildren = ActualChildren;
//create a list for our validated children //create a list for our validated children
var validChildren = new ConcurrentBag<Tuple<BaseItem, bool>>(); var validChildren = new ConcurrentBag<Tuple<BaseItem, bool>>();
@ -615,14 +658,15 @@ namespace MediaBrowser.Controller.Entities
//that's all the new and changed ones - now see if there are any that are missing //that's all the new and changed ones - now see if there are any that are missing
var itemsRemoved = currentChildren.Values.Except(newChildren).ToList(); var itemsRemoved = currentChildren.Values.Except(newChildren).ToList();
var childrenReplaced = false; foreach (var item in itemsRemoved)
if (itemsRemoved.Count > 0)
{ {
ActualChildren = new ConcurrentBag<BaseItem>(newChildren); BaseItem removed;
childrenReplaced = true;
foreach (var item in itemsRemoved) if (!_children.TryRemove(item.Id, out removed))
{
Logger.Error("Failed to remove {0}", item.Name);
}
else
{ {
LibraryManager.ReportItemRemoved(item); LibraryManager.ReportItemRemoved(item);
} }
@ -632,19 +676,21 @@ namespace MediaBrowser.Controller.Entities
foreach (var item in newItems) foreach (var item in newItems)
{ {
Logger.Debug("** " + item.Name + " Added to library.");
if (!childrenReplaced)
{
_children.Add(item);
}
if (saveTasks.Count > 50) if (saveTasks.Count > 50)
{ {
await Task.WhenAll(saveTasks).ConfigureAwait(false); await Task.WhenAll(saveTasks).ConfigureAwait(false);
saveTasks.Clear(); saveTasks.Clear();
} }
if (!_children.TryAdd(item.Id, item))
{
Logger.Error("Failed to add {0}", item.Name);
}
else
{
Logger.Debug("** " + item.Name + " Added to library.");
}
saveTasks.Add(LibraryManager.CreateItem(item, CancellationToken.None)); saveTasks.Add(LibraryManager.CreateItem(item, CancellationToken.None));
} }
@ -807,7 +853,7 @@ namespace MediaBrowser.Controller.Entities
} }
// If indexed is false or the indexing function is null // If indexed is false or the indexing function is null
return result ?? (ActualChildren.Where(c => c.IsVisible(user))); return result ?? (Children.Where(c => c.IsVisible(user)));
} }
/// <summary> /// <summary>

View File

@ -1,4 +1,5 @@
using MediaBrowser.Common.Extensions; using System;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
@ -109,7 +110,7 @@ namespace MediaBrowser.Controller.Entities
/// Override to return the children defined to us when we were created /// Override to return the children defined to us when we were created
/// </summary> /// </summary>
/// <value>The actual children.</value> /// <value>The actual children.</value>
protected override ConcurrentBag<BaseItem> LoadChildren() protected override ConcurrentDictionary<Guid,BaseItem> LoadChildren()
{ {
var originalChildSource = ChildSource.ToList(); var originalChildSource = ChildSource.ToList();
@ -134,7 +135,7 @@ namespace MediaBrowser.Controller.Entities
// Now - since we built the index grouping from the bottom up - we now need to properly set Parents from the top down // Now - since we built the index grouping from the bottom up - we now need to properly set Parents from the top down
SetParents(this, kids.OfType<IndexFolder>()); SetParents(this, kids.OfType<IndexFolder>());
return new ConcurrentBag<BaseItem>(kids); return new ConcurrentDictionary<Guid,BaseItem>(kids.ToDictionary(i => i.Id));
} }
/// <summary> /// <summary>

View File

@ -173,4 +173,7 @@ Global
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
EndGlobalSection EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal EndGlobal