Skip to content

[SignalR] Remove a few minor allocations #13872

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ private async Task StopAsyncCore(bool disposing)
/// </returns>
public IAsyncEnumerable<TResult> StreamAsyncCore<TResult>(string methodName, object[] args, CancellationToken cancellationToken = default)
{
var cts = cancellationToken.CanBeCanceled ? CancellationTokenSource.CreateLinkedTokenSource(cancellationToken) : new CancellationTokenSource();
var cts = cancellationToken.CanBeCanceled ? CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, default) : new CancellationTokenSource();
var stream = CastIAsyncEnumerable<TResult>(methodName, args, cts);
var cancelableStream = AsyncEnumerableAdapters.MakeCancelableTypedAsyncEnumerable(stream, cts);
return cancelableStream;
Expand Down
22 changes: 11 additions & 11 deletions src/SignalR/server/Core/src/DefaultHubLifetimeManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,15 @@ public override Task SendAllAsync(string methodName, object[] args, Cancellation
return SendToAllConnections(methodName, args, null);
}

private Task SendToAllConnections(string methodName, object[] args, Func<HubConnectionContext, bool> include)
private Task SendToAllConnections(string methodName, object[] args, Func<HubConnectionContext, object, bool> include, object state = null)
{
List<Task> tasks = null;
SerializedHubMessage message = null;

// foreach over HubConnectionStore avoids allocating an enumerator
foreach (var connection in _connections)
{
if (include != null && !include(connection))
if (include != null && !include(connection, state))
{
continue;
}
Expand Down Expand Up @@ -127,12 +127,12 @@ private Task SendToAllConnections(string methodName, object[] args, Func<HubConn

// Tasks and message are passed by ref so they can be lazily created inside the method post-filtering,
// while still being re-usable when sending to multiple groups
private void SendToGroupConnections(string methodName, object[] args, ConcurrentDictionary<string, HubConnectionContext> connections, Func<HubConnectionContext, bool> include, ref List<Task> tasks, ref SerializedHubMessage message)
private void SendToGroupConnections(string methodName, object[] args, ConcurrentDictionary<string, HubConnectionContext> connections, Func<HubConnectionContext, object, bool> include, object state, ref List<Task> tasks, ref SerializedHubMessage message)
{
// foreach over ConcurrentDictionary avoids allocating an enumerator
foreach (var connection in connections)
{
if (include != null && !include(connection.Value))
if (include != null && !include(connection.Value, state))
{
continue;
}
Expand Down Expand Up @@ -193,7 +193,7 @@ public override Task SendGroupAsync(string groupName, string methodName, object[
// group might be modified inbetween checking and sending
List<Task> tasks = null;
SerializedHubMessage message = null;
SendToGroupConnections(methodName, args, group, null, ref tasks, ref message);
SendToGroupConnections(methodName, args, group, null, null, ref tasks, ref message);

if (tasks != null)
{
Expand Down Expand Up @@ -221,7 +221,7 @@ public override Task SendGroupsAsync(IReadOnlyList<string> groupNames, string me
var group = _groups[groupName];
if (group != null)
{
SendToGroupConnections(methodName, args, group, null, ref tasks, ref message);
SendToGroupConnections(methodName, args, group, null, null, ref tasks, ref message);
}
}

Expand All @@ -247,7 +247,7 @@ public override Task SendGroupExceptAsync(string groupName, string methodName, o
List<Task> tasks = null;
SerializedHubMessage message = null;

SendToGroupConnections(methodName, args, group, connection => !excludedConnectionIds.Contains(connection.ConnectionId), ref tasks, ref message);
SendToGroupConnections(methodName, args, group, (connection, state) => !((IReadOnlyList<string>)state).Contains(connection.ConnectionId), excludedConnectionIds, ref tasks, ref message);

if (tasks != null)
{
Expand All @@ -271,7 +271,7 @@ private HubMessage CreateInvocationMessage(string methodName, object[] args)
/// <inheritdoc />
public override Task SendUserAsync(string userId, string methodName, object[] args, CancellationToken cancellationToken = default)
{
return SendToAllConnections(methodName, args, connection => string.Equals(connection.UserIdentifier, userId, StringComparison.Ordinal));
return SendToAllConnections(methodName, args, (connection, state) => string.Equals(connection.UserIdentifier, (string)state, StringComparison.Ordinal), userId);
}

/// <inheritdoc />
Expand All @@ -292,19 +292,19 @@ public override Task OnDisconnectedAsync(HubConnectionContext connection)
/// <inheritdoc />
public override Task SendAllExceptAsync(string methodName, object[] args, IReadOnlyList<string> excludedConnectionIds, CancellationToken cancellationToken = default)
{
return SendToAllConnections(methodName, args, connection => !excludedConnectionIds.Contains(connection.ConnectionId));
return SendToAllConnections(methodName, args, (connection, state) => !((IReadOnlyList<string>)state).Contains(connection.ConnectionId), excludedConnectionIds);
}

/// <inheritdoc />
public override Task SendConnectionsAsync(IReadOnlyList<string> connectionIds, string methodName, object[] args, CancellationToken cancellationToken = default)
{
return SendToAllConnections(methodName, args, connection => connectionIds.Contains(connection.ConnectionId));
return SendToAllConnections(methodName, args, (connection, state) => ((IReadOnlyList<string>)state).Contains(connection.ConnectionId), connectionIds);
}

/// <inheritdoc />
public override Task SendUsersAsync(IReadOnlyList<string> userIds, string methodName, object[] args, CancellationToken cancellationToken = default)
{
return SendToAllConnections(methodName, args, connection => userIds.Contains(connection.UserIdentifier));
return SendToAllConnections(methodName, args, (connection, state) => ((IReadOnlyList<string>)state).Contains(connection.UserIdentifier), userIds);
}
}
}
4 changes: 2 additions & 2 deletions src/SignalR/server/Core/src/Internal/DefaultHubDispatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ await SendInvocationError(hubMethodInvocationMessage.InvocationId, connection,
{
if (descriptor.OriginalParameterTypes[parameterPointer] == typeof(CancellationToken))
{
cts = CancellationTokenSource.CreateLinkedTokenSource(connection.ConnectionAborted);
cts = CancellationTokenSource.CreateLinkedTokenSource(connection.ConnectionAborted, default);
arguments[parameterPointer] = cts.Token;
}
else if (isStreamCall && ReflectionHelper.IsStreamingType(descriptor.OriginalParameterTypes[parameterPointer], mustBeDirectType: true))
Expand Down Expand Up @@ -308,7 +308,7 @@ await SendInvocationError(hubMethodInvocationMessage.InvocationId, connection,
return;
}

cts = cts ?? CancellationTokenSource.CreateLinkedTokenSource(connection.ConnectionAborted);
cts = cts ?? CancellationTokenSource.CreateLinkedTokenSource(connection.ConnectionAborted, default);
connection.ActiveRequestCancellationSources.TryAdd(hubMethodInvocationMessage.InvocationId, cts);
var enumerable = descriptor.FromReturnedStream(result, cts.Token);

Expand Down