reduce scanning overhead a bit

This commit is contained in:
Luke Pulverenti 2013-04-15 14:45:58 -04:00
parent 3d9b862430
commit 2b8b98b590
16 changed files with 198 additions and 96 deletions

View File

@ -664,22 +664,6 @@ namespace MediaBrowser.Controller.Dto
return null; return null;
} }
/// <summary>
/// Gets the library update info.
/// </summary>
/// <param name="changeEvent">The <see cref="ChildrenChangedEventArgs" /> instance containing the event data.</param>
/// <returns>LibraryUpdateInfo.</returns>
public static LibraryUpdateInfo GetLibraryUpdateInfo(ChildrenChangedEventArgs changeEvent)
{
return new LibraryUpdateInfo
{
Folder = GetBaseItemInfo(changeEvent.Folder),
ItemsAdded = changeEvent.ItemsAdded.Select(GetBaseItemInfo),
ItemsRemoved = changeEvent.ItemsRemoved.Select(i => i.Id),
ItemsUpdated = changeEvent.ItemsUpdated.Select(i => i.Id)
};
}
/// <summary> /// <summary>
/// Converts a UserItemData to a DTOUserItemData /// Converts a UserItemData to a DTOUserItemData
/// </summary> /// </summary>

View File

@ -659,7 +659,7 @@ namespace MediaBrowser.Controller.Entities
foreach (var tuple in list) foreach (var tuple in list)
{ {
if (tasks.Count > 50) if (tasks.Count > 5)
{ {
await Task.WhenAll(tasks).ConfigureAwait(false); await Task.WhenAll(tasks).ConfigureAwait(false);
} }

View File

@ -49,8 +49,17 @@ namespace MediaBrowser.Controller.Providers
throw new ArgumentNullException(); throw new ArgumentNullException();
} }
var settings = new XmlReaderSettings
{
CheckCharacters = false,
IgnoreProcessingInstructions = true,
IgnoreComments = true,
IgnoreWhitespace = true,
ValidationType = ValidationType.None
};
// Use XmlReader for best performance // Use XmlReader for best performance
using (var reader = XmlReader.Create(metadataFile)) using (var reader = XmlReader.Create(metadataFile, settings))
{ {
reader.MoveToContent(); reader.MoveToContent();

View File

@ -31,6 +31,8 @@ namespace MediaBrowser.Controller.Providers
/// </summary> /// </summary>
protected readonly Guid Id; protected readonly Guid Id;
protected static readonly SemaphoreSlim XmlParsingResourcePool = new SemaphoreSlim(5, 5);
/// <summary> /// <summary>
/// Supportses the specified item. /// Supportses the specified item.
/// </summary> /// </summary>

View File

@ -58,7 +58,7 @@ namespace MediaBrowser.Controller.Providers
/// <returns>Task{System.Boolean}.</returns> /// <returns>Task{System.Boolean}.</returns>
public override Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken) public override Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
{ {
return Task.Run(() => Fetch(item, cancellationToken)); return Fetch(item, cancellationToken);
} }
/// <summary> /// <summary>
@ -67,7 +67,7 @@ namespace MediaBrowser.Controller.Providers
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
private bool Fetch(BaseItem item, CancellationToken cancellationToken) private async Task<bool> Fetch(BaseItem item, CancellationToken cancellationToken)
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
@ -76,7 +76,18 @@ namespace MediaBrowser.Controller.Providers
if (metadataFile.HasValue) if (metadataFile.HasValue)
{ {
var path = metadataFile.Value.Path; var path = metadataFile.Value.Path;
await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
new BaseItemXmlParser<Folder>(Logger).Fetch((Folder)item, path, cancellationToken); new BaseItemXmlParser<Folder>(Logger).Fetch((Folder)item, path, cancellationToken);
}
finally
{
XmlParsingResourcePool.Release();
}
SetLastRefreshed(item, DateTime.UtcNow); SetLastRefreshed(item, DateTime.UtcNow);
return true; return true;
} }

View File

