From 3510ef3d2beb810c87f8f3d52f95b95110e574d0 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 --- .../Networking/BaseNetworkManager.cs | 15 +++-- .../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, 97 insertions(+), 91 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 bc3dc360f7..527a5fb3e6 100644 --- a/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs +++ b/MediaBrowser.Common.Implementations/Networking/BaseNetworkManager.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; -using System.Threading; using MoreLinq; namespace MediaBrowser.Common.Implementations.Networking @@ -14,14 +13,11 @@ namespace MediaBrowser.Common.Implementations.Networking public abstract class BaseNetworkManager { protected ILogger Logger { get; private set; } - private Timer _clearCacheTimer; + private DateTime _lastRefresh; protected BaseNetworkManager(ILogger logger) { Logger = logger; - - // Can't use network change events due to a crash in Linux - _clearCacheTimer = new Timer(ClearCacheTimerCallback, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)); } private void ClearCacheTimerCallback(object state) @@ -41,15 +37,20 @@ namespace MediaBrowser.Common.Implementations.Networking /// IPAddress. public IEnumerable GetLocalIpAddresses() { - if (_localIpAddresses == null) + var forceRefresh = (DateTime.UtcNow - _lastRefresh).TotalMinutes >= 1; + + if (_localIpAddresses == null || forceRefresh) { lock (_localIpAddressSyncLock) { - if (_localIpAddresses == null) + forceRefresh = (DateTime.UtcNow - _lastRefresh).TotalMinutes >= 1; + + if (_localIpAddresses == null || forceRefresh) { var addresses = GetLocalIpAddressesInternal().ToList(); _localIpAddresses = addresses; + _lastRefresh = DateTime.UtcNow; return addresses; } 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 fe13d8cef0..c7865b6aab 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 @@ -211,6 +203,8 @@ namespace MediaBrowser.Server.Implementations.Channels public async Task RefreshChannels(IProgress progress, CancellationToken cancellationToken) { + _refreshedItems.Clear(); + var allChannelsList = GetAllChannels().ToList(); var numComplete = 0; @@ -1487,12 +1481,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; @@ -1511,8 +1499,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('/') @@ -1547,46 +1533,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; - } - } } } \ No newline at end of file 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; - } } } }