Add zero copy version of pre-process json decoder#31
Conversation
… unit tests for consistency with original implementation, and add JMH benchmark. Signed-off-by: NeatGuyCoding <15627489+NeatGuyCoding@users.noreply.github.com>
…equired modules Signed-off-by: NeatGuyCoding <15627489+NeatGuyCoding@users.noreply.github.com>
There was a problem hiding this comment.
Pull Request Overview
This PR introduces a true zero-copy optimization for the JSON preprocessing functionality in the PacketDecoder class, achieving significant performance improvements (2.2x faster throughput based on benchmarks).
- Replaced string-based URL decoding with in-place ByteBuf manipulation to eliminate object allocations
- Added comprehensive test coverage including URL encoding, special characters, and Unicode support
- Added JMH benchmark demonstrating performance improvements (19,135 vs 8,616 ops/ms)
Reviewed Changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| PacketDecoder.java | Implements zero-copy preprocessJson method with in-place URL decoding and escaped newline handling |
| PacketDecoderTest.java | Adds comprehensive test cases for URL encoding scenarios and provides old implementation for comparison |
| PreprocessJsonBenchmark.java | New JMH benchmark class comparing old vs new preprocessJson performance |
| License header files | Updates license header format from <p> tags to simple * separators |
| Maven POM files | Adds checkstyle plugin configuration and updates CI build command |
| GitHub workflow | Changes Maven command from test to verify phase |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
netty-socketio-core/src/main/java/com/corundumstudio/socketio/protocol/PacketDecoder.java
Show resolved
Hide resolved
netty-socketio-core/src/test/java/com/corundumstudio/socketio/protocol/PacketDecoderTest.java
Outdated
Show resolved
Hide resolved
...cketio-core/src/test/java/com/corundumstudio/socketio/benchmark/PreprocessJsonBenchmark.java
Show resolved
Hide resolved
...cketio-core/src/test/java/com/corundumstudio/socketio/benchmark/PreprocessJsonBenchmark.java
Show resolved
Hide resolved
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughThe pull request optimizes JSON preprocessing in PacketDecoder by replacing string-based decoding with zero-copy in-place processing on ByteBuf. Supporting changes include Maven workflow transition to verify phase, new JMH benchmark for performance comparison, expanded test coverage with helper methods, and Maven-checkstyle-plugin configuration. Changes
Sequence DiagramsequenceDiagram
actor Client
participant PD as PacketDecoder
participant Buf as ByteBuf
participant Helpers as In-Place Helpers
Note over PD,Helpers: New Zero-Copy Approach
Client->>PD: preprocessJson(jsonIndex, ByteBuf)
PD->>Buf: Create copy of content
PD->>Helpers: urlDecodeInPlace(copied ByteBuf)
Helpers->>Buf: Decode URL entities in-place
Helpers-->>PD: Return mutated ByteBuf
PD->>Helpers: replaceEscapedNewlinesInPlace(copied ByteBuf)
Helpers->>Buf: Unescape newlines in-place
Helpers-->>PD: Return mutated ByteBuf
alt jsonIndex provided
PD->>Buf: Validate and advance readerIndex (skip "d=" prefix)
end
PD-->>Client: Return processed ByteBuf
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes The changes span multiple concerns (optimization, testing, build configuration) with mixed complexity. The core PacketDecoder refactoring introduces new in-place processing logic requiring careful review of buffer manipulation and edge cases. Test expansion and benchmark setup follow established patterns. Build config changes are straightforward but distributed across files. Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (4)
netty-socketio-core/src/main/java/com/corundumstudio/socketio/protocol/PacketDecoder.java (1)
145-153: Bug: writes 'n' instead of newline; should be '\n'.The comment and behavior diverge; replace with newline byte 0x0A.
Apply within this block:
- // Replace "\\n" with "\n" (1 byte: actual newline) - buffer.setByte(writePos, (byte) 'n'); + // Replace "\\n" with "\n" (1 byte: actual newline) + buffer.setByte(writePos, (byte) '\n');netty-socketio-core/src/test/java/com/corundumstudio/socketio/benchmark/PreprocessJsonBenchmark.java (2)
109-115: Critical: Memory leak from unreleased ByteBuf instances.Each benchmark iteration creates a new ByteBuf (via
content.copy()inpreprocessJson) that is returned but never released. JMH will accumulate these leaked buffers across thousands of iterations, causing memory exhaustion.Additionally, the past review comment about resetting the buffer's reader index remains unaddressed. While not strictly necessary given that
preprocessJsoncopies the buffer, resetting is defensive practice for benchmarks.Apply this diff to fix both issues:
@Benchmark public ByteBuf benchmarkNewMethod() throws UnsupportedEncodingException { ByteBuf buffer = testBuffers[bufferIndex % testBuffers.length]; + buffer.readerIndex(0); ByteBuf result = decoder.preprocessJson(1, buffer); bufferIndex++; + result.release(); - return result; + return Unpooled.EMPTY_BUFFER; }Note: Returning
Unpooled.EMPTY_BUFFERprevents JMH from optimizing away the method call while avoiding the leak. Alternatively, use JMH'sBlackholeto consume the result:@Benchmark -public ByteBuf benchmarkNewMethod() throws UnsupportedEncodingException { +public void benchmarkNewMethod(Blackhole blackhole) throws UnsupportedEncodingException { ByteBuf buffer = testBuffers[bufferIndex % testBuffers.length]; + buffer.readerIndex(0); ByteBuf result = decoder.preprocessJson(1, buffer); bufferIndex++; + blackhole.consume(result); + result.release(); - return result; }
117-123: Critical: Memory leak from unreleased ByteBuf instances.Each benchmark iteration creates a new ByteBuf (via
Unpooled.wrappedBuffer()inpreprocessJsonOld) that is returned but never released. This causes the same memory leak asbenchmarkNewMethod.Additionally, the past review comment about resetting the buffer's reader index remains unaddressed.
Apply this diff to fix both issues:
@Benchmark public ByteBuf benchmarkOldMethod() throws UnsupportedEncodingException { ByteBuf buffer = testBuffers[bufferIndex % testBuffers.length]; + buffer.readerIndex(0); ByteBuf result = preprocessJsonOld(1, buffer); bufferIndex++; + result.release(); - return result; + return Unpooled.EMPTY_BUFFER; }Or use JMH's
Blackhole:@Benchmark -public ByteBuf benchmarkOldMethod() throws UnsupportedEncodingException { +public void benchmarkOldMethod(Blackhole blackhole) throws UnsupportedEncodingException { ByteBuf buffer = testBuffers[bufferIndex % testBuffers.length]; + buffer.readerIndex(0); ByteBuf result = preprocessJsonOld(1, buffer); bufferIndex++; + blackhole.consume(result); + result.release(); - return result; }netty-socketio-core/src/test/java/com/corundumstudio/socketio/protocol/PacketDecoderTest.java (1)
569-569: Remove debug print statement.This debug print statement should be removed from production test code, as noted in the previous review.
Apply this diff:
- System.out.println(testCase);
🧹 Nitpick comments (4)
.github/workflows/build.yml (1)
26-26: Switch to verify looks good; consider-ntpto cut CI noise.Keeps semantics while enabling verify-bound plugins. Optional: add
-ntpto reduce transfer logs in CI.Apply within this line:
- mvn --batch-mode --errors --fail-at-end verify + mvn --batch-mode --errors --fail-at-end -ntp verifynetty-socketio-smoke-test/pom.xml (1)
117-124: Checkstyle plugin is added but inert (skip=true, no executions). Intentional?As configured, it won’t run nor fail the build. If the goal is future enforcement, consider centralizing plugin config in parent POM and binding an execution with
<goal>check</goal>(kept skipped by default).netty-socketio-quarkus/netty-socketio-quarkus-deployment/pom.xml (1)
46-61: Usecheckgoal (fail build) instead ofcheckstyle(report only) for verify-time enforcement.Currently, even if you flip
<skip>false</skip>,checkstylewon’t fail the build. Usecheckto enforce.Apply within these lines:
<executions> <execution> <phase>verify</phase> <goals> - <goal>checkstyle</goal> + <goal>check</goal> </goals> </execution> </executions> <configuration> <skip>true</skip> </configuration>netty-socketio-core/src/main/java/com/corundumstudio/socketio/protocol/PacketDecoder.java (1)
89-127: URL decoding behavior changes vsURLDecoder: incomplete%sequences and exception type.
- Incomplete or malformed escapes (e.g., trailing
%or%GZ) are passed through, whereasURLDecoderthrows. This may alter behavior. Confirm desired compatibility and update tests accordingly.UnsupportedEncodingExceptionis not actually thrown; remove from the private method signature.Apply signature change here:
- private void urlDecodeInPlace(ByteBuf buffer) throws UnsupportedEncodingException { + private void urlDecodeInPlace(ByteBuf buffer) {If strict parity with
URLDecoder.decode(..., UTF-8)is required, detect incomplete%patterns and either throw or replace with U+FFFD per project policy.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
.github/workflows/build.yml(1 hunks)netty-socketio-core/src/main/java/com/corundumstudio/socketio/protocol/PacketDecoder.java(1 hunks)netty-socketio-core/src/test/java/com/corundumstudio/socketio/benchmark/PreprocessJsonBenchmark.java(1 hunks)netty-socketio-core/src/test/java/com/corundumstudio/socketio/protocol/PacketDecoderTest.java(3 hunks)netty-socketio-quarkus/netty-socketio-quarkus-deployment/pom.xml(1 hunks)netty-socketio-quarkus/netty-socketio-quarkus-runtime/src/main/java/com/corundumstudio/socketio/quarkus/lifecycle/SocketIOServerLifecycle.java(1 hunks)netty-socketio-smoke-test/pom.xml(1 hunks)netty-socketio-smoke-test/src/main/java/com/corundumstudio/socketio/smoketest/ClientMetrics.java(1 hunks)netty-socketio-smoke-test/src/main/java/com/corundumstudio/socketio/smoketest/ServerMain.java(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
netty-socketio-core/src/test/java/com/corundumstudio/socketio/benchmark/PreprocessJsonBenchmark.java (2)
netty-socketio-core/src/main/java/com/corundumstudio/socketio/protocol/PacketDecoder.java (1)
PacketDecoder(34-526)netty-socketio-core/src/test/java/com/corundumstudio/socketio/protocol/PacketDecoderTest.java (1)
PacketDecoderTest(56-780)
🔇 Additional comments (8)
netty-socketio-smoke-test/src/main/java/com/corundumstudio/socketio/smoketest/ClientMetrics.java (1)
3-3: License header formatting only—no functional impact.The changes remove
<p>tags and adjust indentation in the Apache License header. The implementation code remains unchanged and the class design is sound (good use of thread-safeLongAdderandHistogramfor metrics collection).Also applies to: 7-7, 8-8, 9-9
netty-socketio-smoke-test/src/main/java/com/corundumstudio/socketio/smoketest/ServerMain.java (1)
3-3: License header formatting update.The license header formatting has been adjusted (blank line added and indentation refined). These are purely cosmetic changes with no impact on functionality.
Also applies to: 7-9
netty-socketio-quarkus/netty-socketio-quarkus-runtime/src/main/java/com/corundumstudio/socketio/quarkus/lifecycle/SocketIOServerLifecycle.java (1)
3-9: LGTM: license header formatting only.No behavior change.
netty-socketio-core/src/main/java/com/corundumstudio/socketio/protocol/PacketDecoder.java (1)
79-84: Resource ownership: confirm caller releases returned buffer.With
retainedSlice()(or even currentcopy()), the returned buffer has refCnt 1 and must be released by the caller. Ensure all call sites follow this to avoid leaks.netty-socketio-core/src/test/java/com/corundumstudio/socketio/benchmark/PreprocessJsonBenchmark.java (1)
60-107: LGTM: Proper buffer lifecycle management in setup/tearDown.The setup and tearDown methods correctly manage ByteBuf resources for the test cases.
netty-socketio-core/src/test/java/com/corundumstudio/socketio/protocol/PacketDecoderTest.java (3)
56-56: LGTM: Public visibility enables code reuse.Making the class public allows the benchmark to access the
preprocessJsonOldhelper method, which is appropriate for sharing test utilities.
492-593: Excellent test coverage for URL encoding edge cases.The test comprehensively validates URL decoding across special characters, Unicode sequences, and mixed-escape scenarios, ensuring equivalence between legacy and new preprocessing implementations. The buffer lifecycle management and reader index reset (line 577) are handled correctly.
595-612: LGTM: Well-designed helper for legacy implementation.The
preprocessJsonOldhelper method effectively encapsulates the legacy preprocessing logic and enables code reuse between the test and benchmark. The implementation correctly handles URL decoding and escaped newline replacement.
netty-socketio-core/src/main/java/com/corundumstudio/socketio/protocol/PacketDecoder.java
Outdated
Show resolved
Hide resolved
netty-socketio-core/src/main/java/com/corundumstudio/socketio/protocol/PacketDecoder.java
Show resolved
Hide resolved
…onable tests Signed-off-by: NeatGuyCoding <15627489+NeatGuyCoding@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (3)
netty-socketio-core/src/test/java/com/corundumstudio/socketio/protocol/PacketDecoderTest.java (1)
674-699: Remove or downgrade logging statement from production test code.Line 677 uses
log.info()which will clutter test output. Change tolog.debug()or remove entirely, as JUnit already tracks test execution.Apply this diff:
- log.info("Running preprocessJson test for case: {}", testCase); + log.debug("Running preprocessJson test for case: {}", testCase);netty-socketio-core/src/main/java/com/corundumstudio/socketio/protocol/PacketDecoder.java (2)
52-64: Not actually zero-copy;copy()defeats the PR's goal and contradicts Javadoc.
content.copy()at line 63 allocates and memcpy's the entire buffer, which contradicts both the "True zero-copy" claim in the Javadoc and the PR's performance objectives. UseretainedSlice()(orretainedDuplicate()) to achieve actual zero-copy by working on a view of the original buffer with independent indices. The caller must then release the returned buffer.Apply this diff:
/** - * True zero-copy optimized version of preprocessJson that works directly with ByteBuf - * without string conversion and without creating new ByteBuf instances. - * + * Zero-copy preprocessing that operates on a retained slice of the input ByteBuf + * without string conversion and without allocating new byte arrays. + * * @param jsonIndex JSONP index, if null then no JSONP processing is needed * @param content the input ByteBuf containing the packet data - * @return processed ByteBuf with true zero-copy optimization - * @throws UnsupportedEncodingException if UTF-8 encoding is not supported + * @return processed ByteBuf (caller must release) */ public ByteBuf preprocessJson(Integer jsonIndex, ByteBuf content) throws UnsupportedEncodingException { - // Create a mutable copy of the input ByteBuf for in-place modifications - ByteBuf mutableContent = content.copy(); + // Work on a retained slice to avoid copying; caller must release the returned buffer + ByteBuf mutableContent = content.retainedSlice();
69-77: Guard skipping of the "d=" prefix; current code drops first 2 bytes unconditionally whenjsonIndex != null.This can corrupt payloads that don't start with
d=. Verify the prefix before advancing the reader index.Apply this diff:
- // Skip "d=" prefix (2 bytes) by adjusting reader index + // Skip "d=" prefix (2 bytes) only if present if (mutableContent.readableBytes() >= 2) { - mutableContent.readerIndex(mutableContent.readerIndex() + 2); + int ri = mutableContent.readerIndex(); + if (mutableContent.getByte(ri) == (byte) 'd' + && mutableContent.getByte(ri + 1) == (byte) '=') { + mutableContent.readerIndex(ri + 2); + } }
🧹 Nitpick comments (1)
netty-socketio-core/src/main/java/com/corundumstudio/socketio/protocol/PacketDecoder.java (1)
130-154: Clarify confusing comment notation for escaped newline replacement.The comment at line 130 uses identical notation for both the before and after states:
"\\n"with"\n", making it unclear what transformation is being described. The code correctly replaces a 3-byte sequence (backslash, backslash, n) with a 2-byte sequence (backslash, n), matching the legacy implementation at line 711 in PacketDecoderTest.java. Clarify the comment to explicitly state the byte-level transformation to avoid confusion.Consider this clarification:
/** - * Replace escaped newlines "\\n" with "\n" in-place - * Note: This reduces the buffer size from 3 bytes("\\n") to 2 byte("\n") per replacement + * Replace double-escaped newlines with single-escaped newlines in-place. + * Transforms the 3-byte sequence (backslash, backslash, 'n') to 2-byte sequence (backslash, 'n'). * because unescaping of new lines can be done safely on server-side(c) socket.io.js * @see https://github.com/Automattic/socket.io-client/blob/1.3.3/socket.io.js#L2682 */
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
netty-socketio-core/src/main/java/com/corundumstudio/socketio/protocol/PacketDecoder.java(1 hunks)netty-socketio-core/src/test/java/com/corundumstudio/socketio/protocol/PacketDecoderTest.java(22 hunks)
🔇 Additional comments (5)
netty-socketio-core/src/main/java/com/corundumstudio/socketio/protocol/PacketDecoder.java (2)
86-127: LGTM! URL decoding logic is correct.The in-place URL decoding correctly handles percent-encoded characters (%XX), plus-to-space conversion, and adjusts the writer index after processing. The implementation properly validates hex digits before decoding.
171-190: LGTM! Hex digit validation and conversion helpers are correct.The helper methods properly validate and convert hexadecimal digits, with appropriate error handling for invalid input.
netty-socketio-core/src/test/java/com/corundumstudio/socketio/protocol/PacketDecoderTest.java (3)
61-62: LGTM! Public visibility and logging support added appropriately.Making the test class public and adding logging support enables better test observability and external benchmark integration, aligning with the PR's addition of JMH benchmarking in PreprocessJsonBenchmark.
498-672: Excellent comprehensive test coverage for URL encoding scenarios.The test suite thoroughly exercises edge cases including all byte values (0x00-0xFF), extensive special characters, unicode, emojis, and double encoding. This ensures correctness of the new zero-copy implementation against the legacy approach.
701-718: LGTM! Legacy implementation preserved for comparison testing.The
preprocessJsonOldmethod correctly preserves the original string-based decoding logic, providing a reliable baseline for validating the new in-place implementation. Making this method public enables its use in benchmarks.
…onable tests Signed-off-by: NeatGuyCoding <15627489+NeatGuyCoding@users.noreply.github.com>
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
netty-socketio-core/src/main/java/com/corundumstudio/socketio/protocol/PacketDecoder.java
Show resolved
Hide resolved
netty-socketio-core/src/main/java/com/corundumstudio/socketio/protocol/PacketDecoder.java
Show resolved
Hide resolved
netty-socketio-core/src/test/java/com/corundumstudio/socketio/protocol/PacketDecoderTest.java
Show resolved
Hide resolved
netty-socketio-core/src/test/java/com/corundumstudio/socketio/protocol/PacketDecoderTest.java
Show resolved
Hide resolved
netty-socketio-core/src/test/java/com/corundumstudio/socketio/protocol/PacketDecoderTest.java
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (2)
netty-socketio-core/src/main/java/com/corundumstudio/socketio/protocol/PacketDecoder.java (2)
139-179: Escaped newline replacement is functionally wrong; write '\n' and match 2-byte pattern (“\” + “n”).
- Should detect backslash + 'n' (two bytes), not “\n” (three).
- Should write the newline byte 0x0A, not '' and 'n'.
- Size reduces 2 bytes → 1 byte, not “3 → 2”.
- /** - * Replace escaped newlines "\\n" with "\n" in-place - * Note: This reduces the buffer size from 3 bytes("\\n") to 2 byte("\n") per replacement + /** + * Replace escaped newlines "\\n" with a real newline in-place. + * Note: This reduces the buffer size from 2 bytes ("\\n") to 1 byte ('\n') per replacement * because unescaping of new lines can be done safely on server-side(c) socket.io.js * @see https://github.com/Automattic/socket.io-client/blob/1.3.3/socket.io.js#L2682 */ private void replaceEscapedNewlinesInPlace(ByteBuf buffer) { int readerIndex = buffer.readerIndex(); int writerIndex = buffer.writerIndex(); int readPos = readerIndex; int writePos = readerIndex; while (readPos < writerIndex) { byte b = buffer.getByte(readPos); - // Check for "\\\\n" pattern (real 3 bytes: "\\n") - if (b == '\\' && readPos + 2 < writerIndex) { - byte b1 = buffer.getByte(readPos + 1); - byte b2 = buffer.getByte(readPos + 2); - - if (b1 == '\\' && b2 == 'n') { - buffer.setByte(writePos, (byte) '\\'); - writePos++; - buffer.setByte(writePos, (byte) 'n'); - writePos++; - readPos += 3; // Skip both bytes + // Check for "\n" escape (two bytes: '\' + 'n') + if (b == '\\' && readPos + 1 < writerIndex) { + byte b1 = buffer.getByte(readPos + 1); + if (b1 == 'n') { + buffer.setByte(writePos, (byte) '\n'); + writePos++; + readPos += 2; // consume '\' and 'n' } else { buffer.setByte(writePos, b); writePos++; readPos++; } } else { buffer.setByte(writePos, b); writePos++; readPos++; } } // Adjust writer index to reflect the new length buffer.writerIndex(writePos); }
66-93: Zero-copy semantics + refCnt safety: avoid slice()+release(); mutate in place or retain the slice.Current flow:
- slice() returns a derived buffer sharing refCnt with content.
- releasing the slice in catch can prematurely release the original.
- Returning an unretained slice can cause lifetime confusion.
Prefer true in-place mutation and return the same buffer, or retain the slice and never release here.
Option A (simplest, true zero-copy): mutate input and return it.
- // Create a mutable copy of the input ByteBuf for in-place modifications - ByteBuf mutableContent = content.slice(); - try { - // Perform URL decoding in-place - urlDecodeInPlace(mutableContent); - - if (jsonIndex != null) { - // Handle escaped newlines in-place: replace "\\n" with "\n" - replaceEscapedNewlinesInPlace(mutableContent); - - // Skip "d=" prefix (2 bytes) by adjusting reader index - if (mutableContent.readableBytes() >= 2) { - int ri = mutableContent.readerIndex(); - // Check for 'd=' prefix - if (mutableContent.getByte(ri) == (byte) 'd' - && mutableContent.getByte(ri + 1) == (byte) '=') { - mutableContent.readerIndex(ri + 2); - } else { - throw new IllegalArgumentException("Invalid JSONP format: missing 'd=' prefix"); - } - } - } - - return mutableContent; - } catch (Exception e) { - mutableContent.release(); - throw e; - } + // Mutate content in place; no allocation, no refCnt juggling + urlDecodeInPlace(content); + + if (jsonIndex != null) { + // Replace "\n" escape with newline and then skip "d=" + replaceEscapedNewlinesInPlace(content); + + if (content.readableBytes() >= 2) { + int ri = content.readerIndex(); + if (content.getByte(ri) == (byte) 'd' && content.getByte(ri + 1) == (byte) '=') { + content.readerIndex(ri + 2); + } else { + throw new IllegalArgumentException("Invalid JSONP format: missing 'd=' prefix"); + } + } + } + return content;Option B (if you need independent indices): use retainedSlice() and don’t release here; document caller must release the returned buffer.
- ByteBuf mutableContent = content.slice(); + ByteBuf mutableContent = content.retainedSlice(); try { urlDecodeInPlace(mutableContent); ... return mutableContent; } catch (Exception e) { - mutableContent.release(); + // no release of 'content' here; only the retained slice + mutableContent.release(); throw e; }
🧹 Nitpick comments (4)
netty-socketio-core/src/main/java/com/corundumstudio/socketio/protocol/PacketDecoder.java (2)
56-64: Javadoc overstates “true zero-copy” and “no new ByteBuf instances.”You create a derived buffer via slice(). Clarify semantics (zero-copy: no new byte arrays; may return the same buffer or a slice).
- /** - * True zero-copy optimized version of preprocessJson that works directly with ByteBuf - * without string conversion and without creating new ByteBuf instances. - * + /** + * Zero-copy preprocessing that operates directly on a ByteBuf without string conversion + * and without allocating new byte arrays. It mutates the buffer contents in place and + * returns a buffer view of the processed data. + *
99-137: No need to declare UnsupportedEncodingException; consider removing redundant throws.urlDecodeInPlace does not use APIs that can throw UnsupportedEncodingException. Consider removing it here and from preprocessJson’s signature (if source/binary compatibility allows).
netty-socketio-core/src/test/java/com/corundumstudio/socketio/protocol/PacketDecoderTest.java (2)
674-698: Release newResult and reduce test log noise.Add release to avoid leaks if preprocessJson returns a retained slice; prefer debug level for noisy per‑case logs.
- log.info("Running preprocessJson test for case: {}", testCase); + log.debug("Running preprocessJson test for case: {}", testCase); @@ - // Clean up - buffer.release(); - originalResult.release(); + // Clean up + buffer.release(); + originalResult.release(); + if (newResult.refCnt() > 0) { + newResult.release(); + }If you keep returning the original buffer (in‑place), the added release will be a no‑op due to shared refCnt; if you switch to retainedSlice(), this prevents leaks. Please confirm with a quick CI run.
498-671: Large combinatorial inputs may slow CI; consider tagging as “slow” or parameterizing.The exhaustive encoded cases are great for coverage but can make unit tests heavy. Consider moving them under a separate @tag("slow") or splitting into parameterized subsets.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
netty-socketio-core/src/main/java/com/corundumstudio/socketio/protocol/PacketDecoder.java(3 hunks)netty-socketio-core/src/test/java/com/corundumstudio/socketio/protocol/PacketDecoderTest.java(22 hunks)
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
netty-socketio-quarkus/netty-socketio-quarkus-deployment/pom.xml(1 hunks)netty-socketio-smoke-test/pom.xml(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: build (17) / build
- GitHub Check: build (21) / build
🔇 Additional comments (1)
netty-socketio-smoke-test/pom.xml (1)
117-125: Version 3.6.0 is confirmed as the latest stable release — no further action needed.The maven-checkstyle-plugin version 3.6.0 is the current stable version (released 2024-10-22) and is fully supported. The configuration appropriately skips checkstyle for the smoke-test module as part of the workflow transition to the verify phase.
Result:
Summary by CodeRabbit
Chores
Tests