@ -58,7 +58,7 @@ namespace MediaBrowser.Controller.Providers.Movies
/// <returns>Task{System.Boolean}.</returns> /// <returns>Task{System.Boolean}.</returns>
public override Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken) public override Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
{ {
return Task.Run(() => Fetch(item, cancellationToken)); return Fetch(item, cancellationToken);
} }
/// <summary> /// <summary>
@ -67,7 +67,7 @@ namespace MediaBrowser.Controller.Providers.Movies
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
private bool Fetch(BaseItem item, CancellationToken cancellationToken) private async Task<bool> Fetch(BaseItem item, CancellationToken cancellationToken)
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
@ -77,6 +77,11 @@ namespace MediaBrowser.Controller.Providers.Movies
{ {
var path = metadataFile.Value.Path; var path = metadataFile.Value.Path;
var boxset = item as BoxSet; var boxset = item as BoxSet;
await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
if (boxset != null) if (boxset != null)
{ {
new BaseItemXmlParser<BoxSet>(Logger).Fetch(boxset, path, cancellationToken); new BaseItemXmlParser<BoxSet>(Logger).Fetch(boxset, path, cancellationToken);
@ -85,6 +90,12 @@ namespace MediaBrowser.Controller.Providers.Movies
{ {
new BaseItemXmlParser<Movie>(Logger).Fetch((Movie)item, path, cancellationToken); new BaseItemXmlParser<Movie>(Logger).Fetch((Movie)item, path, cancellationToken);
} }
}
finally
{
XmlParsingResourcePool.Release();
}
SetLastRefreshed(item, DateTime.UtcNow); SetLastRefreshed(item, DateTime.UtcNow);
return true; return true;
} }

View File

@ -15,7 +15,8 @@ namespace MediaBrowser.Controller.Providers.TV
/// </summary> /// </summary>
public class EpisodeProviderFromXml : BaseMetadataProvider public class EpisodeProviderFromXml : BaseMetadataProvider
{ {
public EpisodeProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager) : base(logManager, configurationManager) public EpisodeProviderFromXml(ILogManager logManager, IServerConfigurationManager configurationManager)
: base(logManager, configurationManager)
{ {
} }
@ -55,7 +56,7 @@ namespace MediaBrowser.Controller.Providers.TV
/// <returns>Task{System.Boolean}.</returns> /// <returns>Task{System.Boolean}.</returns>
public override Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken) public override Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
{ {
return Task.Run(() => Fetch(item, cancellationToken)); return Fetch(item, cancellationToken);
} }
/// <summary> /// <summary>
@ -84,42 +85,31 @@ namespace MediaBrowser.Controller.Providers.TV
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
private bool Fetch(BaseItem item, CancellationToken cancellationToken) private async Task<bool> Fetch(BaseItem item, CancellationToken cancellationToken)
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
var metadataFile = Path.Combine(item.MetaLocation, Path.ChangeExtension(Path.GetFileName(item.Path), ".xml")); var metadataFile = Path.Combine(item.MetaLocation, Path.ChangeExtension(Path.GetFileName(item.Path), ".xml"));
var episode = (Episode)item; var file = item.ResolveArgs.Parent.ResolveArgs.GetMetaFileByPath(metadataFile);
if (!FetchMetadata(episode, item.ResolveArgs.Parent, metadataFile, cancellationToken))
{
// Don't set last refreshed if we didn't do anything
return false;
}
SetLastRefreshed(item, DateTime.UtcNow);
return true;
}
/// <summary>
/// Fetches the metadata.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="parent">The parent.</param>
/// <param name="metadataFile">The metadata file.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
private bool FetchMetadata(Episode item, Folder parent, string metadataFile, CancellationToken cancellationToken)
{
var file = parent.ResolveArgs.GetMetaFileByPath(metadataFile);
if (!file.HasValue) if (!file.HasValue)
{ {
return false; return false;
} }
new EpisodeXmlParser(Logger).Fetch(item, metadataFile, cancellationToken); await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
new EpisodeXmlParser(Logger).Fetch((Episode)item, metadataFile, cancellationToken);
}
finally
{
XmlParsingResourcePool.Release();
}
SetLastRefreshed(item, DateTime.UtcNow);
return true; return true;
} }
} }

View File

