Go to the documentation of this file.
19 #ifndef GRPCPP_SUPPORT_CLIENT_CALLBACK_H
20 #define GRPCPP_SUPPORT_CLIENT_CALLBACK_H
48 template <
class InputMessage,
class OutputMessage,
49 class BaseInputMessage = InputMessage,
50 class BaseOutputMessage = OutputMessage>
54 const InputMessage* request, OutputMessage* result,
56 static_assert(std::is_base_of<BaseInputMessage, InputMessage>::value,
57 "Invalid input message specification");
58 static_assert(std::is_base_of<BaseOutputMessage, OutputMessage>::value,
59 "Invalid output message specification");
61 channel, method, context, request, result, on_completion);
64 template <
class InputMessage,
class OutputMessage>
65 class CallbackUnaryCallImpl {
70 const InputMessage* request, OutputMessage* result,
88 const size_t alloc_sz =
sizeof(OpSetAndTag);
91 auto* ops =
new (&alloced->opset) FullCallOpSet;
92 auto* tag =
new (&alloced->tag)
101 ops->SendInitialMetadata(&context->send_initial_metadata_,
102 context->initial_metadata_flags());
103 ops->RecvInitialMetadata(context);
104 ops->RecvMessage(result);
105 ops->AllowNoMessage();
106 ops->ClientSendClose();
107 ops->ClientRecvStatus(context, tag->status_ptr());
108 ops->set_core_cq_tag(tag);
140 template <
class Request,
class Response>
142 template <
class Response>
144 template <
class Request>
151 template <
class Request,
class Response>
158 virtual void Read(Response* resp) = 0;
159 virtual void AddHold(
int holds) = 0;
164 reactor->BindStream(
this);
168 template <
class Response>
173 virtual void Read(Response* resp) = 0;
174 virtual void AddHold(
int holds) = 0;
179 reactor->BindReader(
this);
183 template <
class Request>
195 virtual void AddHold(
int holds) = 0;
200 reactor->BindWriter(
this);
229 template <
class Request,
class Response>
230 class ClientBidiReactor :
public internal::ClientReactor {
260 stream_->Write(req, options);
308 stream_->AddHold(holds);
363 template <
class Response>
364 class ClientReadReactor :
public internal::ClientReactor {
372 reader_->AddHold(holds);
388 template <
class Request>
389 class ClientWriteReactor :
public internal::ClientReactor {
394 writer_->Write(req, options);
404 writer_->AddHold(holds);
445 reactor->BindCall(
this);
451 template <
class Request,
class Response>
452 class ClientCallbackReaderWriterFactory;
453 template <
class Response>
454 class ClientCallbackReaderFactory;
455 template <
class Request>
456 class ClientCallbackWriterFactory;
458 template <
class Request,
class Response>
459 class ClientCallbackReaderWriterImpl
463 static void operator delete(
void* , std::size_t size) {
472 static void operator delete(
void*,
void*) {
GPR_ASSERT(
false); }
474 void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_)
override {
480 if (!start_corked_) {
481 start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
482 context_->initial_metadata_flags());
490 if (backlog_.read_ops) {
493 if (backlog_.write_ops) {
496 if (backlog_.writes_done_ops) {
502 started_.store(
true, std::memory_order_release);
507 this->MaybeFinish(
false);
510 void Read(Response* msg)
override {
511 read_ops_.RecvMessage(msg);
512 callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
513 if (
GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
515 if (
GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
516 backlog_.read_ops =
true;
524 ABSL_LOCKS_EXCLUDED(start_mu_)
override {
525 if (options.is_last_message()) {
526 options.set_buffer_hint();
527 write_ops_.ClientSendClose();
530 GPR_ASSERT(write_ops_.SendMessagePtr(msg, options).ok());
531 callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
533 write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
534 context_->initial_metadata_flags());
535 corked_write_needed_ =
false;
538 if (
GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
540 if (
GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
541 backlog_.write_ops =
true;
548 writes_done_ops_.ClientSendClose();
549 writes_done_tag_.
Set(
552 reactor_->OnWritesDoneDone(ok);
555 &writes_done_ops_,
false);
557 callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
559 writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
560 context_->initial_metadata_flags());
561 corked_write_needed_ =
false;
563 if (
GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
565 if (
GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
566 backlog_.writes_done_ops =
true;
574 callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);
587 start_corked_(context_->initial_metadata_corked_),
588 corked_write_needed_(start_corked_) {
589 this->BindReactor(reactor);
595 reactor_->OnReadInitialMetadataDone(
596 ok && !reactor_->InternalTrailersOnly(call_.call()));
600 start_ops_.RecvInitialMetadata(context_);
606 reactor_->OnWriteDone(ok);
615 reactor_->OnReadDone(ok);
624 [
this](
bool ) { MaybeFinish(true); },
627 finish_ops_.ClientRecvStatus(context_, &finish_status_);
637 void MaybeFinish(
bool from_reaction) {
639 1, std::memory_order_acq_rel) == 1)) {
641 auto* reactor = reactor_;
642 auto* call = call_.
call();
643 this->~ClientCallbackReaderWriterImpl();
649 call, [reactor, s = std::move(s)]() { reactor->OnDone(s); });
657 ClientBidiReactor<Request, Response>*
const reactor_;
663 const bool start_corked_;
664 bool corked_write_needed_;
686 struct StartCallBacklog {
687 bool write_ops =
false;
688 bool writes_done_ops =
false;
689 bool read_ops =
false;
691 StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
694 std::atomic<intptr_t> callbacks_outstanding_{3};
695 std::atomic_bool started_{
false};
699 template <
class Request,
class Response>
700 class ClientCallbackReaderWriterFactory {
707 channel->CreateCall(method, context, channel->CallbackCQ());
717 template <
class Response>
721 static void operator delete(
void* , std::size_t size) {
730 static void operator delete(
void*,
void*) {
GPR_ASSERT(
false); }
741 reactor_->OnReadInitialMetadataDone(
742 ok && !reactor_->InternalTrailersOnly(call_.call()));
746 start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
747 context_->initial_metadata_flags());
748 start_ops_.RecvInitialMetadata(context_);
756 reactor_->OnReadDone(ok);
764 if (backlog_.read_ops) {
767 started_.store(
true, std::memory_order_release);
772 [
this](
bool ) { MaybeFinish(true); },
773 &finish_ops_,
false);
774 finish_ops_.ClientRecvStatus(context_, &finish_status_);
779 void Read(Response* msg)
override {
780 read_ops_.RecvMessage(msg);
781 callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
782 if (
GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
784 if (
GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
785 backlog_.read_ops =
true;
793 callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);
800 template <
class Request>
804 : context_(context), call_(call), reactor_(reactor) {
805 this->BindReactor(reactor);
807 GPR_ASSERT(start_ops_.SendMessagePtr(request).ok());
808 start_ops_.ClientSendClose();
812 void MaybeFinish(
bool from_reaction) {
814 1, std::memory_order_acq_rel) == 1)) {
816 auto* reactor = reactor_;
817 auto* call = call_.
call();
818 this->~ClientCallbackReaderImpl();
824 call, [reactor, s = std::move(s)]() { reactor->OnDone(s); });
832 ClientReadReactor<Response>*
const reactor_;
849 struct StartCallBacklog {
850 bool read_ops =
false;
852 StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
855 std::atomic<intptr_t> callbacks_outstanding_{2};
856 std::atomic_bool started_{
false};
860 template <
class Response>
861 class ClientCallbackReaderFactory {
863 template <
class Request>
869 channel->CreateCall(method, context, channel->CallbackCQ());
878 template <
class Request>
882 static void operator delete(
void* , std::size_t size) {
891 static void operator delete(
void*,
void*) {
GPR_ASSERT(
false); }
893 void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_)
override {
899 if (!start_corked_) {
900 start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
901 context_->initial_metadata_flags());
908 if (backlog_.write_ops) {
911 if (backlog_.writes_done_ops) {
917 started_.store(
true, std::memory_order_release);
922 this->MaybeFinish(
false);
926 ABSL_LOCKS_EXCLUDED(start_mu_)
override {
928 options.set_buffer_hint();
929 write_ops_.ClientSendClose();
932 GPR_ASSERT(write_ops_.SendMessagePtr(msg, options).ok());
933 callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
936 write_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
937 context_->initial_metadata_flags());
938 corked_write_needed_ =
false;
941 if (
GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
943 if (
GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
944 backlog_.write_ops =
true;
952 writes_done_ops_.ClientSendClose();
953 writes_done_tag_.
Set(
956 reactor_->OnWritesDoneDone(ok);
959 &writes_done_ops_,
false);
961 callbacks_outstanding_.fetch_add(1, std::memory_order_relaxed);
964 writes_done_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
965 context_->initial_metadata_flags());
966 corked_write_needed_ =
false;
969 if (
GPR_UNLIKELY(!started_.load(std::memory_order_acquire))) {
971 if (
GPR_LIKELY(!started_.load(std::memory_order_relaxed))) {
972 backlog_.writes_done_ops =
true;
980 callbacks_outstanding_.fetch_add(holds, std::memory_order_relaxed);
987 template <
class Response>
994 start_corked_(context_->initial_metadata_corked_),
995 corked_write_needed_(start_corked_) {
996 this->BindReactor(reactor);
1002 reactor_->OnReadInitialMetadataDone(
1003 ok && !reactor_->InternalTrailersOnly(call_.call()));
1006 &start_ops_,
false);
1007 start_ops_.RecvInitialMetadata(context_);
1013 reactor_->OnWriteDone(ok);
1016 &write_ops_,
false);
1020 finish_ops_.RecvMessage(response);
1021 finish_ops_.AllowNoMessage();
1024 [
this](
bool ) { MaybeFinish(true); },
1027 finish_ops_.ClientRecvStatus(context_, &finish_status_);
1032 void MaybeFinish(
bool from_reaction) {
1034 1, std::memory_order_acq_rel) == 1)) {
1036 auto* reactor = reactor_;
1037 auto* call = call_.
call();
1038 this->~ClientCallbackWriterImpl();
1044 call, [reactor, s = std::move(s)]() { reactor->OnDone(s); });
1052 ClientWriteReactor<Request>*
const reactor_;
1058 const bool start_corked_;
1059 bool corked_write_needed_;
1079 struct StartCallBacklog {
1080 bool write_ops =
false;
1081 bool writes_done_ops =
false;
1083 StartCallBacklog backlog_ ABSL_GUARDED_BY(start_mu_);
1086 std::atomic<intptr_t> callbacks_outstanding_{3};
1087 std::atomic_bool started_{
false};
1091 template <
class Request>
1092 class ClientCallbackWriterFactory {
1094 template <
class Response>
1100 channel->CreateCall(method, context, channel->CallbackCQ());
1112 static void operator delete(
void* , std::size_t size) {
1131 reactor_->OnReadInitialMetadataDone(
1132 ok && !reactor_->InternalTrailersOnly(call_.call()));
1135 &start_ops_,
false);
1136 start_ops_.SendInitialMetadata(&context_->send_initial_metadata_,
1137 context_->initial_metadata_flags());
1138 start_ops_.RecvInitialMetadata(context_);
1143 call_.
call(), [
this](
bool ) { MaybeFinish(); }, &finish_ops_,
1145 finish_ops_.ClientRecvStatus(context_, &finish_status_);
1153 template <
class Request,
class Response>
1157 : context_(context), call_(call), reactor_(reactor) {
1160 GPR_ASSERT(start_ops_.SendMessagePtr(request).ok());
1161 start_ops_.ClientSendClose();
1162 finish_ops_.RecvMessage(response);
1163 finish_ops_.AllowNoMessage();
1169 void MaybeFinish() {
1171 1, std::memory_order_acq_rel) == 1)) {
1173 auto* reactor = reactor_;
1174 auto* call = call_.
call();
1183 ClientUnaryReactor*
const reactor_;
1199 std::atomic<intptr_t> callbacks_outstanding_{2};
1204 template <
class Request,
class Response,
class BaseRequest = Request,
1205 class BaseResponse = Response>
1211 channel->CreateCall(method, context, channel->CallbackCQ());
1217 static_cast<const BaseRequest*
>(request),
1218 static_cast<BaseResponse*
>(response), reactor);
1225 #endif // GRPCPP_SUPPORT_CLIENT_CALLBACK_H
Definition: client_callback.h:1109
CallbackWithSuccessTag can be reused multiple times, and will be used in this fashion for streaming o...
Definition: callback_common.h:136
virtual void OnReadInitialMetadataDone(bool)
Definition: client_callback.h:377
virtual void OnReadInitialMetadataDone(bool)
Definition: client_callback.h:409
void StartWritesDone()
Definition: client_callback.h:399
virtual ~ClientCallbackWriter()
Definition: client_callback.h:186
void Read(Response *msg) override
Definition: client_callback.h:510
void AddHold(int holds) override
Definition: client_callback.h:979
void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_) override
Definition: client_callback.h:474
Definition: call_op_set.h:619
void StartWrite(const Request *req)
Initiate a write operation (or post it for later initiation if StartCall has not yet been invoked).
Definition: client_callback.h:251
GRPCAPI void * grpc_call_arena_alloc(grpc_call *call, size_t size)
Allocate memory in the grpc_call arena: this memory is automatically discarded at call completion.
Definition: call_op_set.h:526
void AddHold()
Holds are needed if (and only if) this stream has operations that take place on it after StartCall bu...
Definition: client_callback.h:305
Definition: client_context.h:68
virtual void OnReadDone(bool)
Definition: client_callback.h:378
An Alarm posts the user-provided tag to its associated completion queue or invokes the user-provided ...
Definition: alarm.h:33
Primary implementation of CallOpSetInterface.
Definition: completion_queue.h:96
#define GPR_DEBUG_ASSERT(x)
Definition: log.h:103
void Write(const Request *msg, grpc::WriteOptions options) ABSL_LOCKS_EXCLUDED(start_mu_) override
Definition: client_callback.h:523
void RemoveHold() override
Definition: client_callback.h:795
Definition: call_op_set.h:286
CallbackUnaryCallImpl(grpc::ChannelInterface *channel, const grpc::internal::RpcMethod &method, grpc::ClientContext *context, const InputMessage *request, OutputMessage *result, std::function< void(grpc::Status)> on_completion)
Definition: client_callback.h:67
WriteOptions & set_last_message()
last-message bit: indicates this is the last message in a stream client-side: makes Write the equival...
Definition: call_op_set.h:155
ClientUnaryReactor is a reactor-style interface for a unary RPC.
Definition: client_callback.h:431
virtual void Read(Response *resp)=0
static void Create(grpc::ChannelInterface *channel, const grpc::internal::RpcMethod &method, grpc::ClientContext *context, ClientBidiReactor< Request, Response > *reactor)
Definition: client_callback.h:702
void StartWrite(const Request *req, grpc::WriteOptions options)
Definition: client_callback.h:393
void StartCall()
Definition: client_callback.h:391
void OnDone(const grpc::Status &) override
Definition: client_callback.h:408
virtual void OnDone(const grpc::Status &)=0
Called by the library when all operations associated with this RPC have completed and all Holds have ...
void RemoveHold() override
Definition: client_callback.h:576
void OnDone(const grpc::Status &) override
Definition: client_callback.h:376
Straightforward wrapping of the C call object.
Definition: call.h:36
void CallbackUnaryCall(grpc::ChannelInterface *channel, const grpc::internal::RpcMethod &method, grpc::ClientContext *context, const InputMessage *request, OutputMessage *result, std::function< void(grpc::Status)> on_completion)
Perform a callback-based unary call.
Definition: client_callback.h:51
#define GPR_ASSERT(x)
abort() the process if x is zero, having written a line to the log.
Definition: log.h:95
virtual void WritesDone()=0
void RemoveHold() override
Definition: client_callback.h:982
static void Create(grpc::ChannelInterface *channel, const grpc::internal::RpcMethod &method, grpc::ClientContext *context, Response *response, ClientWriteReactor< Request > *reactor)
Definition: client_callback.h:1095
virtual void OnReadInitialMetadataDone(bool)
Notifies the application that a read of initial metadata from the server is done.
Definition: client_callback.h:329
Definition: callback_common.h:70
void BindReactor(ClientBidiReactor< Request, Response > *reactor)
Definition: client_callback.h:163
bool ok() const
Is the status OK?
Definition: status.h:126
void BindReactor(ClientUnaryReactor *reactor)
Definition: client_callback.h:444
GRPCAPI void grpc_call_ref(grpc_call *call)
Ref a call.
void StartRead(Response *resp)
Initiate a read operation (or post it for later initiation if StartCall has not yet been invoked).
Definition: client_callback.h:243
void AddMultipleHolds(int holds)
Definition: client_callback.h:370
void StartCall() ABSL_LOCKS_EXCLUDED(start_mu_) override
Definition: client_callback.h:893
void Write(const Request *msg, grpc::WriteOptions options) ABSL_LOCKS_EXCLUDED(start_mu_) override
Definition: client_callback.h:925
void StartWrite(const Request *req, grpc::WriteOptions options)
Initiate/post a write operation with specified options.
Definition: client_callback.h:259
void OnDone(const grpc::Status &) override
Notifies the application that all operations associated with this RPC have completed and all Holds ha...
Definition: client_callback.h:319
virtual ~ClientReactor()=default
virtual void StartCall()=0
virtual void AddHold(int holds)=0
virtual void OnReadDone(bool)
Notifies the application that a StartRead operation completed.
Definition: client_callback.h:335
Did it work? If it didn't, why?
Definition: status.h:35
virtual void WritesDone()=0
GRPCAPI void grpc_call_unref(grpc_call *call)
Unref a call.
Definition: channel_interface.h:49
void StartCall()
Definition: client_callback.h:366
virtual void OnWriteDone(bool)
Notifies the application that a StartWrite or StartWriteLast operation completed.
Definition: client_callback.h:342
A ClientContext allows the person implementing a service client to:
Definition: client_context.h:193
void StartCall() override
Definition: client_callback.h:732
Definition: channel_interface.h:45
struct grpc_call grpc_call
A Call represents an RPC.
Definition: grpc_types.h:70
Definition: client_context.h:66
virtual void OnReadInitialMetadataDone(bool)
Definition: client_callback.h:435
void BindReactor(ClientWriteReactor< Request > *reactor)
Definition: client_callback.h:199
virtual void RemoveHold()=0
Definition: client_callback.h:152
void StartWritesDone()
Indicate that the RPC will have no more write operations.
Definition: client_callback.h:281
virtual void Read(Response *resp)=0
void StartRead(Response *resp)
Definition: client_callback.h:367
Codegen interface for grpc::Channel.
Definition: channel_interface.h:71
Definition: client_callback.h:114
Definition: client_callback.h:1202
void Read(Response *msg) override
Definition: client_callback.h:779
void StartWriteLast(const Request *req, grpc::WriteOptions options)
Definition: client_callback.h:396
Definition: client_context.h:72
virtual void Write(const Request *req, grpc::WriteOptions options)=0
ClientWriteReactor is the interface for a client-streaming RPC.
Definition: client_callback.h:145
void grpc_call_run_in_event_engine(const grpc_call *call, absl::AnyInvocable< void()> cb)
Definition: client_callback.h:204
void AddMultipleHolds(int holds)
Definition: client_callback.h:306
void RemoveHold()
Definition: client_callback.h:374
static void Create(grpc::ChannelInterface *channel, const grpc::internal::RpcMethod &method, grpc::ClientContext *context, const Request *request, Response *response, ClientUnaryReactor *reactor)
Definition: client_callback.h:1206
void StartWriteLast(const Request *req, grpc::WriteOptions options)
Initiate/post a write operation with specified options and an indication that this is the last write ...
Definition: client_callback.h:272
Per-message write options.
Definition: call_op_set.h:78
virtual void RemoveHold()=0
virtual void OnWritesDoneDone(bool)
Notifies the application that a StartWritesDone operation completed.
Definition: client_callback.h:351
void WritesDone() ABSL_LOCKS_EXCLUDED(start_mu_) override
Definition: client_callback.h:951
virtual ~ClientCallbackReader()
Definition: client_callback.h:171
void Set(grpc_call *call, std::function< void(bool)> f, CompletionQueueTag *ops, bool can_inline)
Definition: callback_common.h:163
void AddHold(int holds) override
Definition: client_callback.h:792
void BindReactor(ClientReadReactor< Response > *reactor)
Definition: client_callback.h:178
Definition: client_callback.h:184
virtual void AddHold(int holds)=0
void RemoveHold()
Definition: client_callback.h:310
virtual ~ClientCallbackReaderWriter()
Definition: client_callback.h:154
virtual void RemoveHold()=0
void Write(const Request *req)
Definition: client_callback.h:188
virtual void StartCall()=0
void AddHold()
Definition: client_callback.h:401
void PerformOps(CallOpSetInterface *ops)
Definition: call.h:66
grpc_call * call() const
Definition: call.h:70
void StartCall()
Definition: client_callback.h:433
virtual void StartCall()=0
Definition: call_op_set.h:769
A thin wrapper around grpc_completion_queue (see src/core/lib/surface/completion_queue....
Definition: completion_queue.h:103
ClientBidiReactor is the interface for a bidirectional streaming RPC.
Definition: client_callback.h:141
Definition: channel_interface.h:47
void WriteLast(const Request *req, grpc::WriteOptions options)
Definition: client_callback.h:190
Definition: client_context.h:70
virtual bool InternalTrailersOnly(const grpc_call *call) const
InternalTrailersOnly is not part of the API and is not meant to be overridden.
virtual void StartCall()=0
void StartCall() override
Definition: client_callback.h:1123
void StartWrite(const Request *req)
Definition: client_callback.h:392
void StartCall()
Activate the RPC and initiate any reads or writes that have been Start'ed before this call.
Definition: client_callback.h:236
virtual void OnWriteDone(bool)
Definition: client_callback.h:410
Definition: call_op_set.h:424
Descriptor of an RPC method.
Definition: rpc_method.h:29
virtual void AddHold(int holds)=0
void AddMultipleHolds(int holds)
Definition: client_callback.h:402
Definition: client_callback.h:169
virtual ~ClientCallbackUnary()
Definition: client_callback.h:206
void set_core_cq_tag(void *core_cq_tag)
set_core_cq_tag is used to provide a different core CQ tag than "this".
Definition: call_op_set.h:943
void AddHold(int holds) override
Definition: client_callback.h:573
void RemoveHold()
Definition: client_callback.h:406
ClientReadReactor is the interface for a server-streaming RPC.
Definition: client_callback.h:143
void WritesDone() ABSL_LOCKS_EXCLUDED(start_mu_) override
Definition: client_callback.h:547
void AddHold()
Definition: client_callback.h:369
void OnDone(const grpc::Status &) override
Called by the library when all operations associated with this RPC have completed and all Holds have ...
Definition: client_callback.h:434
static void Create(grpc::ChannelInterface *channel, const grpc::internal::RpcMethod &method, grpc::ClientContext *context, const Request *request, ClientReadReactor< Response > *reactor)
Definition: client_callback.h:864
virtual void OnWritesDoneDone(bool)
Definition: client_callback.h:411