Change NitriteId to use `long` internally to avoid parseLong overhead by leoger · Pull Request #1117 · nitrite/nitrite-java

nitrite/src/main/java/org/dizitart/no2/transaction/TransactionalRTree.java (3)

29-30: Simplified null check after switching to primitive long.

The code now only checks if nitriteId is null without checking nitriteId.getIdValue(). This simplification is appropriate since the PR changes NitriteId to use a primitive long internally instead of a String, and primitive types cannot be null.


37-38: Simplified null check in remove method.

Similar to the add method, the code now only checks if nitriteId is null without checking nitriteId.getIdValue(). This change is consistent with using primitive long for the ID value.


102-108: Method signature works well with the new ID representation.

The getKey method already accepts a long parameter, which aligns perfectly with the change to use long internally for NitriteId. This method doesn't require any changes as it was already designed to work with primitive long values.

nitrite-rocksdb-adapter/src/main/java/org/dizitart/no2/rocksdb/RocksDBRTree.java (5)

47-53: Code simplification looks good.

The modification simplifies the check by directly using nitriteId.getIdValue() without checking if the ID value is null. This change is consistent with the PR objective of changing NitriteId to use long internally instead of String, which eliminates the need for null checks on the ID value.


55-62: Consistent simplification in remove method.

Similar to the add method, this change simplifies the code by removing unnecessary null checks on the ID value. The modification maintains consistency across both methods and aligns with the PR's goal of improving performance by reducing overhead.


86-88: Consistent string conversion pattern.

Similar to the findIntersectingKeys method, this code correctly maintains compatibility by converting the long ID back to a string when creating NitriteId objects. This approach ensures consistency throughout the codebase.


118-124: Method already accepts long parameter.

The getKey method was already designed to accept a long ID parameter, which makes it compatible with the change in NitriteId implementation. No modifications were needed for this method, confirming good design foresight.


71-73:

Details ✅ Verification successful

Verify ID conversion for compatibility.

While not changed in this PR, notice that line 72 still converts the spatial key's ID to a string when creating a NitriteId (NitriteId.createId(Long.toString(sk.getId()))). This is important for maintaining backward compatibility with code that expects string IDs, but should be validated to ensure it works properly with the changed NitriteId implementation.


🏁 Script executed:

#!/bin/bash
# Description: Check how NitriteId.createId is defined to verify it handles the string conversion correctly

# Look for NitriteId creation methods
ast-grep --pattern $'class NitriteId {
  $$$
  static NitriteId createId($_) {
    $$$
  }
  $$$
}'

# Check for any usage patterns of createId with string arguments
rg -A 3 "NitriteId.createId\\(.*toString\\(" --type java

Length of output: 4087


ID Conversion Verified for Backward Compatibility

  • The usage of Long.toString(sk.getId()) as an argument to NitriteId.createId() in the RocksDB adapter is consistent with patterns found in other modules (e.g., MVStore and in-memory adapters), ensuring compatibility with string-based IDs.
  • Unit tests (e.g., in NitriteIdTest.java) further validate that passing a string correctly upholds the expected behavior of the NitriteId implementation.
  • No changes are required based on the current verification.
nitrite/src/main/java/org/dizitart/no2/store/memory/InMemoryRTree.java (3)

42-43: Appropriate simplification of the null check logic.

The change simplifies the condition by removing redundant checks. Since NitriteId now uses long internally instead of String, the additional validation for getIdValue() is no longer necessary as it will always return a valid primitive long value.


51-52: Appropriate simplification in the remove method.

Similar to the changes in the add method, this simplification is consistent with the refactoring of NitriteId to use a primitive long type internally instead of a String.


60-60: Consistent usage of long value in spatial key creation.

The use of 0L as the ID parameter when creating spatial keys for search operations is consistent with the updated type system. This maintains the existing logic while adapting to the new internal representation.

Also applies to: 75-75

nitrite/src/test/java/org/dizitart/no2/filters/FilterTest.java (1)

28-28: Type change consistent with NitriteId implementation update.

