Don't take a lock if there's no intention to manipulate the list of open streams. Instead, use a ConcurrentDictionary so that, in those situations, thread-safe access to the dictionary is ensured.

This commit is contained in:
Ryan Petris 2020-09-23 14:12:26 -07:00
parent e92d8dd195
commit 4db5700e18
No known key found for this signature in database
GPG Key ID: C3D15EFA013E18C2

View File

@ -1,6 +1,7 @@
#pragma warning disable CS1591
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@ -43,7 +44,7 @@ namespace Emby.Server.Implementations.Library
private readonly ILocalizationManager _localizationManager;
private readonly IApplicationPaths _appPaths;
private readonly Dictionary<string, ILiveStream> _openStreams = new Dictionary<string, ILiveStream>(StringComparer.OrdinalIgnoreCase);
private readonly ConcurrentDictionary<string, ILiveStream> _openStreams = new ConcurrentDictionary<string, ILiveStream>(StringComparer.OrdinalIgnoreCase);
private readonly SemaphoreSlim _liveStreamSemaphore = new SemaphoreSlim(1, 1);
private IMediaSourceProvider[] _providers;
@ -582,29 +583,20 @@ namespace Emby.Server.Implementations.Library
mediaSource.InferTotalBitrate();
}
public async Task<IDirectStreamProvider> GetDirectStreamProviderByUniqueId(string uniqueId, CancellationToken cancellationToken)
public Task<IDirectStreamProvider> GetDirectStreamProviderByUniqueId(string uniqueId, CancellationToken cancellationToken)
{
await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try
var info = _openStreams.Values.FirstOrDefault(i =>
{
var info = _openStreams.Values.FirstOrDefault(i =>
var liveStream = i as ILiveStream;
if (liveStream != null)
{
var liveStream = i as ILiveStream;
if (liveStream != null)
{
return string.Equals(liveStream.UniqueId, uniqueId, StringComparison.OrdinalIgnoreCase);
}
return string.Equals(liveStream.UniqueId, uniqueId, StringComparison.OrdinalIgnoreCase);
}
return false;
});
return false;
});
return info as IDirectStreamProvider;
}
finally
{
_liveStreamSemaphore.Release();
}
return Task.FromResult(info as IDirectStreamProvider);
}
public async Task<LiveStreamResponse> OpenLiveStream(LiveStreamRequest request, CancellationToken cancellationToken)
@ -793,29 +785,20 @@ namespace Emby.Server.Implementations.Library
return new Tuple<MediaSourceInfo, IDirectStreamProvider>(info.MediaSource, info as IDirectStreamProvider);
}
private async Task<ILiveStream> GetLiveStreamInfo(string id, CancellationToken cancellationToken)
private Task<ILiveStream> GetLiveStreamInfo(string id, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(id))
{
throw new ArgumentNullException(nameof(id));
}
await _liveStreamSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false);
try
if (_openStreams.TryGetValue(id, out ILiveStream info))
{
if (_openStreams.TryGetValue(id, out ILiveStream info))
{
return info;
}
else
{
throw new ResourceNotFoundException();
}
return Task.FromResult(info);
}
finally
else
{
_liveStreamSemaphore.Release();
return Task.FromException<ILiveStream>(new ResourceNotFoundException());
}
}
@ -844,7 +827,7 @@ namespace Emby.Server.Implementations.Library
if (liveStream.ConsumerCount <= 0)
{
_openStreams.Remove(id);
_openStreams.TryRemove(id, out _);
_logger.LogInformation("Closing live stream {0}", id);