@@ -54,7 +54,7 @@ internal class NativeClientCall<Request, Response>(
5454 private var closed = atomic(false )
5555
5656 // tracks how many operations are in flight (not yet completed by the listener).
57- // if 0, there are no more operations (except for the RECV_STATUS_ON_CLIENT op) .
57+ // if 0 and we got a closeInfo (containing the status), there are no more ongoing operations .
5858 // in this case, we can safely call onClose on the listener.
5959 // we need this mechanism to ensure that onClose is not called while any other callback is still running
6060 // on the listener.
@@ -64,7 +64,7 @@ internal class NativeClientCall<Request, Response>(
6464 // if null, the call is still in progress. otherwise, the call can be closed as soon as inFlight is 0.
6565 private val closeInfo = atomic<Pair <Status , GrpcTrailers >? > (null )
6666
67- // we currently don't buffer messages, so after one `sendMessage` call, ready turns false.
67+ // we currently don't buffer messages, so after one `sendMessage` call, ready turns false. (KRPC-192)
6868 private val ready = atomic(true )
6969
7070 /* *
@@ -81,11 +81,11 @@ internal class NativeClientCall<Request, Response>(
8181 * AND the corresponding listener callback returned.
8282 *
8383 * If the counter reaches 0, no more listener callbacks are executed, and the call can be closed by
84- * calling [tryDeliverClose ].
84+ * calling [tryToCloseCall ].
8585 */
8686 private fun endOp () {
8787 if (inFlight.decrementAndGet() == 0 ) {
88- tryDeliverClose ()
88+ tryToCloseCall ()
8989 }
9090 }
9191
@@ -97,23 +97,23 @@ internal class NativeClientCall<Request, Response>(
9797 * - If the [inFlight] counter is not 0, this does nothing.
9898 * - Otherwise, the listener's onClose callback is invoked and the call is closed.
9999 */
100- private fun tryDeliverClose () {
101- val s = closeInfo.value ? : return
100+ private fun tryToCloseCall () {
101+ val info = closeInfo.value ? : return
102102 if (inFlight.value == 0 && closed.compareAndSet(expect = false , update = true )) {
103- val lst = checkNotNull(listener) { " Not yet started" }
103+ val lst = checkNotNull(listener) { internalError( " Not yet started" ) }
104104 // allows the managed channel to join for the call to finish.
105105 callJob.complete()
106- lst.onClose(s .first, s .second)
106+ lst.onClose(info .first, info .second)
107107 }
108108 }
109109
110110 /* *
111- * Sets the [closeInfo] and calls [tryDeliverClose ].
112- * This is called as soon as the RECV_STATUS_ON_CLIENT batch is finished.
111+ * Sets the [closeInfo] and calls [tryToCloseCall ].
112+ * This is called as soon as the RECV_STATUS_ON_CLIENT batch (started with [startRecvStatus]) finished.
113113 */
114114 private fun markClosePending (status : Status , trailers : GrpcTrailers ) {
115115 if (closeInfo.compareAndSet(null , Pair (status, trailers))) {
116- tryDeliverClose ()
116+ tryToCloseCall ()
117117 }
118118 }
119119
@@ -132,8 +132,8 @@ internal class NativeClientCall<Request, Response>(
132132 responseListener : Listener <Response >,
133133 headers : GrpcTrailers ,
134134 ) {
135- check(listener == null ) { " Already started" }
136- check(! cancelled) { " Already cancelled." }
135+ check(listener == null ) { internalError( " Already started" ) }
136+ check(! cancelled) { internalError( " Already cancelled." ) }
137137
138138 listener = responseListener
139139
@@ -164,7 +164,7 @@ internal class NativeClientCall<Request, Response>(
164164 beginOp()
165165
166166 when (val callResult = cq.runBatch(this @NativeClientCall, ops, nOps)) {
167- is BatchResult .Called -> {
167+ is BatchResult .Submitted -> {
168168 callResult.future.onComplete { success ->
169169 try {
170170 if (success) {
@@ -184,7 +184,7 @@ internal class NativeClientCall<Request, Response>(
184184 cancelInternal(grpc_status_code.GRPC_STATUS_UNAVAILABLE , " Channel shutdown" )
185185 }
186186
187- is BatchResult .CallError -> {
187+ is BatchResult .SubmitError -> {
188188 cleanup()
189189 endOp()
190190 cancelInternal(
@@ -196,7 +196,7 @@ internal class NativeClientCall<Request, Response>(
196196 }
197197
198198 /* *
199- * Starts a batch operation to receive the status from the completion queue.
199+ * Starts a batch operation to receive the status from the completion queue (RECV_STATUS_ON_CLIENT) .
200200 * This operation is bound to the lifetime of the call, so it will finish once all other operations are done.
201201 * If this operation fails, it will call [markClosePending] with the corresponding error, as the entire call
202202 * si considered failed.
@@ -206,7 +206,7 @@ internal class NativeClientCall<Request, Response>(
206206 */
207207 @OptIn(ExperimentalStdlibApi ::class )
208208 private fun startRecvStatus (): Boolean {
209- checkNotNull(listener) { " Not yet started" }
209+ checkNotNull(listener) { internalError( " Not yet started" ) }
210210 val arena = Arena ()
211211 val statusCode = arena.alloc< grpc_status_code.Var > ()
212212 val statusDetails = arena.alloc< grpc_slice> ()
@@ -221,7 +221,7 @@ internal class NativeClientCall<Request, Response>(
221221 }
222222
223223 when (val callResult = cq.runBatch(this @NativeClientCall, op.ptr, 1u )) {
224- is BatchResult .Called -> {
224+ is BatchResult .Submitted -> {
225225 callResult.future.onComplete {
226226 val details = statusDetails.toByteArray().toKString()
227227 val status = Status (statusCode.value.toKotlin(), details, null )
@@ -244,7 +244,7 @@ internal class NativeClientCall<Request, Response>(
244244 return false
245245 }
246246
247- is BatchResult .CallError -> {
247+ is BatchResult .SubmitError -> {
248248 arena.clear()
249249 markClosePending(
250250 Status (StatusCode .INTERNAL , " Failed to start call: ${callResult.error} " ),
@@ -285,9 +285,11 @@ internal class NativeClientCall<Request, Response>(
285285 * This must only be called again after [numMessages] were received in the [Listener.onMessage] callback.
286286 */
287287 override fun request (numMessages : Int ) {
288- check(numMessages > 0 ) { " numMessages must be > 0" }
289- val listener = checkNotNull(listener) { " Not yet started" }
290- check(! cancelled) { " Already cancelled" }
288+ check(numMessages > 0 ) { internalError(" numMessages must be > 0" ) }
289+ // limit numMessages to prevent potential stack overflows
290+ check(numMessages <= 16 ) { internalError(" numMessages must be <= 16" ) }
291+ val listener = checkNotNull(listener) { internalError(" Not yet started" ) }
292+ check(! cancelled) { internalError(" Already cancelled" ) }
291293
292294 var remainingMessages = numMessages
293295
@@ -333,8 +335,8 @@ internal class NativeClientCall<Request, Response>(
333335 }
334336
335337 override fun halfClose () {
336- check(! halfClosed) { " Already half closed." }
337- check(! cancelled) { " Already cancelled." }
338+ check(! halfClosed) { internalError( " Already half closed." ) }
339+ check(! cancelled) { internalError( " Already cancelled." ) }
338340 halfClosed = true
339341
340342 val arena = Arena ()
@@ -350,10 +352,10 @@ internal class NativeClientCall<Request, Response>(
350352 override fun isReady (): Boolean = ready.value
351353
352354 override fun sendMessage (message : Request ) {
353- checkNotNull(listener) { " Not yet started" }
354- check(! halfClosed) { " Already half closed." }
355- check(! cancelled) { " Already cancelled." }
356- check(isReady()) { " Not yet ready." }
355+ checkNotNull(listener) { internalError( " Not yet started" ) }
356+ check(! halfClosed) { internalError( " Already half closed." ) }
357+ check(! cancelled) { internalError( " Already cancelled." ) }
358+ check(isReady()) { internalError( " Not yet ready." ) }
357359
358360 // set ready false, as only one message can be sent at a time.
359361 ready.value = false
@@ -368,14 +370,12 @@ internal class NativeClientCall<Request, Response>(
368370 }
369371
370372 runBatch(op.ptr, 1u , cleanup = {
371- // no mater what happens, we need to set ready to true again.
372- turnReady()
373-
374373 // actual cleanup
375374 grpc_byte_buffer_destroy(byteBuffer)
376375 arena.clear()
377376 }) {
378- // Nothing to do here
377+ // set ready true, as we can now send another message.
378+ turnReady()
379379 }
380380 }
381381}
0 commit comments