improve session manager

This commit is contained in:
Jan Eggers
2018-06-20 08:20:54 +02:00
parent 66048931a2
commit 64b38487bc
@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using MQTTnet.Adapter; using MQTTnet.Adapter;
@@ -14,7 +15,11 @@ namespace MQTTnet.Server
public class MqttClientSessionsManager public class MqttClientSessionsManager
{ {
private readonly BlockingCollection<MqttEnqueuedApplicationMessage> _messageQueue = new BlockingCollection<MqttEnqueuedApplicationMessage>(); private readonly BlockingCollection<MqttEnqueuedApplicationMessage> _messageQueue = new BlockingCollection<MqttEnqueuedApplicationMessage>();
private readonly ConcurrentDictionary<string, MqttClientSession> _sessions = new ConcurrentDictionary<string, MqttClientSession>();
/// <summary>
/// manual locking dictionaries is faster than using concurrent dictionary
/// </summary>
private readonly Dictionary<string, MqttClientSession> _sessions = new Dictionary<string, MqttClientSession>();
private readonly CancellationToken _cancellationToken; private readonly CancellationToken _cancellationToken;
@@ -43,12 +48,16 @@ namespace MQTTnet.Server
public Task StopAsync() public Task StopAsync()
{ {
foreach (var session in _sessions) lock (_sessions)
{ {
session.Value.Stop(MqttClientDisconnectType.NotClean); foreach (var session in _sessions)
} {
session.Value.Stop(MqttClientDisconnectType.NotClean);
}
_sessions.Clear(); _sessions.Clear();
}
_messageQueue.Dispose();
return Task.FromResult(0); return Task.FromResult(0);
} }
@@ -60,10 +69,11 @@ namespace MQTTnet.Server
public Task<IList<IMqttClientSessionStatus>> GetClientStatusAsync() public Task<IList<IMqttClientSessionStatus>> GetClientStatusAsync()
{ {
var result = new List<IMqttClientSessionStatus>(); var result = new List<IMqttClientSessionStatus>();
foreach (var session in _sessions)
foreach (var session in GetSessions())
{ {
var status = new MqttClientSessionStatus(this, session.Value); var status = new MqttClientSessionStatus(this, session);
session.Value.FillStatus(status); session.FillStatus(status);
result.Add(status); result.Add(status);
} }
@@ -83,12 +93,15 @@ namespace MQTTnet.Server
if (clientId == null) throw new ArgumentNullException(nameof(clientId)); if (clientId == null) throw new ArgumentNullException(nameof(clientId));
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters)); if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
if (!_sessions.TryGetValue(clientId, out var session)) lock (_sessions)
{ {
throw new InvalidOperationException($"Client session '{clientId}' is unknown."); if (!_sessions.TryGetValue(clientId, out var session))
} {
throw new InvalidOperationException($"Client session '{clientId}' is unknown.");
}
return session.SubscribeAsync(topicFilters); return session.SubscribeAsync(topicFilters);
}
} }
public Task UnsubscribeAsync(string clientId, IList<string> topicFilters) public Task UnsubscribeAsync(string clientId, IList<string> topicFilters)
@@ -96,17 +109,23 @@ namespace MQTTnet.Server
if (clientId == null) throw new ArgumentNullException(nameof(clientId)); if (clientId == null) throw new ArgumentNullException(nameof(clientId));
if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters)); if (topicFilters == null) throw new ArgumentNullException(nameof(topicFilters));
if (!_sessions.TryGetValue(clientId, out var session)) lock (_sessions)
{ {
throw new InvalidOperationException($"Client session '{clientId}' is unknown."); if (!_sessions.TryGetValue(clientId, out var session))
} {
throw new InvalidOperationException($"Client session '{clientId}' is unknown.");
}
return session.UnsubscribeAsync(topicFilters); return session.UnsubscribeAsync(topicFilters);
}
} }
public void DeleteSession(string clientId) public void DeleteSession(string clientId)
{ {
_sessions.TryRemove(clientId, out _); lock (_sessions)
{
_sessions.Remove(clientId);
}
_logger.Verbose("Session for client '{0}' deleted.", clientId); _logger.Verbose("Session for client '{0}' deleted.", clientId);
} }
@@ -143,7 +162,7 @@ namespace MQTTnet.Server
_retainedMessagesManager.HandleMessageAsync(sender?.ClientId, applicationMessage).GetAwaiter().GetResult(); _retainedMessagesManager.HandleMessageAsync(sender?.ClientId, applicationMessage).GetAwaiter().GetResult();
} }
foreach (var clientSession in _sessions.Values) foreach (var clientSession in GetSessions())
{ {
clientSession.EnqueueApplicationMessage(enqueuedApplicationMessage.Sender, applicationMessage); clientSession.EnqueueApplicationMessage(enqueuedApplicationMessage.Sender, applicationMessage);
} }
@@ -158,6 +177,14 @@ namespace MQTTnet.Server
} }
} }
private List<MqttClientSession> GetSessions()
{
lock (_sessions)
{
return _sessions.Values.ToList();
}
}
private async Task RunSession(IMqttChannelAdapter clientAdapter, CancellationToken cancellationToken) private async Task RunSession(IMqttChannelAdapter clientAdapter, CancellationToken cancellationToken)
{ {
var clientId = string.Empty; var clientId = string.Empty;
@@ -263,7 +290,7 @@ namespace MQTTnet.Server
{ {
if (connectPacket.CleanSession) if (connectPacket.CleanSession)
{ {
_sessions.TryRemove(connectPacket.ClientId, out _); _sessions.Remove(connectPacket.ClientId);
clientSession.Stop(MqttClientDisconnectType.Clean); clientSession.Stop(MqttClientDisconnectType.Clean);
clientSession.Dispose(); clientSession.Dispose();