-
Notifications
You must be signed in to change notification settings - Fork 557
perf(core): StringId hold bytes to avoid decode/encode #2862
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
base: master
Are you sure you want to change the base?
Conversation
Change-Id: I1ff93a2ee31f142fb7ab5cfe0e038ef2da2f982d
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #2862 +/- ##
============================================
+ Coverage 40.91% 41.00% +0.09%
Complexity 333 333
============================================
Files 747 747
Lines 60168 60189 +21
Branches 7683 7692 +9
============================================
+ Hits 24615 24679 +64
+ Misses 32975 32923 -52
- Partials 2578 2587 +9 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
@@ -128,14 +129,19 @@ public static int compareType(Id id1, Id id2) { | |||
public static class StringId implements Id { | |||
|
|||
protected String id; | |||
protected byte[] bytes; |
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.
Thread Safety Concern: The lazy initialization pattern used here is not thread-safe. If multiple threads access the same StringId instance simultaneously, race conditions could occur during the lazy initialization of id
and bytes
fields. Consider using volatile fields or synchronization to ensure thread safety.
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.
At present, I haven't found any scenarios where this would cause problems. It's safe even if multiple assignments occur at the same time.
@@ -128,14 +129,19 @@ public static int compareType(Id id1, Id id2) { | |||
public static class StringId implements Id { | |||
|
|||
protected String id; | |||
protected byte[] bytes; | |||
|
|||
public StringId(String id) { |
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.
Inconsistent State Risk: The constructor initializes bytes = null
explicitly, but the state where both id
and bytes
are null is not handled. Consider adding validation to ensure at least one field is non-null, or document the invariant that exactly one field should be null at any time.
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.
id is null is not allowed in this constructor
if (this.id != null) { | ||
return this.id.compareTo(other.asString()); | ||
} else { | ||
return Bytes.compare(this.bytes, other.asBytes()); |
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.
Performance Optimization: Consider using Arrays.equals()
instead of Bytes.equals()
for byte array comparison if Bytes.equals()
is just a wrapper. Also, cache the result of other.asBytes()
to avoid multiple conversions in the comparison.
StringId other = (StringId) obj; | ||
if (this.id != null) { | ||
return this.id.equals(other.asString()); | ||
} else { |
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.
Potential Memory Leak: In the equals method, calling other.asBytes()
when this.id != null
may trigger unnecessary byte array creation and caching in the other object. Consider checking if the other object has the same representation type first to avoid forced conversions.
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.
done
@@ -128,14 +129,19 @@ public static int compareType(Id id1, Id id2) { | |||
public static class StringId implements Id { |
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.
Missing Test Coverage: This performance optimization changes core behavior of StringId. Please ensure comprehensive test coverage including:\n- Thread safety tests with concurrent access\n- Edge cases with empty/null inputs\n- Performance regression tests\n- Memory usage validation tests
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.
Pull Request Overview
This PR optimizes the StringId class to hold both string and byte representations to avoid unnecessary decode/encode operations. The change improves performance by lazily initializing either the string or byte representation depending on how the StringId is constructed, eliminating redundant conversions.
Key changes:
- Added byte array field to StringId to store raw bytes alongside string representation
- Modified constructors to initialize only one representation (string or bytes) depending on input
- Updated methods to lazily decode/encode only when needed
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
File | Description |
---|---|
IdGenerator.java | Added bytes field to StringId class and implemented lazy encoding/decoding logic |
StringIdOffHeap.java | Added cleanup of bytes field in memory release method |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
if (this.bytes == null) { | ||
this.bytes = StringEncoding.encode(this.id); | ||
} | ||
return this.bytes; |
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.
Returning the internal byte array directly allows external modification of the StringId's state. Consider returning a defensive copy with return this.bytes.clone();
to maintain immutability.
return this.bytes; | |
return this.bytes.clone(); |
Copilot uses AI. Check for mistakes.
return this.id.compareTo(other.asString()); | ||
} else { | ||
return Bytes.compare(this.bytes, other.asBytes()); |
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.
This optimization to avoid string conversion during comparison may not be effective since other.asBytes()
will still trigger encoding if the other StringId only has a string representation. Consider checking if both objects have bytes available before using byte comparison.
Copilot uses AI. Check for mistakes.
return false; | ||
} | ||
return this.id.equals(((StringId) other).id); | ||
StringId other = (StringId) obj; | ||
if (this.id != null) { |
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.
Similar to the compareTo method, this optimization may not be effective since other.asString()
and other.asBytes()
will trigger conversions if the other StringId doesn't have the required representation. Consider optimizing for cases where both objects have the same representation type.
Copilot uses AI. Check for mistakes.
@@ -70,6 +70,7 @@ public void serializeSelfToByteBuf(MemoryPool memoryPool) { | |||
@Override | |||
public void releaseOriginalVarsOnHeap() { | |||
this.id = null; | |||
this.bytes = null; |
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.
in serializeSelfToByteBuf we can set stringBytes = this.bytes if this.bytes != null
@@ -128,14 +129,19 @@ public static int compareType(Id id1, Id id2) { | |||
public static class StringId implements Id { | |||
|
|||
protected String id; | |||
protected byte[] bytes; |
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.
At present, I haven't found any scenarios where this would cause problems. It's safe even if multiple assignments occur at the same time.
@@ -128,14 +129,19 @@ public static int compareType(Id id1, Id id2) { | |||
public static class StringId implements Id { | |||
|
|||
protected String id; | |||
protected byte[] bytes; | |||
|
|||
public StringId(String id) { |
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.
id is null is not allowed in this constructor
Change-Id: I436858dbad61ecc2e83861b05a6620a46b6df245
We can avoid the decode of temporary IDs now. Temporary IDs are not ultimately returned to the user and do not require JSON serialization, for example, the intermediate vertex ids of the adjacent edge query.
Once binary serialization is supported, we can also directly return bytes serialization to the user.
Change-Id: I1ff93a2ee31f142fb7ab5cfe0e038ef2da2f982d