@ -59,7 +59,7 @@ namespace MediaBrowser.Controller.Providers.TV
/// <returns>Task{System.Boolean}.</returns> /// <returns>Task{System.Boolean}.</returns>
public override Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken) public override Task<bool> FetchAsync(BaseItem item, bool force, CancellationToken cancellationToken)
{ {
return Task.Run(() => Fetch(item, cancellationToken)); return Fetch(item, cancellationToken);
} }
/// <summary> /// <summary>
@ -68,7 +68,7 @@ namespace MediaBrowser.Controller.Providers.TV
/// <param name="item">The item.</param> /// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns> /// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
private bool Fetch(BaseItem item, CancellationToken cancellationToken) private async Task<bool> Fetch(BaseItem item, CancellationToken cancellationToken)
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
@ -78,7 +78,17 @@ namespace MediaBrowser.Controller.Providers.TV
{ {
var path = metadataFile.Value.Path; var path = metadataFile.Value.Path;
await XmlParsingResourcePool.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
new SeriesXmlParser(Logger).Fetch((Series)item, path, cancellationToken); new SeriesXmlParser(Logger).Fetch((Series)item, path, cancellationToken);
}
finally
{
XmlParsingResourcePool.Release();
}
SetLastRefreshed(item, DateTime.UtcNow); SetLastRefreshed(item, DateTime.UtcNow);
return true; return true;

View File

@ -9,27 +9,35 @@ namespace MediaBrowser.Model.Entities
public class LibraryUpdateInfo public class LibraryUpdateInfo
{ {
/// <summary> /// <summary>
/// Gets or sets the folder. /// Gets or sets the folders.
/// </summary> /// </summary>
/// <value>The folder.</value> /// <value>The folders.</value>
public BaseItemInfo Folder { get; set; } public List<Guid> Folders { get; set; }
/// <summary> /// <summary>
/// Gets or sets the items added. /// Gets or sets the items added.
/// </summary> /// </summary>
/// <value>The items added.</value> /// <value>The items added.</value>
public IEnumerable<BaseItemInfo> ItemsAdded { get; set; } public List<Guid> ItemsAdded { get; set; }
/// <summary> /// <summary>
/// Gets or sets the items removed. /// Gets or sets the items removed.
/// </summary> /// </summary>
/// <value>The items removed.</value> /// <value>The items removed.</value>
public IEnumerable<Guid> ItemsRemoved { get; set; } public List<Guid> ItemsRemoved { get; set; }
/// <summary> /// <summary>
/// Gets or sets the items updated. /// Gets or sets the items updated.
/// </summary> /// </summary>
/// <value>The items updated.</value> /// <value>The items updated.</value>
public IEnumerable<Guid> ItemsUpdated { get; set; } public List<Guid> ItemsUpdated { get; set; }
public LibraryUpdateInfo()
{
Folders = new List<Guid>();
ItemsAdded = new List<Guid>();
ItemsRemoved = new List<Guid>();
ItemsUpdated = new List<Guid>();
}
} }
} }

View File

@ -21,5 +21,13 @@ namespace MediaBrowser.Model.Weather
/// <value>The forecasts.</value> /// <value>The forecasts.</value>
[ProtoMember(2)] [ProtoMember(2)]
public WeatherForecast[] Forecasts { get; set; } public WeatherForecast[] Forecasts { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="WeatherInfo"/> class.
/// </summary>
public WeatherInfo()
{
Forecasts = new WeatherForecast[] {};
}
} }
} }

View File

@ -55,7 +55,7 @@ namespace MediaBrowser.Server.Implementations.MediaEncoder
/// <summary> /// <summary>
/// The audio image resource pool /// The audio image resource pool
/// </summary> /// </summary>
private readonly SemaphoreSlim _audioImageResourcePool = new SemaphoreSlim(2, 2); private readonly SemaphoreSlim _audioImageResourcePool = new SemaphoreSlim(1, 1);
/// <summary> /// <summary>
/// The _subtitle extraction resource pool /// The _subtitle extraction resource pool

View File

@ -147,6 +147,8 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
{ {
// Image is already in the cache // Image is already in the cache
item.PrimaryImagePath = path; item.PrimaryImagePath = path;
await _libraryManager.SaveItem(item, cancellationToken).ConfigureAwait(false);
} }
} }

View File

@ -2,6 +2,7 @@
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -60,30 +61,21 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param> /// <param name="progress">The progress.</param>
/// <returns>Task.</returns> /// <returns>Task.</returns>
public Task Execute(CancellationToken cancellationToken, IProgress<double> progress) public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
{ {
var videos = _libraryManager.RootFolder.RecursiveChildren.OfType<Video>().Where(v => v.Chapters != null).ToList(); var videos = _libraryManager.RootFolder.RecursiveChildren
.OfType<Video>()
.Where(v => v.Chapters != null && v.Chapters.Count != 0)
.ToList();
var numComplete = 0; var numComplete = 0;
var tasks = videos.Select(v => Task.Run(async () => foreach (var video in videos)
{
try
{
await _kernel.FFMpegManager.PopulateChapterImages(v, cancellationToken, true, true);
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception ex)
{
_logger.ErrorException("Error creating chapter images for {0}", ex, v.Name);
}
finally
{
lock (progress)
{ {
cancellationToken.ThrowIfCancellationRequested();
await _kernel.FFMpegManager.PopulateChapterImages(video, cancellationToken, true, true);
numComplete++; numComplete++;
double percent = numComplete; double percent = numComplete;
percent /= videos.Count; percent /= videos.Count;
@ -91,10 +83,6 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
progress.Report(100 * percent); progress.Report(100 * percent);
} }
} }
}));
return Task.WhenAll(tasks);
}
/// <summary> /// <summary>
/// Gets the name of the task /// Gets the name of the task