The test assertion has been updated to check for Long type instead of String, aligning with the PR objective to change NitriteId to use long internally instead of String.

This change correctly validates the implementation change while ensuring test consistency.

nitrite/src/test/java/org/dizitart/no2/collection/NitriteIdTest.java (1)

63-63: Updated assertion to match new internal type representation.

This test has been updated to verify that NitriteId.createId("42").getIdValue() now returns a long value (42L) rather than a string. This correctly reflects the internal type change from String to long.

The updated assertion properly validates the converted implementation while maintaining test coverage.

nitrite-rocksdb-adapter/src/main/java/org/dizitart/no2/rocksdb/formatter/NitriteSerializers.java (1)

37-37: Preserves backward compatibility with existing database files.

The serializer now explicitly converts the long value to a string before writing, maintaining the serialized format while allowing the internal representation to change to long.

This approach is excellent because:

  1. It maintains backward compatibility with existing database files
  2. It supports the PR's objective of reducing parseLong overhead in normal operations
  3. It only incurs the toString conversion cost during serialization, which happens less frequently than normal operations
nitrite/src/test/java/org/dizitart/no2/collection/NitriteDocumentTest.java (1)

59-60: Test updated to use long representation for NitriteId.

Both the document initialization and the assertion have been updated to use long values instead of strings, aligning with the internal type change in NitriteId.

The test now correctly uses the proper type (long) for the _id field and verifies the expected value type from getId().getIdValue(). This is consistent with the PR's objective.

nitrite/src/main/java/org/dizitart/no2/collection/operation/ReadOperations.java (1)

138-138:

Details ❓ Verification inconclusive

Type change for NitriteId values to improve performance

This change implements the core PR objective of using long values for NitriteId instead of String, which helps avoid the overhead of parseLong operations. The code now casts the value from the filter directly to long instead of String.

Let's verify that this cast is safe by examining the byIdFilter implementation:


🏁 Script executed:

#!/bin/bash
# Examine the ByIdFilter implementation to confirm it returns long values

# Find the ByIdFilter class
rg -A 10 "class .*ByIdFilter" --type java
# Check what getValue() returns
ast-grep --pattern 'class $_ implements $_ {
  $$$
  public $_ getValue() {
    $$$
  }
  $$$
}'

Length of output: 142


Manual Verification Required: Confirm ByIdFilter.getValue() Returns a Long

The change to cast the filter value directly to long should boost performance as expected, but the automated check did not return evidence regarding the return type of ByIdFilter.getValue(). Please verify manually that this method indeed returns a long (or a value safely castable to long) by checking its implementation in the ByIdFilter class (for example, in a file like nitrite/src/main/java/org/dizitart/no2/collection/filters/ByIdFilter.java).

  • Action Item: Inspect the ByIdFilter class to confirm that the getValue() method returns a long value.
  • Impact: Ensure the cast in ReadOperations.java at line 138 is valid. If the value is not a long, adjust the casting logic to maintain type safety.
nitrite-jackson-mapper/src/main/java/org/dizitart/no2/mapper/jackson/modules/NitriteIdSerializer.java (1)

38-38:

Details ✅ Verification successful

Simplified serialization of NitriteId with long values

The serializer has been improved by removing null checks that were no longer needed, simplifying the code to directly convert the long ID value to string. This is a clean change that aligns with the PR objectives.

Let's verify that this simplification is safe by examining the NitriteId implementation:


🏁 Script executed:

#!/bin/bash
# Find NitriteId to confirm getIdValue() cannot return null
rg -A 3 "getIdValue\(\)" --type java

Length of output: 13901


Simplification Verified: NitriteId Serialization is Safe

The null check removal is safe since getIdValue() consistently returns a primitive long, which cannot be null. Our grep across the codebase confirms that all usages simply convert this long value to a string without any need for additional null handling.

  • File: nitrite-jackson-mapper/src/main/java/org/dizitart/no2/mapper/jackson/modules/NitriteIdSerializer.java (Line 38)
  • Summary: The simplification directly converts the long ID to a string with Long.toString(value.getIdValue()), aligning with the rest of the codebase where getIdValue() is always a primitive long.
