Skip to content

Commit 582021e

Browse files
authored
fix: Fix PayloadProcessor response payload race condition (#120)
Prevent incorrectly empty logged payloads: - Do not attempt to avoid slicing the response bytebuf in the case that a PayloadProcessor is configured - Do not attempt to avoid some additional refcount updates in the case status != OK Resolves #111 ----- Signed-off-by: Nick Hill <[email protected]>
1 parent a997686 commit 582021e

File tree

1 file changed

+16
-19
lines changed

1 file changed

+16
-19
lines changed

src/main/java/com/ibm/watson/modelmesh/ModelMeshApi.java

+16-19
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,7 @@ public void onHalfClose() {
725725
String vModelId = null;
726726
String requestId = null;
727727
ModelResponse response = null;
728+
ByteBuf responsePayload = null;
728729
try (InterruptingListener cancelListener = newInterruptingListener()) {
729730
if (logHeaders != null) {
730731
logHeaders.addToMDC(headers); // MDC cleared in finally block
@@ -767,18 +768,20 @@ public void onHalfClose() {
767768
} finally {
768769
if (payloadProcessor != null) {
769770
processPayload(reqMessage.readerIndex(reqReaderIndex),
770-
requestId, resolvedModelId, methodName, headers, null, true);
771+
requestId, resolvedModelId, methodName, headers, null);
771772
} else {
772773
releaseReqMessage();
773774
}
774775
reqMessage = null; // ownership released or transferred
775776
}
776777

777-
respReaderIndex = response.data.readerIndex();
778778
respSize = response.data.readableBytes();
779779
call.sendHeaders(response.metadata);
780+
if (payloadProcessor != null) {
781+
responsePayload = response.data.retainedSlice();
782+
}
780783
call.sendMessage(response.data);
781-
// response is released via ReleaseAfterResponse.releaseAll()
784+
// final response refcount is released via ReleaseAfterResponse.releaseAll()
782785
status = OK;
783786
} catch (Exception e) {
784787
status = toStatus(e);
@@ -795,17 +798,13 @@ public void onHalfClose() {
795798
evictMethodDescriptor(methodName);
796799
}
797800
} finally {
798-
final boolean releaseResponse = status != OK;
799801
if (payloadProcessor != null) {
800-
ByteBuf data = null;
801-
Metadata metadata = null;
802-
if (response != null) {
803-
data = response.data.readerIndex(respReaderIndex);
804-
metadata = response.metadata;
805-
}
806-
processPayload(data, requestId, resolvedModelId, methodName, metadata, status, releaseResponse);
807-
} else if (releaseResponse && response != null) {
808-
response.release();
802+
Metadata metadata = response != null ? response.metadata : null;
803+
processPayload(responsePayload, requestId, resolvedModelId, methodName, metadata, status);
804+
}
805+
if (status != OK && response != null) {
806+
// An additional release is required if we call.sendMessage() wasn't sucessful
807+
response.data.release();
809808
}
810809
ReleaseAfterResponse.releaseAll();
811810
clearThreadLocals();
@@ -820,23 +819,21 @@ public void onHalfClose() {
820819
}
821820

822821
/**
823-
* Invoke PayloadProcessor on the request/response data
822+
* Invoke PayloadProcessor on the request/response data. This method takes ownership
823+
* of the passed-in {@code ByteBuf}.
824+
*
824825
* @param data the binary data
825826
* @param payloadId the id of the request
826827
* @param modelId the id of the model
827828
* @param methodName the name of the invoked method
828829
* @param metadata the method name metadata
829830
* @param status null for requests, non-null for responses
830-
* @param takeOwnership whether the processor should take ownership
831831
*/
832832
private void processPayload(ByteBuf data, String payloadId, String modelId, String methodName,
833-
Metadata metadata, io.grpc.Status status, boolean takeOwnership) {
833+
Metadata metadata, io.grpc.Status status) {
834834
Payload payload = null;
835835
try {
836836
assert payloadProcessor != null;
837-
if (!takeOwnership) {
838-
ReferenceCountUtil.retain(data);
839-
}
840837
payload = new Payload(payloadId, modelId, methodName, metadata, data, status);
841838
if (payloadProcessor.process(payload)) {
842839
data = null; // ownership transferred

0 commit comments

Comments
 (0)