-
-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve binary serialization performance #460
Conversation
📝 WalkthroughWalkthroughThe pull request introduces a new Changes
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (6)
src/test/java/org/joda/beans/ser/bin/TestLinkedByteArrayOutputStream.java (5)
30-36
: Ensure more boundary coverage
Currently, the test ensures that an unused instance ofLinkedByteArrayOutputStream
remains empty. Consider adding a boundary test for negative input or zero-length writes to improve coverage.
40-46
: Validate edge case for large single-byte writes
While this test confirms that writing a single byte works, you could also test extremes, such asInteger.MAX_VALUE
or negative bytes, to ensure they are handled correctly.
50-56
: Test name mismatch
The method nametest_writeByte_growCapacity
is fine, but consider verifying internal segment transitions more thoroughly. You might also confirm that multiple capacity expansions behave correctly, as a single expansion might not detect all edge conditions.
84-93
: Check partial writes in multiple expansions
This test verifies a partial write near the capacity boundary. Adding one more partial write sequence past the capacity might expose potential off-by-one errors in segment transitions.
98-107
: Confirm array content post-expansion
The test ensures correct handling of large byte arrays, but consider verifying random data or partial offsets after expansions to gain extra confidence in correctness.src/main/java/org/joda/beans/ser/bin/LinkedByteArrayOutputStream.java (1)
39-47
: Possible micro-optimisation
TheByteSegment
class and logic appear well structured. If you anticipate extremely large writes, you might consider pre-sizing segments beyond 1024 or making it configurable. However, as is, this is straightforward and likely meets typical usage needs.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/main/java/org/joda/beans/ser/bin/JodaBeanBinWriter.java
(1 hunks)src/main/java/org/joda/beans/ser/bin/LinkedByteArrayOutputStream.java
(1 hunks)src/test/java/org/joda/beans/ser/bin/TestLinkedByteArrayOutputStream.java
(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
src/main/java/org/joda/beans/ser/bin/JodaBeanBinWriter.java (2)
Pattern **/*.java
: - Review code using Java 21 standards, taking into account the rules defined by src/main/checkstyle/checkstyle.xml
.
- Validate that code indentation uses spaces, not tabs, with an indent of multiple of 4.
- Validate that immutable local variables are not annotated with
final
unless the variable is required for use in an inner class. - Favour use of
var
keyword for type declarations.var
may also be used when the value is a castnull
. - Use a coding standard where multi-line expressions have operators and tenary separators at the end of line.
- Propose changes that only use the Java 21 API, not the API of Guava.
- The pattern matching
instanceof
expression safely handlesnull
, returningfalse
.
Pattern **/main/java/**/*.java
: - This project is mature and must provide a stable backwards-compatible public Java API.
- In the 'Walkthrough' section, you must always provide a list of up to 25 changes to the public Java API that will affect end users.
If there are no changes, you must explicitly state that there are no changes to the public Java API in this PR.
The public Java API is defined as public and protected methods on public classes, plus the filemodule-info.java
.
Provide the list by deeply analysing code flow, which incudes analysing code flow through private methods and calls to Guava and Java 21.
Changes to be reported on include:- New or removed methods in the public Java API
- Changes to method return types or parameter types in the public Java API
- Changes to method behaviour in the public Java API that might affect consumers
- This project uses
System.out.println
instead of logging - This project tends to prefer
for
loops to streams for performance reasons, however either form is acceptable.
Do not make suggestions to change between streams and for loops or vice versa.
src/main/java/org/joda/beans/ser/bin/LinkedByteArrayOutputStream.java (2)
Pattern **/*.java
: - Review code using Java 21 standards, taking into account the rules defined by src/main/checkstyle/checkstyle.xml
.
- Validate that code indentation uses spaces, not tabs, with an indent of multiple of 4.
- Validate that immutable local variables are not annotated with
final
unless the variable is required for use in an inner class. - Favour use of
var
keyword for type declarations.var
may also be used when the value is a castnull
. - Use a coding standard where multi-line expressions have operators and tenary separators at the end of line.
- Propose changes that only use the Java 21 API, not the API of Guava.
- The pattern matching
instanceof
expression safely handlesnull
, returningfalse
.
Pattern **/main/java/**/*.java
: - This project is mature and must provide a stable backwards-compatible public Java API.
- In the 'Walkthrough' section, you must always provide a list of up to 25 changes to the public Java API that will affect end users.
If there are no changes, you must explicitly state that there are no changes to the public Java API in this PR.
The public Java API is defined as public and protected methods on public classes, plus the filemodule-info.java
.
Provide the list by deeply analysing code flow, which incudes analysing code flow through private methods and calls to Guava and Java 21.
Changes to be reported on include:- New or removed methods in the public Java API
- Changes to method return types or parameter types in the public Java API
- Changes to method behaviour in the public Java API that might affect consumers
- This project uses
System.out.println
instead of logging - This project tends to prefer
for
loops to streams for performance reasons, however either form is acceptable.
Do not make suggestions to change between streams and for loops or vice versa.
src/test/java/org/joda/beans/ser/bin/TestLinkedByteArrayOutputStream.java (2)
Pattern **/*.java
: - Review code using Java 21 standards, taking into account the rules defined by src/main/checkstyle/checkstyle.xml
.
- Validate that code indentation uses spaces, not tabs, with an indent of multiple of 4.
- Validate that immutable local variables are not annotated with
final
unless the variable is required for use in an inner class. - Favour use of
var
keyword for type declarations.var
may also be used when the value is a castnull
. - Use a coding standard where multi-line expressions have operators and tenary separators at the end of line.
- Propose changes that only use the Java 21 API, not the API of Guava.
- The pattern matching
instanceof
expression safely handlesnull
, returningfalse
.
Pattern **/test/java/**/*.java
: For test code, focus on:
- Correctness of test assertions
- Test coverage of edge cases
- Clear test naming and documentation
- Encourage test methods to be package-scoped where possible
- Be more lenient with code style and minor optimisations
🔇 Additional comments (4)
src/main/java/org/joda/beans/ser/bin/JodaBeanBinWriter.java (1)
102-102
: Performance enhancement
ReplacingByteArrayOutputStream
withLinkedByteArrayOutputStream
likely improves memory allocation patterns and performance. Good work ensuring that the method signature remains unchanged for backwards compatibility.src/main/java/org/joda/beans/ser/bin/LinkedByteArrayOutputStream.java (3)
76-97
: Potential data race concerns
This class is documented as not thread-safe. If multi-threaded usage is expected in the future, highlight concurrency constraints in Javadoc or add safety checks (e.g., usage under a lock or ensuring each segment remains private).
110-114
: Efficient streaming
UsingwriteTo(OutputStream)
to stream the data directly is a good addition. This design prevents allocating a potentially large combined byte array unnecessarily.
159-169
: Hex representation clarity
Printing the written bytes in hex form is a valuable debugging tool. The approach is clear and succinct.
fcbdb9d
to
03acad7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (3)
src/test/java/org/joda/beans/ser/json/TestJsonPerformance.java (1)
38-50
: Consider expanding edge-case coverage
At present, this performance test focuses on typical usage but does not exercise edge cases (e.g. highly nested beans or empty fields). Including edge cases helps identify potential performance bottlenecks and ensures more robust measurement across various scenarios.src/main/java/org/joda/beans/ser/LinkedByteArrayOutputStream.java (2)
70-77
: Potential concurrency implications
This class is not thread-safe, which matches the JavaDoc note. If required for concurrent use, you may need synchronisation or a thread-confined usage pattern.
88-110
: Efficient handling of large writes
Splitting large writes or copying them as single segments is a sensible approach. However, you could further explore a dynamic resizing strategy that reuses segments.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/changes/changes.xml
(2 hunks)src/main/java/org/joda/beans/ser/LinkedByteArrayOutputStream.java
(1 hunks)src/main/java/org/joda/beans/ser/bin/JodaBeanBinWriter.java
(2 hunks)src/test/java/org/joda/beans/ser/TestLinkedByteArrayOutputStream.java
(1 hunks)src/test/java/org/joda/beans/ser/bin/TestBinPerformance.java
(1 hunks)src/test/java/org/joda/beans/ser/json/TestJsonPerformance.java
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/main/java/org/joda/beans/ser/bin/JodaBeanBinWriter.java
🧰 Additional context used
📓 Path-based instructions (4)
src/test/java/org/joda/beans/ser/bin/TestBinPerformance.java (2)
Pattern **/*.java
: - Review code using Java 21 standards, taking into account the rules defined by src/main/checkstyle/checkstyle.xml
.
- Validate that code indentation uses spaces, not tabs, with an indent of multiple of 4.
- Validate that immutable local variables are not annotated with
final
unless the variable is required for use in an inner class. - Favour use of
var
keyword for type declarations.var
may also be used when the value is a castnull
. - Use a coding standard where multi-line expressions have operators and tenary separators at the end of line.
- Propose changes that only use the Java 21 API, not the API of Guava.
- The pattern matching
instanceof
expression safely handlesnull
, returningfalse
.
Pattern **/test/java/**/*.java
: For test code, focus on:
- Correctness of test assertions
- Test coverage of edge cases
- Clear test naming and documentation
- Encourage test methods to be package-scoped where possible
- Be more lenient with code style and minor optimisations
src/test/java/org/joda/beans/ser/TestLinkedByteArrayOutputStream.java (2)
Pattern **/*.java
: - Review code using Java 21 standards, taking into account the rules defined by src/main/checkstyle/checkstyle.xml
.
- Validate that code indentation uses spaces, not tabs, with an indent of multiple of 4.
- Validate that immutable local variables are not annotated with
final
unless the variable is required for use in an inner class. - Favour use of
var
keyword for type declarations.var
may also be used when the value is a castnull
. - Use a coding standard where multi-line expressions have operators and tenary separators at the end of line.
- Propose changes that only use the Java 21 API, not the API of Guava.
- The pattern matching
instanceof
expression safely handlesnull
, returningfalse
.
Pattern **/test/java/**/*.java
: For test code, focus on:
- Correctness of test assertions
- Test coverage of edge cases
- Clear test naming and documentation
- Encourage test methods to be package-scoped where possible
- Be more lenient with code style and minor optimisations
src/test/java/org/joda/beans/ser/json/TestJsonPerformance.java (2)
Pattern **/*.java
: - Review code using Java 21 standards, taking into account the rules defined by src/main/checkstyle/checkstyle.xml
.
- Validate that code indentation uses spaces, not tabs, with an indent of multiple of 4.
- Validate that immutable local variables are not annotated with
final
unless the variable is required for use in an inner class. - Favour use of
var
keyword for type declarations.var
may also be used when the value is a castnull
. - Use a coding standard where multi-line expressions have operators and tenary separators at the end of line.
- Propose changes that only use the Java 21 API, not the API of Guava.
- The pattern matching
instanceof
expression safely handlesnull
, returningfalse
.
Pattern **/test/java/**/*.java
: For test code, focus on:
- Correctness of test assertions
- Test coverage of edge cases
- Clear test naming and documentation
- Encourage test methods to be package-scoped where possible
- Be more lenient with code style and minor optimisations
src/main/java/org/joda/beans/ser/LinkedByteArrayOutputStream.java (2)
Pattern **/*.java
: - Review code using Java 21 standards, taking into account the rules defined by src/main/checkstyle/checkstyle.xml
.
- Validate that code indentation uses spaces, not tabs, with an indent of multiple of 4.
- Validate that immutable local variables are not annotated with
final
unless the variable is required for use in an inner class. - Favour use of
var
keyword for type declarations.var
may also be used when the value is a castnull
. - Use a coding standard where multi-line expressions have operators and tenary separators at the end of line.
- Propose changes that only use the Java 21 API, not the API of Guava.
- The pattern matching
instanceof
expression safely handlesnull
, returningfalse
.
Pattern **/main/java/**/*.java
: - This project is mature and must provide a stable backwards-compatible public Java API.
- In the 'Walkthrough' section, you must always provide a list of up to 25 changes to the public Java API that will affect end users.
If there are no changes, you must explicitly state that there are no changes to the public Java API in this PR.
The public Java API is defined as public and protected methods on public classes, plus the filemodule-info.java
.
Provide the list by deeply analysing code flow, which incudes analysing code flow through private methods and calls to Guava and Java 21.
Changes to be reported on include:- New or removed methods in the public Java API
- Changes to method return types or parameter types in the public Java API
- Changes to method behaviour in the public Java API that might affect consumers
- This project uses
System.out.println
instead of logging - This project tends to prefer
for
loops to streams for performance reasons, however either form is acceptable.
Do not make suggestions to change between streams and for loops or vice versa.
🔇 Additional comments (10)
src/test/java/org/joda/beans/ser/json/TestJsonPerformance.java (1)
32-32
: Good use of @disabled for performance tests
As this is a performance test, marking it with@Disabled
helps prevent unintentional long-running test executions in the automated CI pipeline.src/test/java/org/joda/beans/ser/bin/TestBinPerformance.java (2)
32-32
: Performance test disabled
Similarly to the JSON performance test, using@Disabled
here is consistent with the project's approach to performance testing. It prevents unintentional execution in routine test suites.
38-50
: Verify bin-to-bin round-trip consistency
While this test measures performance, you may want to include a quick integrity check to ensure the round-tripped binary data matches the original bean data.src/test/java/org/joda/beans/ser/TestLinkedByteArrayOutputStream.java (3)
29-36
: Excellent coverage for empty stream cases
The test confirms the stream's behaviour when unused, facilitating confidence in the default initial state.
48-56
: Thorough testing of capacity growth
Verifying that data is correctly appended beyond the initial buffer size is crucial. The tests here use a good approach to ensure correctness for large writes.
80-90
: Appreciate precise substring writing checks
Writing only part of a byte array and verifying the resulting content is an effective way to prevent boundary errors in the stream implementation.src/main/java/org/joda/beans/ser/LinkedByteArrayOutputStream.java (2)
36-36
: Class naming and scope
Naming the classLinkedByteArrayOutputStream
is self-explanatory. Since it is a specialised output stream for performance, ensure it remains internally well-documented regarding its intended usage and limitations.
180-187
: Hex conversion clarity
UsingHexFormat
fortoString()
is a helpful feature. This ensures simple debugging by displaying the stream contents in hex format.src/changes/changes.xml (2)
21-23
: LGTM! The change aligns with the PR objectives.The addition of
LinkedByteArrayOutputStream
as a faster alternative toByteArrayOutputStream
directly supports the goal of improving binary serialisation performance.
54-54
: Verify the impact on binary serialisation performance.The change to handle
Iterable
as a collection type in standard binary format could affect serialisation performance. Please ensure this change has been performance tested.Run the following script to check for performance tests:
✅ Verification successful
No significant performance impact from Iterable serialisation changes
The implementation shows that Iterable serialisation is handled by converting to a List using Java's Stream API, which is an efficient operation. The conversion is necessary since Iterable lacks size information, and the resulting List is then processed using the existing collection serialisation logic. This approach:
- Maintains type safety through generics
- Preserves the order of elements
- Reuses existing optimised collection serialisation code
The presence of performance test files (
TestBinPerformance.java
andTestJsonPerformance.java
) indicates that serialisation performance is monitored, though no specific Iterable-related performance regressions are evident.🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check for performance tests related to Iterable serialisation. # Search for performance test files fd -e java -e kt -e scala ".*[Pp]erformance.*Test.*" | grep -i "serial" # Search for test cases involving Iterable rg -l "Iterable.*serialize|serialize.*Iterable"Length of output: 121
Script:
#!/bin/bash # Let's try a broader search for performance tests and serialisation-related files # Search for any test files related to serialisation fd -e java -e kt -e scala ".*[Ss]erial.*Test.*" # Search for any performance-related files fd -e java -e kt -e scala ".*[Pp]erformance.*" # Search for files containing both 'binary' and 'format' keywords rg -l "binary.*format|format.*binary" # Look for test files containing 'Iterable' rg -l "Iterable" -g "*Test*"Length of output: 1517
Script:
#!/bin/bash # Let's examine the performance test files and their content # Check TestBinPerformance.java content echo "=== TestBinPerformance.java ===" rg -A 5 -B 5 "Iterable|Collection|List|Set" src/test/java/org/joda/beans/ser/bin/TestBinPerformance.java # Check recent changes to performance tests echo "=== Recent changes to performance tests ===" git log -p --since="6 months ago" src/test/java/org/joda/beans/ser/bin/TestBinPerformance.java # Check the implementation of Iterable serialisation echo "=== Iterable serialisation implementation ===" rg -A 5 -B 5 "Iterable" src/main/java/org/joda/beans/ser/bin/JodaBeanStandardBinWriter.javaLength of output: 2591
* Add a dedicated byte array output stream * Performance gain of 20-30% when used * Add Binary and JSON performance tests
03acad7
to
b939fd4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (3)
src/changes/changes.xml (3)
21-23
: Consider adding performance metrics to the changelog entry.The changelog entry could be more informative by including specific performance improvements achieved with
LinkedByteArrayOutputStream
compared toByteArrayOutputStream
. This would help users understand the magnitude of the optimisation.Consider expanding the entry like this:
- Add `LinkedByteArrayOutputStream`, which is like `ByteArrayOutputStream` but faster. + Add `LinkedByteArrayOutputStream`, which is like `ByteArrayOutputStream` but with X% better performance in binary serialisation operations through optimised byte array handling.
24-26
: Enhance the documentation for ResolvedType.The current description is quite vague about how
ResolvedType
simplifies generic type management. Consider providing more context about its benefits and use cases.Consider expanding the entry like this:
- Add `ResolvedType`, which allows generic type information to be managed in a simple way. + Add `ResolvedType`, which simplifies generic type management by providing a structured way to resolve and manipulate type parameters at runtime, improving type safety and reducing boilerplate code.
54-54
: Document the previous behaviour for better migration guidance.For a potentially incompatible change, it would be helpful to document how
Iterable
was handled previously. This would help users understand the impact and necessary migration steps.Consider expanding the entry like this:
- The standard binary and JSON formats now handle `Iterable` as a collection type. + The standard binary and JSON formats now handle `Iterable` as a collection type. Previously, Iterable instances were not directly serialisable and required conversion to concrete collection types.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/changes/changes.xml
(2 hunks)src/main/java/org/joda/beans/ser/LinkedByteArrayOutputStream.java
(1 hunks)src/main/java/org/joda/beans/ser/bin/JodaBeanBinWriter.java
(2 hunks)src/test/java/org/joda/beans/ser/TestLinkedByteArrayOutputStream.java
(1 hunks)src/test/java/org/joda/beans/ser/bin/TestBinPerformance.java
(1 hunks)src/test/java/org/joda/beans/ser/json/TestJsonPerformance.java
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- src/main/java/org/joda/beans/ser/LinkedByteArrayOutputStream.java
🚧 Files skipped from review as they are similar to previous changes (4)
- src/test/java/org/joda/beans/ser/bin/TestBinPerformance.java
- src/test/java/org/joda/beans/ser/json/TestJsonPerformance.java
- src/main/java/org/joda/beans/ser/bin/JodaBeanBinWriter.java
- src/test/java/org/joda/beans/ser/TestLinkedByteArrayOutputStream.java
Summary by CodeRabbit
Release Notes
New Features
LinkedByteArrayOutputStream
for more efficient byte array handling.Performance Improvements
Testing
LinkedByteArrayOutputStream
.Compatibility Notes