nitrite-mvstore-adapter/src/main/java/org/dizitart/no2/mvstore/NitriteMVRTreeMap.java (2)

46-48: Simplified null check pattern for NitriteId

The null check for nitriteId.getIdValue() has been removed since it's now guaranteed to have a value when nitriteId itself is not null. This makes the code cleaner and more maintainable.


59-61: Simplified null check pattern for NitriteId

Similar to the previous change, the redundant null check has been removed here as well, maintaining consistency throughout the codebase.

nitrite/src/main/java/org/dizitart/no2/collection/NitriteDocument.java (2)

106-107: Changed ID type from String to long

The document ID is now stored as a long value instead of a String, which aligns with the PR objective to improve performance by avoiding string parsing.


115-117: Robust ID retrieval with type cast

The code now attempts to cast the retrieved ID directly to long while also saving the original value. This allows for a fallback mechanism in case the cast fails, enhancing the robustness of the code.

nitrite/src/main/java/org/dizitart/no2/collection/NitriteId.java (10)

50-51: The field type change aligns with performance objective.

Changing from String to long for the idValue field effectively eliminates string parsing overhead, which aligns with the PR's goal of improving performance. This primitive type change is more efficient for operations like comparison and reduces memory consumption.


54-54: Direct primitive assignment effectively reduces overhead.

Using the primitive value directly (generator.getId()) rather than converting it to a String first eliminates unnecessary string creation and parsing operations.


57-59: String constructor appropriately handles conversion to the new type.

The constructor now correctly parses the string input to a long value, maintaining compatibility with code that creates IDs from strings while storing them as longs internally.


61-63: New constructor enhances API usability.

Adding a constructor that directly accepts a long value is a good addition that complements the internal representation change and provides a more direct way to create IDs from numeric values.


87-96: New static factory method provides a more efficient creation path.

The createId(long value) method is a valuable addition that provides a more efficient way to create IDs when the caller already has a numeric identifier. This avoids unnecessary string conversion overhead.


120-120: Simplified comparison logic enhances performance.

Using Long.compare directly on the primitive values is more efficient than the previous string comparison. This change should improve sorting and equality checks performance.


125-125: More efficient string representation.

Removing any null checks and directly creating the string representation from the primitive long value simplifies the code and improves performance.


129-129: Serialization maintains backward compatibility.

Converting the long value to a string during serialization ensures backward compatibility with existing database files and other systems that expect string identifiers.


133-133: Deserialization properly restores the primitive type.

The readObject method correctly parses the string from the input stream back to a long value, ensuring proper reconstitution of the object during deserialization.


94-94:

Details ✅ Verification successful

Verify that validId implementation properly handles long values.

The code calls validId(value) for the long parameter, but the implementation shown at line 106 only explicitly validates string representations. Ensure there's a corresponding implementation for validating long values directly.


🏁 Script executed:

#!/bin/bash
# Search for an overloaded validId method that accepts a long parameter
rg -A 5 "validId\(long" --type java

Length of output: 37


I'll run a more general search in the NitriteId.java file to list all occurrences of validId( along with their context, so that we can verify if there's an overloaded implementation handling long values.


🏁 Script executed:

#!/bin/bash
# List all occurrences of "validId(" in NitriteId.java with context to verify its overloads.
rg -C 5 "validId\\s*\\(" nitrite/src/main/java/org/dizitart/no2/collection/NitriteId.java

Length of output: 1031


ValidId Method: Long Value Handling Confirmed
The current implementation uses a single validId(Object value) method to validate identifiers for both string and long inputs. In the createId(long) method, the long value is autoboxed and passed to validId, where its conversion to a string followed by Long.parseLong effectively validates it as a 64-bit integer.

  • Observation: No separate overload for long values exists, but this design is intentional and functionally correct.
  • Recommendation: If clarity or performance improvements are desired, consider adding an explicit validId(long value) overload and document its behavior; otherwise, the current approach is acceptable.