From fc539eb19334bdfde8bc798d94ccb56b686e5193 Mon Sep 17 00:00:00 2001 From: Vijay Pai <vpai@google.com> Date: Wed, 21 Jun 2017 16:17:35 -0700 Subject: [PATCH] Re-enable public constructor for ClientAsyncResponseReader to avoid busting client that bypassed code generator. This code is deprecated-on-arrival as it is a performance pessimization. This code path should not be used. --- .../grpc++/impl/codegen/async_unary_call.h | 90 ++++++++++++++----- include/grpc++/impl/codegen/call.h | 20 +++++ 2 files changed, 89 insertions(+), 21 deletions(-) diff --git a/include/grpc++/impl/codegen/async_unary_call.h b/include/grpc++/impl/codegen/async_unary_call.h index 4aa4e25a9e..de0ab2372a 100644 --- a/include/grpc++/impl/codegen/async_unary_call.h +++ b/include/grpc++/impl/codegen/async_unary_call.h @@ -87,6 +87,28 @@ class ClientAsyncResponseReader final ClientAsyncResponseReader(call, context, request); } + /// TODO(vjpai): Delete the below constructor + /// PLEASE DO NOT USE THIS CONSTRUCTOR IN NEW CODE + /// This code is only present as a short-term workaround + /// for users that bypassed the code-generator and directly + /// created this struct rather than properly using a stub. + /// This code will not remain a valid public constructor for long. + template <class W> + ClientAsyncResponseReader(ChannelInterface* channel, CompletionQueue* cq, + const RpcMethod& method, ClientContext* context, + const W& request) + : context_(context), + call_(channel->CreateCall(method, context, cq)), + collection_(std::make_shared<Ops>()) { + collection_->init_buf_.SetCollection(collection_); + collection_->init_buf_.SendInitialMetadata( + context->send_initial_metadata_, context->initial_metadata_flags()); + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(collection_->init_buf_.SendMessage(request).ok()); + collection_->init_buf_.ClientSendClose(); + call_.PerformOps(&collection_->init_buf_); + } + // always allocated against a call arena, no memory free required static void operator delete(void* ptr, std::size_t size) { assert(size == sizeof(ClientAsyncResponseReader)); @@ -101,9 +123,18 @@ class ClientAsyncResponseReader final void ReadInitialMetadata(void* tag) { GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - meta_buf_.set_output_tag(tag); - meta_buf_.RecvInitialMetadata(context_); - call_.PerformOps(&meta_buf_); + Ops& o = ops; + + // TODO(vjpai): Remove the collection_ specialization as soon + // as the public constructor is deleted + if (collection_) { + o = *collection_; + collection_->meta_buf_.SetCollection(collection_); + } + + o.meta_buf_.set_output_tag(tag); + o.meta_buf_.RecvInitialMetadata(context_); + call_.PerformOps(&o.meta_buf_); } /// See \a ClientAysncResponseReaderInterface::Finish for semantics. @@ -112,14 +143,23 @@ class ClientAsyncResponseReader final /// - the \a ClientContext associated with this call is updated with /// possible initial and trailing metadata sent from the server. void Finish(R* msg, Status* status, void* tag) { - finish_buf_.set_output_tag(tag); + Ops& o = ops; + + // TODO(vjpai): Remove the collection_ specialization as soon + // as the public constructor is deleted + if (collection_) { + o = *collection_; + collection_->finish_buf_.SetCollection(collection_); + } + + o.finish_buf_.set_output_tag(tag); if (!context_->initial_metadata_received_) { - finish_buf_.RecvInitialMetadata(context_); + o.finish_buf_.RecvInitialMetadata(context_); } - finish_buf_.RecvMessage(msg); - finish_buf_.AllowNoMessage(); - finish_buf_.ClientRecvStatus(context_, status); - call_.PerformOps(&finish_buf_); + o.finish_buf_.RecvMessage(msg); + o.finish_buf_.AllowNoMessage(); + o.finish_buf_.ClientRecvStatus(context_, status); + call_.PerformOps(&o.finish_buf_); } private: @@ -129,25 +169,33 @@ class ClientAsyncResponseReader final template <class W> ClientAsyncResponseReader(Call call, ClientContext* context, const W& request) : context_(context), call_(call) { - init_buf_.SendInitialMetadata(context->send_initial_metadata_, - context->initial_metadata_flags()); + ops.init_buf_.SendInitialMetadata(context->send_initial_metadata_, + context->initial_metadata_flags()); // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(init_buf_.SendMessage(request).ok()); - init_buf_.ClientSendClose(); - call_.PerformOps(&init_buf_); + GPR_CODEGEN_ASSERT(ops.init_buf_.SendMessage(request).ok()); + ops.init_buf_.ClientSendClose(); + call_.PerformOps(&ops.init_buf_); } // disable operator new static void* operator new(std::size_t size); static void* operator new(std::size_t size, void* p) { return p; } - SneakyCallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, - CallOpClientSendClose> - init_buf_; - CallOpSet<CallOpRecvInitialMetadata> meta_buf_; - CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>, - CallOpClientRecvStatus> - finish_buf_; + // TODO(vjpai): Remove the reference to CallOpSetCollectionInterface + // as soon as the related workaround (public constructor) is deleted + struct Ops : public CallOpSetCollectionInterface { + SneakyCallOpSet<CallOpSendInitialMetadata, CallOpSendMessage, + CallOpClientSendClose> + init_buf_; + CallOpSet<CallOpRecvInitialMetadata> meta_buf_; + CallOpSet<CallOpRecvInitialMetadata, CallOpRecvMessage<R>, + CallOpClientRecvStatus> + finish_buf_; + } ops; + + // TODO(vjpai): Remove the collection_ as soon as the related workaround + // (public constructor) is deleted + std::shared_ptr<Ops> collection_; }; /// Async server-side API for handling unary calls, where the single diff --git a/include/grpc++/impl/codegen/call.h b/include/grpc++/impl/codegen/call.h index 2ded2d9776..dba53bc427 100644 --- a/include/grpc++/impl/codegen/call.h +++ b/include/grpc++/impl/codegen/call.h @@ -544,6 +544,11 @@ class CallOpClientRecvStatus { grpc_slice error_message_; }; +/// TODO(vjpai): Remove the existence of CallOpSetCollectionInterface +/// and references to it. This code is deprecated-on-arrival and is +/// only added for users that bypassed the code-generator. +class CallOpSetCollectionInterface {}; + /// An abstract collection of call ops, used to generate the /// grpc_call_op structure to pass down to the lower layers, /// and as it is-a CompletionQueueTag, also massages the final @@ -554,6 +559,18 @@ class CallOpSetInterface : public CompletionQueueTag { /// Fills in grpc_op, starting from ops[*nops] and moving /// upwards. virtual void FillOps(grpc_call* call, grpc_op* ops, size_t* nops) = 0; + + /// TODO(vjpai): Remove the SetCollection method and comment. This is only + /// a short-term workaround for users that bypassed the code generator + /// Mark this as belonging to a collection if needed + void SetCollection(std::shared_ptr<CallOpSetCollectionInterface> collection) { + collection_ = collection; + } + + protected: + /// TODO(vjpai): Remove the collection_ field once the idea of bypassing the + /// code generator is forbidden. This is already deprecated + std::shared_ptr<CallOpSetCollectionInterface> collection_; }; /// Primary implementaiton of CallOpSetInterface. @@ -594,6 +611,9 @@ class CallOpSet : public CallOpSetInterface, this->Op6::FinishOp(status); *tag = return_tag_; g_core_codegen_interface->grpc_call_unref(call_); + // TODO(vjpai): Remove the reference to collection_ once the idea of + // bypassing the code generator is forbidden. It is already deprecated + collection_.reset(); return true; } -- GitLab