View File

@ -176,6 +176,8 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
{ {
// Image is already in the cache // Image is already in the cache
item.PrimaryImagePath = path; item.PrimaryImagePath = path;
await _libraryManager.SaveItem(item, cancellationToken).ConfigureAwait(false);
} }
} }

View File

@ -1,4 +1,6 @@
using MediaBrowser.Common.Events; using System.Linq;
using System.Threading;
using MediaBrowser.Common.Events;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.ScheduledTasks; using MediaBrowser.Common.ScheduledTasks;
@ -8,6 +10,7 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Plugins; using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Updates; using MediaBrowser.Controller.Updates;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging; using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Tasks; using MediaBrowser.Model.Tasks;
using MediaBrowser.Model.Updates; using MediaBrowser.Model.Updates;
@ -49,8 +52,33 @@ namespace MediaBrowser.ServerApplication.EntryPoints
/// </summary> /// </summary>
private readonly IServerApplicationHost _appHost; private readonly IServerApplicationHost _appHost;
/// <summary>
/// The _task manager
/// </summary>
private readonly ITaskManager _taskManager; private readonly ITaskManager _taskManager;
/// <summary>
/// The _library changed sync lock
/// </summary>
private readonly object _libraryChangedSyncLock = new object();
/// <summary>
/// Gets or sets the library update info.
/// </summary>
/// <value>The library update info.</value>
private LibraryUpdateInfo LibraryUpdateInfo { get; set; }
/// <summary>
/// Gets or sets the library update timer.
/// </summary>
/// <value>The library update timer.</value>
private Timer LibraryUpdateTimer { get; set; }
/// <summary>
/// The library update duration
/// </summary>
private const int LibraryUpdateDuration = 60000;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WebSocketEvents" /> class. /// Initializes a new instance of the <see cref="WebSocketEvents" /> class.
/// </summary> /// </summary>
@ -145,7 +173,47 @@ namespace MediaBrowser.ServerApplication.EntryPoints
/// <param name="e">The <see cref="ChildrenChangedEventArgs" /> instance containing the event data.</param> /// <param name="e">The <see cref="ChildrenChangedEventArgs" /> instance containing the event data.</param>
void libraryManager_LibraryChanged(object sender, ChildrenChangedEventArgs e) void libraryManager_LibraryChanged(object sender, ChildrenChangedEventArgs e)
{ {
_serverManager.SendWebSocketMessage("LibraryChanged", () => DtoBuilder.GetLibraryUpdateInfo(e)); lock (_libraryChangedSyncLock)
{
if (LibraryUpdateInfo == null)
{
LibraryUpdateInfo = new LibraryUpdateInfo();
}
if (LibraryUpdateTimer == null)
{
LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration,
Timeout.Infinite);
}
else
{
LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite);
}
LibraryUpdateInfo.Folders.Add(e.Folder.Id);
LibraryUpdateInfo.ItemsAdded.AddRange(e.ItemsAdded.Select(i => i.Id));
LibraryUpdateInfo.ItemsUpdated.AddRange(e.ItemsUpdated.Select(i => i.Id));
LibraryUpdateInfo.ItemsRemoved.AddRange(e.ItemsRemoved.Select(i => i.Id));
}
}
/// <summary>
/// Libraries the update timer callback.
/// </summary>
/// <param name="state">The state.</param>
private void LibraryUpdateTimerCallback(object state)
{
lock (_libraryChangedSyncLock)
{
_serverManager.SendWebSocketMessage("LibraryChanged", LibraryUpdateInfo);
if (LibraryUpdateTimer != null)
{
LibraryUpdateTimer.Dispose();
LibraryUpdateTimer = null;
}
}
} }
/// <summary> /// <summary>
@ -206,6 +274,12 @@ namespace MediaBrowser.ServerApplication.EntryPoints
{ {
if (dispose) if (dispose)
{ {
if (LibraryUpdateTimer != null)
{
LibraryUpdateTimer.Dispose();
LibraryUpdateTimer = null;
}
_userManager.UserDeleted -= userManager_UserDeleted; _userManager.UserDeleted -= userManager_UserDeleted;
_userManager.UserUpdated -= userManager_UserUpdated; _userManager.UserUpdated -= userManager_UserUpdated;

View File

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