mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-31 03:02:39 +08:00
replace lock/semaphore by readerwriterlockslim to avoid lock contenti… (#1716)
* replace lock/semaphore by readerwriterlockslim to avoid lock contention while dispatch messages * Update MqttClientSubscriptionsManager.cs removed comment out codes * Update ReleaseNotes.md --------- Co-authored-by: Zeheng Feng <hf944813@broadcom.com> Co-authored-by: Christian <6939810+chkr1011@users.noreply.github.com>
This commit is contained in:
co-authored by
Zeheng Feng
Christian
parent
ac41e838ec
commit
b08d11c069
@@ -1 +1,2 @@
|
|||||||
* [Core] Add validation of maximum string lengths (#1718).
|
* [Core] Add validation of maximum string lengths (#1718).
|
||||||
|
* [Server] Improved performance by changing internal locking strategy for subscriptions (#1716, thanks to @zeheng).
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ namespace MQTTnet.Server
|
|||||||
// See the MqttSubscription object for a detailed explanation.
|
// See the MqttSubscription object for a detailed explanation.
|
||||||
readonly Dictionary<string, MqttSession> _sessions = new Dictionary<string, MqttSession>(4096);
|
readonly Dictionary<string, MqttSession> _sessions = new Dictionary<string, MqttSession>(4096);
|
||||||
|
|
||||||
readonly object _sessionsManagementLock = new object();
|
readonly ReaderWriterLockSlim _sessionsManagementLock = new ReaderWriterLockSlim();
|
||||||
readonly HashSet<MqttSession> _subscriberSessions = new HashSet<MqttSession>();
|
readonly HashSet<MqttSession> _subscriberSessions = new HashSet<MqttSession>();
|
||||||
|
|
||||||
public MqttClientSessionsManager(
|
public MqttClientSessionsManager(
|
||||||
@@ -86,7 +86,8 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
MqttSession session;
|
MqttSession session;
|
||||||
|
|
||||||
lock (_sessionsManagementLock)
|
_sessionsManagementLock.EnterWriteLock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
_sessions.TryGetValue(clientId, out session);
|
_sessions.TryGetValue(clientId, out session);
|
||||||
_sessions.Remove(clientId);
|
_sessions.Remove(clientId);
|
||||||
@@ -96,6 +97,10 @@ namespace MQTTnet.Server
|
|||||||
_subscriberSessions.Remove(session);
|
_subscriberSessions.Remove(session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_sessionsManagementLock.ExitWriteLock();
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -173,10 +178,15 @@ namespace MQTTnet.Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<MqttSession> subscriberSessions;
|
List<MqttSession> subscriberSessions;
|
||||||
lock (_sessionsManagementLock)
|
_sessionsManagementLock.EnterReadLock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
subscriberSessions = _subscriberSessions.ToList();
|
subscriberSessions = _subscriberSessions.ToList();
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_sessionsManagementLock.ExitReadLock();
|
||||||
|
}
|
||||||
|
|
||||||
// Calculate application message topic hash once for subscription checks
|
// Calculate application message topic hash once for subscription checks
|
||||||
MqttTopicHash.Calculate(applicationMessage.Topic, out var topicHash, out _, out _);
|
MqttTopicHash.Calculate(applicationMessage.Topic, out var topicHash, out _, out _);
|
||||||
@@ -256,13 +266,23 @@ namespace MQTTnet.Server
|
|||||||
{
|
{
|
||||||
_createConnectionSyncRoot.Dispose();
|
_createConnectionSyncRoot.Dispose();
|
||||||
|
|
||||||
lock (_sessionsManagementLock)
|
_sessionsManagementLock.EnterWriteLock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
foreach (var sessionItem in _sessions)
|
foreach (var sessionItem in _sessions)
|
||||||
{
|
{
|
||||||
sessionItem.Value.Dispose();
|
sessionItem.Value.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_sessionsManagementLock.ExitWriteLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_sessionsManagementLock != null)
|
||||||
|
{
|
||||||
|
_sessionsManagementLock.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public MqttClient GetClient(string id)
|
public MqttClient GetClient(string id)
|
||||||
@@ -310,7 +330,8 @@ namespace MQTTnet.Server
|
|||||||
{
|
{
|
||||||
var result = new List<MqttSessionStatus>();
|
var result = new List<MqttSessionStatus>();
|
||||||
|
|
||||||
lock (_sessionsManagementLock)
|
_sessionsManagementLock.EnterReadLock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
foreach (var sessionItem in _sessions)
|
foreach (var sessionItem in _sessions)
|
||||||
{
|
{
|
||||||
@@ -318,6 +339,10 @@ namespace MQTTnet.Server
|
|||||||
result.Add(sessionStatus);
|
result.Add(sessionStatus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_sessionsManagementLock.ExitReadLock();
|
||||||
|
}
|
||||||
|
|
||||||
return Task.FromResult((IList<MqttSessionStatus>)result);
|
return Task.FromResult((IList<MqttSessionStatus>)result);
|
||||||
}
|
}
|
||||||
@@ -415,7 +440,8 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
public void OnSubscriptionsAdded(MqttSession clientSession, List<string> topics)
|
public void OnSubscriptionsAdded(MqttSession clientSession, List<string> topics)
|
||||||
{
|
{
|
||||||
lock (_sessionsManagementLock)
|
_sessionsManagementLock.EnterWriteLock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (!clientSession.HasSubscribedTopics)
|
if (!clientSession.HasSubscribedTopics)
|
||||||
{
|
{
|
||||||
@@ -428,11 +454,16 @@ namespace MQTTnet.Server
|
|||||||
clientSession.AddSubscribedTopic(topic);
|
clientSession.AddSubscribedTopic(topic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_sessionsManagementLock.ExitWriteLock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnSubscriptionsRemoved(MqttSession clientSession, List<string> subscriptionTopics)
|
public void OnSubscriptionsRemoved(MqttSession clientSession, List<string> subscriptionTopics)
|
||||||
{
|
{
|
||||||
lock (_sessionsManagementLock)
|
_sessionsManagementLock.EnterWriteLock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
foreach (var subscriptionTopic in subscriptionTopics)
|
foreach (var subscriptionTopic in subscriptionTopics)
|
||||||
{
|
{
|
||||||
@@ -445,6 +476,10 @@ namespace MQTTnet.Server
|
|||||||
_subscriberSessions.Remove(clientSession);
|
_subscriberSessions.Remove(clientSession);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_sessionsManagementLock.ExitWriteLock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
@@ -545,7 +580,8 @@ namespace MQTTnet.Server
|
|||||||
MqttSession oldSession;
|
MqttSession oldSession;
|
||||||
MqttClient oldClient;
|
MqttClient oldClient;
|
||||||
|
|
||||||
lock (_sessionsManagementLock)
|
_sessionsManagementLock.EnterWriteLock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
MqttSession session;
|
MqttSession session;
|
||||||
|
|
||||||
@@ -590,6 +626,10 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
_clients[connectPacket.ClientId] = client;
|
_clients[connectPacket.ClientId] = client;
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_sessionsManagementLock.ExitWriteLock();
|
||||||
|
}
|
||||||
|
|
||||||
if (!connAckPacket.IsSessionPresent)
|
if (!connAckPacket.IsSessionPresent)
|
||||||
{
|
{
|
||||||
@@ -636,7 +676,8 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
MqttSession GetClientSession(string clientId)
|
MqttSession GetClientSession(string clientId)
|
||||||
{
|
{
|
||||||
lock (_sessionsManagementLock)
|
_sessionsManagementLock.EnterReadLock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (!_sessions.TryGetValue(clientId, out var session))
|
if (!_sessions.TryGetValue(clientId, out var session))
|
||||||
{
|
{
|
||||||
@@ -645,6 +686,10 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_sessionsManagementLock.ExitReadLock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async Task<MqttConnectPacket> ReceiveConnectPacket(IMqttChannelAdapter channelAdapter, CancellationToken cancellationToken)
|
async Task<MqttConnectPacket> ReceiveConnectPacket(IMqttChannelAdapter channelAdapter, CancellationToken cancellationToken)
|
||||||
@@ -695,4 +740,4 @@ namespace MQTTnet.Server
|
|||||||
return eventArgs;
|
return eventArgs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace MQTTnet.Server
|
|||||||
readonly Dictionary<string, MqttSubscription> _subscriptions = new Dictionary<string, MqttSubscription>();
|
readonly Dictionary<string, MqttSubscription> _subscriptions = new Dictionary<string, MqttSubscription>();
|
||||||
|
|
||||||
// Use subscription lock to maintain consistency across subscriptions and topic hash dictionaries
|
// Use subscription lock to maintain consistency across subscriptions and topic hash dictionaries
|
||||||
readonly AsyncLock _subscriptionsLock = new AsyncLock();
|
readonly ReaderWriterLockSlim _subscriptionsLock = new ReaderWriterLockSlim();
|
||||||
readonly Dictionary<ulong, TopicHashMaskSubscriptions> _wildcardSubscriptionsByTopicHash = new Dictionary<ulong, TopicHashMaskSubscriptions>();
|
readonly Dictionary<ulong, TopicHashMaskSubscriptions> _wildcardSubscriptionsByTopicHash = new Dictionary<ulong, TopicHashMaskSubscriptions>();
|
||||||
|
|
||||||
public MqttClientSubscriptionsManager(
|
public MqttClientSubscriptionsManager(
|
||||||
@@ -51,7 +51,8 @@ namespace MQTTnet.Server
|
|||||||
var possibleSubscriptions = new List<MqttSubscription>();
|
var possibleSubscriptions = new List<MqttSubscription>();
|
||||||
|
|
||||||
// Check for possible subscriptions. They might have collisions but this is fine.
|
// Check for possible subscriptions. They might have collisions but this is fine.
|
||||||
using (_subscriptionsLock.EnterAsync(CancellationToken.None).GetAwaiter().GetResult())
|
_subscriptionsLock.EnterReadLock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (_noWildcardSubscriptionsByTopicHash.TryGetValue(topicHash, out var noWildcardSubscriptions))
|
if (_noWildcardSubscriptionsByTopicHash.TryGetValue(topicHash, out var noWildcardSubscriptions))
|
||||||
{
|
{
|
||||||
@@ -73,6 +74,10 @@ namespace MQTTnet.Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_subscriptionsLock.ExitReadLock();
|
||||||
|
}
|
||||||
|
|
||||||
// The pre check has evaluated that nothing is subscribed.
|
// The pre check has evaluated that nothing is subscribed.
|
||||||
// If there were some possible candidates they get checked below
|
// If there were some possible candidates they get checked below
|
||||||
@@ -157,7 +162,10 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_subscriptionsLock.Dispose();
|
if (_subscriptionsLock != null)
|
||||||
|
{
|
||||||
|
_subscriptionsLock.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<SubscribeResult> Subscribe(MqttSubscribePacket subscribePacket, CancellationToken cancellationToken)
|
public async Task<SubscribeResult> Subscribe(MqttSubscribePacket subscribePacket, CancellationToken cancellationToken)
|
||||||
@@ -232,7 +240,8 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
var removedSubscriptions = new List<string>();
|
var removedSubscriptions = new List<string>();
|
||||||
|
|
||||||
using (await _subscriptionsLock.EnterAsync(cancellationToken).ConfigureAwait(false))
|
_subscriptionsLock.EnterWriteLock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
foreach (var topicFilter in unsubscribePacket.TopicFilters)
|
foreach (var topicFilter in unsubscribePacket.TopicFilters)
|
||||||
{
|
{
|
||||||
@@ -293,8 +302,11 @@ namespace MQTTnet.Server
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
_subscriptionChangedNotification?.OnSubscriptionsRemoved(_session, removedSubscriptions);
|
{
|
||||||
|
_subscriptionsLock.ExitWriteLock();
|
||||||
|
_subscriptionChangedNotification?.OnSubscriptionsRemoved(_session, removedSubscriptions);
|
||||||
|
}
|
||||||
|
|
||||||
if (_eventContainer.ClientUnsubscribedTopicEvent.HasHandlers)
|
if (_eventContainer.ClientUnsubscribedTopicEvent.HasHandlers)
|
||||||
{
|
{
|
||||||
@@ -341,7 +353,8 @@ namespace MQTTnet.Server
|
|||||||
|
|
||||||
// Add to subscriptions and maintain topic hash dictionaries
|
// Add to subscriptions and maintain topic hash dictionaries
|
||||||
|
|
||||||
using (_subscriptionsLock.EnterAsync(CancellationToken.None).GetAwaiter().GetResult())
|
_subscriptionsLock.EnterWriteLock();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
MqttTopicHash.Calculate(topicFilter.Topic, out var topicHash, out _, out var hasWildcard);
|
MqttTopicHash.Calculate(topicFilter.Topic, out var topicHash, out _, out var hasWildcard);
|
||||||
|
|
||||||
@@ -391,6 +404,10 @@ namespace MQTTnet.Server
|
|||||||
subscriptions.Add(subscription);
|
subscriptions.Add(subscription);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_subscriptionsLock.ExitWriteLock();
|
||||||
|
}
|
||||||
|
|
||||||
return new CreateSubscriptionResult
|
return new CreateSubscriptionResult
|
||||||
{
|
{
|
||||||
@@ -511,4 +528,4 @@ namespace MQTTnet.Server
|
|||||||
public MqttSubscription Subscription { get; set; }
|
public MqttSubscription Subscription { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user