Skip to content

Reduce allocations in GrpcMessageExtensionUtilities.ConvertFromHttpMessageToExpando #11054

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

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
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
10 changes: 4 additions & 6 deletions release_notes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
### Release notes

<!-- Please add your release notes in the following format:
- My change description (#PR)
-->
- Memory allocation optimizations in `ScriptStartupTypeLocator.GetExtensionsStartupTypesAsync` (#11012)
### Release notes

- Memory allocation & CPU optimizations in `GrpcMessageExtensionUtilities.ConvertFromHttpMessageToExpando` (#11054)
- Memory allocation optimizations in `ScriptStartupTypeLocator.GetExtensionsStartupTypesAsync` (#11012)
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using Microsoft.AspNetCore.Http;
using Microsoft.Azure.WebJobs.Script.Grpc.Messages;
using Microsoft.Azure.WebJobs.Script.Workers.Rpc;
Expand All @@ -13,30 +12,58 @@ namespace Microsoft.Azure.WebJobs.Script.Grpc
{
internal static class GrpcMessageExtensionUtilities
{
public static object ConvertFromHttpMessageToExpando(RpcHttp inputMessage)
private static readonly object BoxedTrue = true;
private static readonly object BoxedFalse = false;
private static readonly IReadOnlyDictionary<string, object> EmptyHeaders = new Dictionary<string, object>();

public static ExpandoObject ConvertFromHttpMessageToExpando(RpcHttp inputMessage)
{
if (inputMessage == null)
if (inputMessage is null)
{
return null;
}

dynamic expando = new ExpandoObject();
expando.method = inputMessage.Method;
expando.query = inputMessage.Query as IDictionary<string, string>;
expando.statusCode = inputMessage.StatusCode;
expando.headers = inputMessage.Headers.ToDictionary(p => p.Key, p => (object)p.Value);
expando.enableContentNegotiation = inputMessage.EnableContentNegotiation;
var expando = new ExpandoObject();
IDictionary<string, object> dict = expando;

dict["method"] = inputMessage.Method;
dict["query"] = inputMessage.Query;
dict["statusCode"] = inputMessage.StatusCode;
dict["enableContentNegotiation"] = inputMessage.EnableContentNegotiation ? BoxedTrue : BoxedFalse;

expando.cookies = new List<Tuple<string, string, CookieOptions>>();
foreach (RpcHttpCookie cookie in inputMessage.Cookies)
if (inputMessage.Headers is { Count: > 0 })
{
var headerDict = new Dictionary<string, object>(inputMessage.Headers.Count);
foreach (var kvp in inputMessage.Headers)
{
headerDict[kvp.Key] = kvp.Value;
}
dict["headers"] = headerDict;
}
else
{
expando.cookies.Add(RpcHttpCookieConverter(cookie));
dict["headers"] = EmptyHeaders;
}

if (inputMessage.Body != null)
if (inputMessage.Cookies is { Count: > 0 })
{
expando.body = inputMessage.Body.ToObject();
var cookiesList = new List<Tuple<string, string, CookieOptions>>(inputMessage.Cookies.Count);
foreach (var cookie in inputMessage.Cookies)
{
cookiesList.Add(RpcHttpCookieConverter(cookie));
}
dict["cookies"] = cookiesList;
}
else
{
dict["cookies"] = Array.Empty<Tuple<string, string, CookieOptions>>();
}

if (inputMessage.Body is not null)
{
dict["body"] = inputMessage.Body.ToObject();
}

return expando;
}

Expand Down Expand Up @@ -80,27 +107,17 @@ public static Tuple<string, string, CookieOptions> RpcHttpCookieConverter(RpcHtt

internal static void UpdateWorkerMetadata(this WorkerMetadata workerMetadata, RpcWorkerConfig workerConfig)
{
workerMetadata.RuntimeName = string.IsNullOrEmpty(workerMetadata.RuntimeName)
? workerConfig.Description.Language : workerMetadata.RuntimeName;
workerMetadata.RuntimeVersion = string.IsNullOrEmpty(workerMetadata.RuntimeVersion)
? workerConfig.Description.DefaultRuntimeVersion : workerMetadata.RuntimeVersion;
workerMetadata.RuntimeName ??= workerConfig.Description.Language;
workerMetadata.RuntimeVersion ??= workerConfig.Description.DefaultRuntimeVersion;
}

private static SameSiteMode RpcSameSiteEnumConverter(RpcHttpCookie.Types.SameSite sameSite)
private static SameSiteMode RpcSameSiteEnumConverter(RpcHttpCookie.Types.SameSite sameSite) => sameSite switch
{
switch (sameSite)
{
case RpcHttpCookie.Types.SameSite.Strict:
return SameSiteMode.Strict;
case RpcHttpCookie.Types.SameSite.Lax:
return SameSiteMode.Lax;
case RpcHttpCookie.Types.SameSite.None:
return SameSiteMode.Unspecified;
case RpcHttpCookie.Types.SameSite.ExplicitNone:
return SameSiteMode.None;
default:
return SameSiteMode.Unspecified;
}
}
RpcHttpCookie.Types.SameSite.Strict => SameSiteMode.Strict,
RpcHttpCookie.Types.SameSite.Lax => SameSiteMode.Lax,
RpcHttpCookie.Types.SameSite.None => SameSiteMode.Unspecified,
RpcHttpCookie.Types.SameSite.ExplicitNone => SameSiteMode.None,
_ => SameSiteMode.Unspecified
};
}
}
}