Fixed: Various performance improvements for large collections
This commit is contained in:
parent
9e68653949
commit
0dccc7e91e
|
@ -0,0 +1,51 @@
|
||||||
|
using FizzWare.NBuilder;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Core.Housekeeping.Housekeepers;
|
||||||
|
using NzbDrone.Core.Profiles.Releases;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class UpdateCleanTitleForSeriesFixture : CoreTest<UpdateCleanTitleForSeries>
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void should_update_clean_title()
|
||||||
|
{
|
||||||
|
var series = Builder<Series>.CreateNew()
|
||||||
|
.With(s => s.Title = "Full Title")
|
||||||
|
.With(s => s.CleanTitle = "unclean")
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
Mocker.GetMock<ISeriesRepository>()
|
||||||
|
.Setup(s => s.All())
|
||||||
|
.Returns(new[] { series });
|
||||||
|
|
||||||
|
Subject.Clean();
|
||||||
|
|
||||||
|
Mocker.GetMock<ISeriesRepository>()
|
||||||
|
.Verify(v => v.Update(It.Is<Series>(s => s.CleanTitle == "fulltitle")), Times.Once());
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_update_unchanged_title()
|
||||||
|
{
|
||||||
|
var series = Builder<Series>.CreateNew()
|
||||||
|
.With(s => s.Title = "Full Title")
|
||||||
|
.With(s => s.CleanTitle = "fulltitle")
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
Mocker.GetMock<ISeriesRepository>()
|
||||||
|
.Setup(s => s.All())
|
||||||
|
.Returns(new[] { series });
|
||||||
|
|
||||||
|
Subject.Clean();
|
||||||
|
|
||||||
|
Mocker.GetMock<ISeriesRepository>()
|
||||||
|
.Verify(v => v.Update(It.Is<Series>(s => s.CleanTitle == "fulltitle")), Times.Never());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -263,6 +263,7 @@
|
||||||
<Compile Include="Housekeeping\Housekeepers\CleanupOrphanedHistoryItemsFixture.cs" />
|
<Compile Include="Housekeeping\Housekeepers\CleanupOrphanedHistoryItemsFixture.cs" />
|
||||||
<Compile Include="Housekeeping\Housekeepers\CleanupOrphanedMetadataFilesFixture.cs" />
|
<Compile Include="Housekeeping\Housekeepers\CleanupOrphanedMetadataFilesFixture.cs" />
|
||||||
<Compile Include="Housekeeping\Housekeepers\CleanupDownloadClientUnavailablePendingReleasesFixture.cs" />
|
<Compile Include="Housekeeping\Housekeepers\CleanupDownloadClientUnavailablePendingReleasesFixture.cs" />
|
||||||
|
<Compile Include="Housekeeping\Housekeepers\UpdateCleanTitleForSeriesFixture.cs" />
|
||||||
<Compile Include="Housekeeping\Housekeepers\CleanupUnusedTagsFixture.cs" />
|
<Compile Include="Housekeeping\Housekeepers\CleanupUnusedTagsFixture.cs" />
|
||||||
<Compile Include="Housekeeping\Housekeepers\CleanupOrphanedPendingReleasesFixture.cs" />
|
<Compile Include="Housekeeping\Housekeepers\CleanupOrphanedPendingReleasesFixture.cs" />
|
||||||
<Compile Include="Housekeeping\Housekeepers\FixFutureDownloadClientStatusTimesFixture.cs" />
|
<Compile Include="Housekeeping\Housekeepers\FixFutureDownloadClientStatusTimesFixture.cs" />
|
||||||
|
|
|
@ -19,8 +19,12 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
|
||||||
|
|
||||||
series.ForEach(s =>
|
series.ForEach(s =>
|
||||||
{
|
{
|
||||||
s.CleanTitle = s.CleanTitle.CleanSeriesTitle();
|
var cleanTitle = s.Title.CleanSeriesTitle();
|
||||||
_seriesRepository.Update(s);
|
if (s.CleanTitle != cleanTitle)
|
||||||
|
{
|
||||||
|
s.CleanTitle = cleanTitle;
|
||||||
|
_seriesRepository.Update(s);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace NzbDrone.Core.SeriesStats
|
||||||
mapper.AddParameter("currentDate", DateTime.UtcNow);
|
mapper.AddParameter("currentDate", DateTime.UtcNow);
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
sb.AppendLine(GetSelectClause());
|
sb.AppendLine(GetSelectClause(false));
|
||||||
sb.AppendLine(GetEpisodeFilesJoin());
|
sb.AppendLine(GetEpisodeFilesJoin());
|
||||||
sb.AppendLine(GetGroupByClause());
|
sb.AppendLine(GetGroupByClause());
|
||||||
var queryText = sb.ToString();
|
var queryText = sb.ToString();
|
||||||
|
@ -43,16 +43,15 @@ namespace NzbDrone.Core.SeriesStats
|
||||||
mapper.AddParameter("seriesId", seriesId);
|
mapper.AddParameter("seriesId", seriesId);
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
sb.AppendLine(GetSelectClause());
|
sb.AppendLine(GetSelectClause(true));
|
||||||
sb.AppendLine(GetEpisodeFilesJoin());
|
sb.AppendLine(GetEpisodeFilesJoin());
|
||||||
sb.AppendLine("WHERE Episodes.SeriesId = @seriesId");
|
|
||||||
sb.AppendLine(GetGroupByClause());
|
sb.AppendLine(GetGroupByClause());
|
||||||
var queryText = sb.ToString();
|
var queryText = sb.ToString();
|
||||||
|
|
||||||
return mapper.Query<SeasonStatistics>(queryText);
|
return mapper.Query<SeasonStatistics>(queryText);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetSelectClause()
|
private string GetSelectClause(bool series)
|
||||||
{
|
{
|
||||||
return @"SELECT Episodes.*, SUM(EpisodeFiles.Size) as SizeOnDisk FROM
|
return @"SELECT Episodes.*, SUM(EpisodeFiles.Size) as SizeOnDisk FROM
|
||||||
(SELECT
|
(SELECT
|
||||||
|
@ -64,7 +63,8 @@ namespace NzbDrone.Core.SeriesStats
|
||||||
SUM(CASE WHEN EpisodeFileId > 0 THEN 1 ELSE 0 END) AS EpisodeFileCount,
|
SUM(CASE WHEN EpisodeFileId > 0 THEN 1 ELSE 0 END) AS EpisodeFileCount,
|
||||||
MIN(CASE WHEN AirDateUtc < @currentDate OR EpisodeFileId > 0 OR Monitored = 0 THEN NULL ELSE AirDateUtc END) AS NextAiringString,
|
MIN(CASE WHEN AirDateUtc < @currentDate OR EpisodeFileId > 0 OR Monitored = 0 THEN NULL ELSE AirDateUtc END) AS NextAiringString,
|
||||||
MAX(CASE WHEN AirDateUtc >= @currentDate OR EpisodeFileId = 0 AND Monitored = 0 THEN NULL ELSE AirDateUtc END) AS PreviousAiringString
|
MAX(CASE WHEN AirDateUtc >= @currentDate OR EpisodeFileId = 0 AND Monitored = 0 THEN NULL ELSE AirDateUtc END) AS PreviousAiringString
|
||||||
FROM Episodes
|
FROM Episodes" +
|
||||||
|
(series ? " WHERE Episodes.SeriesId = @seriesId" : "") + @"
|
||||||
GROUP BY Episodes.SeriesId, Episodes.SeasonNumber) as Episodes";
|
GROUP BY Episodes.SeriesId, Episodes.SeasonNumber) as Episodes";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ namespace NzbDrone.SignalR
|
||||||
{
|
{
|
||||||
public interface IBroadcastSignalRMessage
|
public interface IBroadcastSignalRMessage
|
||||||
{
|
{
|
||||||
|
bool IsConnected { get; }
|
||||||
void BroadcastMessage(SignalRMessage message);
|
void BroadcastMessage(SignalRMessage message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +21,8 @@ namespace NzbDrone.SignalR
|
||||||
private IPersistentConnectionContext Context => ((ConnectionManager)GlobalHost.ConnectionManager).GetConnection(GetType());
|
private IPersistentConnectionContext Context => ((ConnectionManager)GlobalHost.ConnectionManager).GetConnection(GetType());
|
||||||
|
|
||||||
private static string API_KEY;
|
private static string API_KEY;
|
||||||
private readonly Dictionary<string, string> _messageHistory;
|
private readonly Dictionary<string, string> _messageHistory;
|
||||||
|
private HashSet<string> _connections = new HashSet<string>();
|
||||||
|
|
||||||
public NzbDronePersistentConnection(IConfigFileProvider configFileProvider)
|
public NzbDronePersistentConnection(IConfigFileProvider configFileProvider)
|
||||||
{
|
{
|
||||||
|
@ -28,6 +30,17 @@ namespace NzbDrone.SignalR
|
||||||
_messageHistory = new Dictionary<string, string>();
|
_messageHistory = new Dictionary<string, string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsConnected
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (_connections)
|
||||||
|
{
|
||||||
|
return _connections.Count != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void BroadcastMessage(SignalRMessage message)
|
public void BroadcastMessage(SignalRMessage message)
|
||||||
{
|
{
|
||||||
|
@ -59,14 +72,34 @@ namespace NzbDrone.SignalR
|
||||||
|
|
||||||
protected override Task OnConnected(IRequest request, string connectionId)
|
protected override Task OnConnected(IRequest request, string connectionId)
|
||||||
{
|
{
|
||||||
|
lock (_connections)
|
||||||
|
{
|
||||||
|
_connections.Add(connectionId);
|
||||||
|
}
|
||||||
|
|
||||||
return SendVersion(connectionId);
|
return SendVersion(connectionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Task OnReconnected(IRequest request, string connectionId)
|
protected override Task OnReconnected(IRequest request, string connectionId)
|
||||||
{
|
{
|
||||||
|
lock (_connections)
|
||||||
|
{
|
||||||
|
_connections.Add(connectionId);
|
||||||
|
}
|
||||||
|
|
||||||
return SendVersion(connectionId);
|
return SendVersion(connectionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override Task OnDisconnected(IRequest request, string connectionId, bool stopCalled)
|
||||||
|
{
|
||||||
|
lock (_connections)
|
||||||
|
{
|
||||||
|
_connections.Remove(connectionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.OnDisconnected(request, connectionId, stopCalled);
|
||||||
|
}
|
||||||
|
|
||||||
private Task SendVersion(string connectionId)
|
private Task SendVersion(string connectionId)
|
||||||
{
|
{
|
||||||
return Context.Connection.Send(connectionId, new SignalRMessage
|
return Context.Connection.Send(connectionId, new SignalRMessage
|
||||||
|
|
|
@ -25,6 +25,8 @@ namespace Sonarr.Http
|
||||||
|
|
||||||
public void Handle(ModelEvent<TModel> message)
|
public void Handle(ModelEvent<TModel> message)
|
||||||
{
|
{
|
||||||
|
if (!_signalRBroadcaster.IsConnected) return;
|
||||||
|
|
||||||
if (message.Action == ModelAction.Deleted || message.Action == ModelAction.Sync)
|
if (message.Action == ModelAction.Deleted || message.Action == ModelAction.Sync)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(message.Action);
|
BroadcastResourceChange(message.Action);
|
||||||
|
@ -35,6 +37,8 @@ namespace Sonarr.Http
|
||||||
|
|
||||||
protected void BroadcastResourceChange(ModelAction action, int id)
|
protected void BroadcastResourceChange(ModelAction action, int id)
|
||||||
{
|
{
|
||||||
|
if (!_signalRBroadcaster.IsConnected) return;
|
||||||
|
|
||||||
if (action == ModelAction.Deleted)
|
if (action == ModelAction.Deleted)
|
||||||
{
|
{
|
||||||
BroadcastResourceChange(action, new TResource {Id = id});
|
BroadcastResourceChange(action, new TResource {Id = id});
|
||||||
|
@ -48,6 +52,8 @@ namespace Sonarr.Http
|
||||||
|
|
||||||
protected void BroadcastResourceChange(ModelAction action, TResource resource)
|
protected void BroadcastResourceChange(ModelAction action, TResource resource)
|
||||||
{
|
{
|
||||||
|
if (!_signalRBroadcaster.IsConnected) return;
|
||||||
|
|
||||||
if (GetType().Namespace.Contains("V3"))
|
if (GetType().Namespace.Contains("V3"))
|
||||||
{
|
{
|
||||||
var signalRMessage = new SignalRMessage
|
var signalRMessage = new SignalRMessage
|
||||||
|
@ -63,6 +69,8 @@ namespace Sonarr.Http
|
||||||
|
|
||||||
protected void BroadcastResourceChange(ModelAction action)
|
protected void BroadcastResourceChange(ModelAction action)
|
||||||
{
|
{
|
||||||
|
if (!_signalRBroadcaster.IsConnected) return;
|
||||||
|
|
||||||
if (GetType().Namespace.Contains("V3"))
|
if (GetType().Namespace.Contains("V3"))
|
||||||
{
|
{
|
||||||
var signalRMessage = new SignalRMessage
|
var signalRMessage = new SignalRMessage
|
||||||
|
|
Loading…
Reference in New Issue