Prevent OOM during streaming deserialization of large responses When a server-side evaluationTimeout fires mid-stream, the client may have already queued significant response data. The reader thread could OOM trying to deserialize large objects (e.g., vertex properties with huge strings) from the already-queued bytes. Fixes: - Reduce MAX_QUEUE_CHUNKS from 512 to 64 (bounds heap usage from queued byte[] chunks) - cancel() now calls markError() instead of markComplete(), causing QueueInputStream.read() to throw immediately on next access - Add error check at top of QueueInputStream.read() so in-progress reads from current buffer fail fast when cancelled - Reader loop checks cancelled flag between readChunk() calls The combined effect: when the ResultSet is done (timeout, error, or client abandonment), the reader thread stops consuming data promptly rather than continuing to deserialize queued bytes until OOM.
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/QueueInputStream.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/QueueInputStream.java index dac3450..90c15e0 100644 --- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/QueueInputStream.java +++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/QueueInputStream.java
@@ -36,7 +36,7 @@ * Maximum number of queued byte[] chunks before enqueue starts discarding. * This bounds memory usage if the consumer is not cancelled promptly. */ - private static final int MAX_QUEUE_CHUNKS = 512; + private static final int MAX_QUEUE_CHUNKS = 64; private final BlockingQueue<byte[]> queue = new LinkedBlockingQueue<>(); private byte[] current; @@ -78,6 +78,7 @@ @Override public int read(final byte[] b, final int off, final int len) throws IOException { + if (error != null) throw error; if (closed) return -1; while (current == null || pos >= current.length) {
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/StreamingResponseConsumer.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/StreamingResponseConsumer.java index 80ad601..d12a4ed 100644 --- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/StreamingResponseConsumer.java +++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/StreamingResponseConsumer.java
@@ -213,7 +213,7 @@ boolean isFirstChunk = true; try { final InputStreamBuffer buffer = new InputStreamBuffer(queueInputStream); - while (true) { + while (!cancelled) { final ResponseMessage msg = serializer.readChunk(buffer, isFirstChunk); isFirstChunk = false;