From cfa8f6c6eca1b58a34a684c17a51b14fb4306f8b Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 28 Jan 2016 22:40:21 -0500 Subject: [PATCH] reduce use of timers throughout the system Conflicts: MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs --- .../Networking/BaseNetworkManager.cs | 13 +++- .../MediaBrowser.Common.csproj | 1 + .../Threading/PeriodicTimer.cs | 67 +++++++++++++++++++ .../People/MovieDbPersonProvider.cs | 18 ++--- .../Channels/ChannelManager.cs | 61 +---------------- .../Connect/ConnectEntryPoint.cs | 5 +- .../EntryPoints/ExternalPortForwarding.cs | 5 +- .../EntryPoints/UsageEntryPoint.cs | 16 ++--- 8 files changed, 99 insertions(+), 87 deletions(-) create mode 100644 MediaBrowser.Common/Threading/PeriodicTimer.cs diff --git a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs index ff11c889a6..527a5fb3e6 100644 --- a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs +++ b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs @@ -20,6 +20,14 @@ namespace MediaBrowser.Common.Implementations.Networking Logger = logger; } + private void ClearCacheTimerCallback(object state) + { + lock (_localIpAddressSyncLock) + { + _localIpAddresses = null; + } + } + private volatile List _localIpAddresses; private readonly object _localIpAddressSyncLock = new object(); @@ -29,14 +37,13 @@ namespace MediaBrowser.Common.Implementations.Networking /// IPAddress. public IEnumerable GetLocalIpAddresses() { - const int cacheMinutes = 3; - var forceRefresh = (DateTime.UtcNow - _lastRefresh).TotalMinutes >= cacheMinutes; + var forceRefresh = (DateTime.UtcNow - _lastRefresh).TotalMinutes >= 1; if (_localIpAddresses == null || forceRefresh) { lock (_localIpAddressSyncLock) { - forceRefresh = (DateTime.UtcNow - _lastRefresh).TotalMinutes >= cacheMinutes; + forceRefresh = (DateTime.UtcNow - _lastRefresh).TotalMinutes >= 1; if (_localIpAddresses == null || forceRefresh) { diff --git a/MediaBrowser.Common/MediaBrowser.Common.csproj b/MediaBrowser.Common/MediaBrowser.Common.csproj index ccdb319fee..17f211d848 100644 --- a/MediaBrowser.Common/MediaBrowser.Common.csproj +++ b/MediaBrowser.Common/MediaBrowser.Common.csproj @@ -90,6 +90,7 @@ + diff --git a/MediaBrowser.Common/Threading/PeriodicTimer.cs b/MediaBrowser.Common/Threading/PeriodicTimer.cs new file mode 100644 index 0000000000..cb562a80dc --- /dev/null +++ b/MediaBrowser.Common/Threading/PeriodicTimer.cs @@ -0,0 +1,67 @@ +using System; +using System.Threading; +using Microsoft.Win32; + +namespace MediaBrowser.Common.Threading +{ + public class PeriodicTimer : IDisposable + { + public Action Callback { get; set; } + private Timer _timer; + private readonly object _state; + private readonly object _timerLock = new object(); + private readonly TimeSpan _period; + + public PeriodicTimer(Action callback, object state, TimeSpan dueTime, TimeSpan period) + { + Callback = callback; + _period = period; + _state = state; + + StartTimer(dueTime); + } + + void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e) + { + if (e.Mode == PowerModes.Resume) + { + DisposeTimer(); + StartTimer(Timeout.InfiniteTimeSpan); + } + } + + private void TimerCallback(object state) + { + Callback(state); + } + + private void StartTimer(TimeSpan dueTime) + { + lock (_timerLock) + { + _timer = new Timer(TimerCallback, _state, dueTime, _period); + + SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged; + } + } + + private void DisposeTimer() + { + SystemEvents.PowerModeChanged -= SystemEvents_PowerModeChanged; + + lock (_timerLock) + { + if (_timer != null) + { + _timer.Dispose(); + _timer = null; + } + } + } + + public void Dispose() + { + DisposeTimer(); + } + } +} diff --git a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs index 5c59197094..14304c2eb5 100644 --- a/MediaBrowser.Providers/People/MovieDbPersonProvider.cs +++ b/MediaBrowser.Providers/People/MovieDbPersonProvider.cs @@ -38,7 +38,7 @@ namespace MediaBrowser.Providers.People private int _requestCount; private readonly object _requestCountLock = new object(); - private Timer _requestCountReset; + private DateTime _lastRequestCountReset; public MovieDbPersonProvider(IFileSystem fileSystem, IServerConfigurationManager configurationManager, IJsonSerializer jsonSerializer, IHttpClient httpClient, ILogger logger) { @@ -48,16 +48,6 @@ namespace MediaBrowser.Providers.People _httpClient = httpClient; _logger = logger; Current = this; - - _requestCountReset = new Timer(OnRequestThrottleTimerFired, null, TimeSpan.FromHours(1), TimeSpan.FromHours(1)); - } - - private void OnRequestThrottleTimerFired(object state) - { - lock (_requestCountLock) - { - _requestCount = 0; - } } public string Name @@ -101,6 +91,12 @@ namespace MediaBrowser.Providers.People { lock (_requestCountLock) { + if ((DateTime.UtcNow - _lastRequestCountReset).TotalHours >= 1) + { + _requestCount = 0; + _lastRequestCountReset = DateTime.UtcNow; + } + var requestCount = _requestCount; if (requestCount >= 5) diff --git a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs index b115c3bfdc..284556c72b 100644 --- a/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs +++ b/MediaBrowser.Server.Implementations/Channels/ChannelManager.cs @@ -29,7 +29,7 @@ using CommonIO; namespace MediaBrowser.Server.Implementations.Channels { - public class ChannelManager : IChannelManager, IDisposable + public class ChannelManager : IChannelManager { private IChannel[] _channels; @@ -47,11 +47,6 @@ namespace MediaBrowser.Server.Implementations.Channels private readonly ILocalizationManager _localization; private readonly ConcurrentDictionary _refreshedItems = new ConcurrentDictionary(); - private readonly ConcurrentDictionary _downloadCounts = new ConcurrentDictionary(); - - private Timer _refreshTimer; - private Timer _clearDownloadCountsTimer; - public ChannelManager(IUserManager userManager, IDtoService dtoService, ILibraryManager libraryManager, ILogger logger, IServerConfigurationManager config, IFileSystem fileSystem, IUserDataManager userDataManager, IJsonSerializer jsonSerializer, ILocalizationManager localization, IHttpClient httpClient, IProviderManager providerManager) { _userManager = userManager; @@ -65,9 +60,6 @@ namespace MediaBrowser.Server.Implementations.Channels _localization = localization; _httpClient = httpClient; _providerManager = providerManager; - - _refreshTimer = new Timer(s => _refreshedItems.Clear(), null, TimeSpan.FromHours(3), TimeSpan.FromHours(3)); - _clearDownloadCountsTimer = new Timer(s => _downloadCounts.Clear(), null, TimeSpan.FromHours(24), TimeSpan.FromHours(24)); } private TimeSpan CacheLength @@ -206,6 +198,8 @@ namespace MediaBrowser.Server.Implementations.Channels public async Task RefreshChannels(IProgress progress, CancellationToken cancellationToken) { + _refreshedItems.Clear(); + var allChannelsList = GetAllChannels().ToList(); var numComplete = 0; @@ -1471,12 +1465,6 @@ namespace MediaBrowser.Server.Implementations.Channels var limit = features.DailyDownloadLimit; - if (!ValidateDownloadLimit(host, limit)) - { - _logger.Error(string.Format("Download limit has been reached for {0}", channel.Name)); - throw new ChannelDownloadException(string.Format("Download limit has been reached for {0}", channel.Name)); - } - foreach (var header in source.RequiredHttpHeaders) { options.RequestHeaders[header.Key] = header.Value; @@ -1495,8 +1483,6 @@ namespace MediaBrowser.Server.Implementations.Channels }; } - IncrementDownloadCount(host, limit); - if (string.Equals(item.MediaType, MediaType.Video, StringComparison.OrdinalIgnoreCase) && response.ContentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase)) { var extension = response.ContentType.Split('/') @@ -1531,46 +1517,5 @@ namespace MediaBrowser.Server.Implementations.Channels } } - - private void IncrementDownloadCount(string key, int? limit) - { - if (!limit.HasValue) - { - return; - } - - int current; - _downloadCounts.TryGetValue(key, out current); - - current++; - _downloadCounts.AddOrUpdate(key, current, (k, v) => current); - } - - private bool ValidateDownloadLimit(string key, int? limit) - { - if (!limit.HasValue) - { - return true; - } - - int current; - _downloadCounts.TryGetValue(key, out current); - - return current < limit.Value; - } - - public void Dispose() - { - if (_clearDownloadCountsTimer != null) - { - _clearDownloadCountsTimer.Dispose(); - _clearDownloadCountsTimer = null; - } - if (_refreshTimer != null) - { - _refreshTimer.Dispose(); - _refreshTimer = null; - } - } } } diff --git a/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs b/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs index 6dab136a58..0d6b8ac26c 100644 --- a/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs +++ b/MediaBrowser.Server.Implementations/Connect/ConnectEntryPoint.cs @@ -13,12 +13,13 @@ using System.Threading; using System.Threading.Tasks; using CommonIO; using MediaBrowser.Common.IO; +using MediaBrowser.Common.Threading; namespace MediaBrowser.Server.Implementations.Connect { public class ConnectEntryPoint : IServerEntryPoint { - private Timer _timer; + private PeriodicTimer _timer; private readonly IHttpClient _httpClient; private readonly IApplicationPaths _appPaths; private readonly ILogger _logger; @@ -43,7 +44,7 @@ namespace MediaBrowser.Server.Implementations.Connect { Task.Run(() => LoadCachedAddress()); - _timer = new Timer(TimerCallback, null, TimeSpan.FromSeconds(5), TimeSpan.FromHours(3)); + _timer = new PeriodicTimer(null, new TimerCallback(TimerCallback), TimeSpan.FromSeconds(5), TimeSpan.FromHours(3)); } private readonly string[] _ipLookups = { "http://bot.whatismyipaddress.com", "https://connect.emby.media/service/ip" }; diff --git a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs index a2ffa9affb..2b2c338dd3 100644 --- a/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs +++ b/MediaBrowser.Server.Implementations/EntryPoints/ExternalPortForwarding.cs @@ -11,6 +11,7 @@ using System.IO; using System.Net; using System.Text; using System.Threading; +using MediaBrowser.Common.Threading; namespace MediaBrowser.Server.Implementations.EntryPoints { @@ -21,7 +22,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints private readonly IServerConfigurationManager _config; private readonly ISsdpHandler _ssdp; - private Timer _timer; + private PeriodicTimer _timer; private bool _isStarted; public ExternalPortForwarding(ILogManager logmanager, IServerApplicationHost appHost, IServerConfigurationManager config, ISsdpHandler ssdp) @@ -95,7 +96,7 @@ namespace MediaBrowser.Server.Implementations.EntryPoints NatUtility.UnhandledException += NatUtility_UnhandledException; NatUtility.StartDiscovery(); - _timer = new Timer(s => _createdRules = new List(), null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5)); + _timer = new PeriodicTimer(s => _createdRules = new List(), null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5)); _ssdp.MessageReceived += _ssdp_MessageReceived; diff --git a/MediaBrowser.Server.Implementations/EntryPoints/UsageEntryPoint.cs b/MediaBrowser.Server.Implementations/EntryPoints/UsageEntryPoint.cs index c3b9c0d4df..d8aef909bb 100644 --- a/MediaBrowser.Server.Implementations/EntryPoints/UsageEntryPoint.cs +++ b/MediaBrowser.Server.Implementations/EntryPoints/UsageEntryPoint.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; +using System.Threading.Tasks; namespace MediaBrowser.Server.Implementations.EntryPoints { @@ -23,7 +24,6 @@ namespace MediaBrowser.Server.Implementations.EntryPoints private readonly ISessionManager _sessionManager; private readonly IUserManager _userManager; - private Timer _timer; private readonly TimeSpan _frequency = TimeSpan.FromHours(24); private readonly ConcurrentDictionary _apps = new ConcurrentDictionary(); @@ -95,16 +95,16 @@ namespace MediaBrowser.Server.Implementations.EntryPoints return info; } - public void Run() + public async void Run() { - _timer = new Timer(OnTimerFired, null, TimeSpan.FromMilliseconds(5000), _frequency); + await Task.Delay(5000).ConfigureAwait(false); + OnTimerFired(); } /// /// Called when [timer fired]. /// - /// The state. - private async void OnTimerFired(object state) + private async void OnTimerFired() { try { @@ -121,12 +121,6 @@ namespace MediaBrowser.Server.Implementations.EntryPoints public void Dispose() { _sessionManager.SessionStarted -= _sessionManager_SessionStarted; - - if (_timer != null) - { - _timer.Dispose(); - _timer = null; - } } } }