Skip to content
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

Client serialization optimizations #1033

Merged
merged 2 commits into from
Sep 2, 2020
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
1 change: 1 addition & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)keys\Grpc.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<CheckEolTargetFramework>false</CheckEolTargetFramework>

<!-- Don't make missing XML docs a fatal build error, but still surface so we have visibility into undocumented APIs. -->
<WarningsNotAsErrors>$(WarningsNotAsErrors);CS1591</WarningsNotAsErrors>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ public override void Complete()

var data = _bufferWriter.WrittenSpan;

GrpcServerLog.SerializedMessage(_serverCallContext.Logger, typeof(object), data.Length);
GrpcServerLog.SerializedMessage(_serverCallContext.Logger, _serverCallContext.ResponseType, data.Length);
WriteMessage(data);
}
else
Expand Down
139 changes: 0 additions & 139 deletions src/Grpc.Net.Client/Internal/DefaultSerializationContext.cs

This file was deleted.

60 changes: 60 additions & 0 deletions src/Grpc.Net.Client/Internal/GrpcCall.NonGeneric.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#region Copyright notice and license

// Copyright 2019 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#endregion

using System;
using Grpc.Core;
using Grpc.Shared;
using Microsoft.Extensions.Logging;

namespace Grpc.Net.Client.Internal
{
internal abstract class GrpcCall
{
// Getting logger name from generic type is slow
private const string LoggerName = "Grpc.Net.Client.Internal.GrpcCall";

private GrpcCallSerializationContext? _serializationContext;
private DefaultDeserializationContext? _deserializationContext;

public GrpcCallSerializationContext SerializationContext
{
get { return _serializationContext ??= new GrpcCallSerializationContext(this); }
}

public DefaultDeserializationContext DeserializationContext
{
get { return _deserializationContext ??= new DefaultDeserializationContext(); }
}

public CallOptions Options { get; }
public ILogger Logger { get; }
public GrpcChannel Channel { get; }

public string? RequestGrpcEncoding { get; internal set; }

public abstract Type RequestType { get; }
public abstract Type ResponseType { get; }

protected GrpcCall(CallOptions options, GrpcChannel channel)
{
Options = options;
Channel = channel;
Logger = channel.LoggerFactory.CreateLogger(LoggerName);
}
}
}
34 changes: 12 additions & 22 deletions src/Grpc.Net.Client/Internal/GrpcCall.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,10 @@

namespace Grpc.Net.Client.Internal
{
internal partial class GrpcCall<TRequest, TResponse> : IDisposable
internal sealed partial class GrpcCall<TRequest, TResponse> : GrpcCall, IDisposable
where TRequest : class
where TResponse : class
{
// Getting logger name from generic type is slow
private const string LoggerName = "Grpc.Net.Client.Internal.GrpcCall";

private readonly CancellationTokenSource _callCts;
private readonly TaskCompletionSource<Status> _callTcs;
private readonly DateTime _deadline;
Expand All @@ -51,17 +48,15 @@ internal partial class GrpcCall<TRequest, TResponse> : IDisposable
public bool Disposed { get; private set; }
public bool ResponseFinished { get; private set; }
public HttpResponseMessage? HttpResponse { get; private set; }
public CallOptions Options { get; }
public Method<TRequest, TResponse> Method { get; }
public GrpcChannel Channel { get; }
public ILogger Logger { get; }

// These are set depending on the type of gRPC call
private TaskCompletionSource<TResponse>? _responseTcs;
public HttpContentClientStreamWriter<TRequest, TResponse>? ClientStreamWriter { get; private set; }
public HttpContentClientStreamReader<TRequest, TResponse>? ClientStreamReader { get; private set; }

public GrpcCall(Method<TRequest, TResponse> method, GrpcMethodInfo grpcMethodInfo, CallOptions options, GrpcChannel channel)
: base(options, channel)
{
// Validate deadline before creating any objects that require cleanup
ValidateDeadline(options.Deadline);
Expand All @@ -71,9 +66,6 @@ public GrpcCall(Method<TRequest, TResponse> method, GrpcMethodInfo grpcMethodInf
_callTcs = new TaskCompletionSource<Status>();
Method = method;
_grpcMethodInfo = grpcMethodInfo;
Options = options;
Channel = channel;
Logger = channel.LoggerFactory.CreateLogger(LoggerName);
_deadline = options.Deadline ?? DateTime.MaxValue;

Channel.RegisterActiveCall(this);
Expand All @@ -94,6 +86,9 @@ public CancellationToken CancellationToken
get { return _callCts.Token; }
}

public override Type RequestType => typeof(TRequest);
public override Type ResponseType => typeof(TResponse);

public void StartUnary(TRequest request)
{
_responseTcs = new TaskCompletionSource<TResponse>(TaskCreationOptions.RunContinuationsAsynchronously);
Expand Down Expand Up @@ -386,10 +381,10 @@ private bool TryGetTrailers([NotNullWhen(true)] out Metadata? trailers)

private void SetMessageContent(TRequest request, HttpRequestMessage message)
{
RequestGrpcEncoding = GrpcProtocolHelpers.GetRequestEncoding(message.Headers);
message.Content = new PushUnaryContent<TRequest, TResponse>(
request,
this,
GrpcProtocolHelpers.GetRequestEncoding(message.Headers),
GrpcProtocolConstants.GrpcContentTypeHeaderValue);
}

Expand Down Expand Up @@ -519,12 +514,9 @@ private async Task RunCall(HttpRequestMessage request, TimeSpan? timeout)
// Read entire response body immediately and read status from trailers
// Trailers are only available once the response body had been read
var responseStream = await HttpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
var message = await responseStream.ReadMessageAsync(
Logger,
Method.ResponseMarshaller.ContextualDeserializer,
var message = await ReadMessageAsync(
responseStream,
GrpcProtocolHelpers.GetGrpcEncoding(HttpResponse),
Channel.ReceiveMaxMessageSize,
Channel.CompressionProviders,
singleMessage: true,
_callCts.Token).ConfigureAwait(false);
status = GrpcProtocolHelpers.GetResponseStatus(HttpResponse);
Expand Down Expand Up @@ -776,7 +768,8 @@ private async Task ReadCredentials(HttpRequestMessage request)

private void CreateWriter(HttpRequestMessage message)
{
ClientStreamWriter = new HttpContentClientStreamWriter<TRequest, TResponse>(this, message);
RequestGrpcEncoding = GrpcProtocolHelpers.GetRequestEncoding(message.Headers);
ClientStreamWriter = new HttpContentClientStreamWriter<TRequest, TResponse>(this);

message.Content = new PushStreamContent<TRequest, TResponse>(ClientStreamWriter, GrpcProtocolConstants.GrpcContentTypeHeaderValue);
}
Expand Down Expand Up @@ -898,16 +891,12 @@ private void DeadlineExceeded()
internal ValueTask WriteMessageAsync(
Stream stream,
TRequest message,
string grpcEncoding,
CallOptions callOptions)
{
return stream.WriteMessageAsync(
Logger,
this,
message,
Method.RequestMarshaller.ContextualSerializer,
grpcEncoding,
Channel.SendMaxMessageSize,
Channel.CompressionProviders,
callOptions);
}

Expand All @@ -918,6 +907,7 @@ internal ValueTask WriteMessageAsync(
CancellationToken cancellationToken)
{
return responseStream.ReadMessageAsync(
DeserializationContext,
Logger,
Method.ResponseMarshaller.ContextualDeserializer,
grpcEncoding,
Expand Down
Loading