Skip to content

fix: JanusGraph property cardinality and hierarchy serialization fixes#1197

Merged
pallakartheekreddy merged 6 commits intodevelopfrom
janus-cardinality
Mar 11, 2026
Merged

fix: JanusGraph property cardinality and hierarchy serialization fixes#1197
pallakartheekreddy merged 6 commits intodevelopfrom
janus-cardinality

Conversation

@aimansharief
Copy link
Collaborator

  • Enforces VertexProperty.Cardinality.single to prevent property accumulation in JanusGraph.
  • Fixes childNodes serialization corruption in HierarchyManager by using .asJava.

Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.

Type of change

Please choose appropriate options.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How Has This Been Tested?

Please describe the tests that you ran to verify your changes in the below checkboxes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration

  • Ran Test A
  • Ran Test B

Test Configuration:

  • Software versions: Java 11, scala-2.12, play-2.7.2
  • Hardware versions: 2 CPU/ 4GB RAM

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

- Enforces VertexProperty.Cardinality.single to prevent property accumulation in JanusGraph.
- Fixes childNodes serialization corruption in HierarchyManager by using .asJava.
@coderabbitai
Copy link

coderabbitai bot commented Feb 27, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1ddec7f4-1b48-45b6-b21f-c7f6585af358

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch janus-cardinality

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

SonarCloud Analysis Results 🔍

Quality Gate Results for Services:

Please review the analysis results for each service. Ensure all quality gates are passing before merging.

1 similar comment
@github-actions
Copy link

SonarCloud Analysis Results 🔍

Quality Gate Results for Services:

Please review the analysis results for each service. Ensure all quality gates are passing before merging.

@github-actions
Copy link

github-actions bot commented Mar 2, 2026

SonarCloud Analysis Results 🔍

Quality Gate Results for Services:

Please review the analysis results for each service. Ensure all quality gates are passing before merging.

@github-actions
Copy link

github-actions bot commented Mar 5, 2026

SonarCloud Analysis Results 🔍

Quality Gate Results for Services:

Please review the analysis results for each service. Ensure all quality gates are passing before merging.

Copy link
Collaborator

@pallakartheekreddy pallakartheekreddy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

This PR correctly identifies and addresses two real bugs from the Neo4j → JanusGraph migration. The core approach (using VertexProperty.Cardinality.single) is the right fix. However, there are a few issues that should be addressed before merging.


Critical: removeProps semantics silently broken

File: NodeAsyncOperations.javasetPrimitiveData (last line of the method)

result.put(key, value != null ? value : "");

When a caller sets a metadata value to null to signal property deletion (via removeProps), setPrimitiveData converts it to "" before the value ever reaches upsertNode's property loop. The loop then:

  1. Drops existing vertex properties for the key ✓
  2. Skips writing when value == null — but value is now """\ not null` ✗
  3. Writes "" back to JanusGraph instead of deleting the property

DefinitionNode.scala:129 sets dbNode.getMetadata.put(prop, null) to request deletion. After this PR, those properties get written as empty strings instead of being removed — a silent data regression.

Fix: Don't replace null with "". Let null propagate as null into result so the if (value == null) continue in upsertNode correctly skips writing (and therefore leaves the explicit pre-delete as a deletion):

result.put(key, value);  // keep null as null

Major: finally block inconsistency across methods

upsertNode was correctly upgraded to use try/finally for transaction cleanup. However addNode, upsertRootNode, and updateNodes still use the old pattern:

// Old pattern (still in addNode, upsertRootNode, updateNodes):
} catch (Exception e) {
    if (null != tx)
        tx.rollback();

If an exception is thrown inside the catch block, transactions leak. Please apply the same finally pattern consistently:

} finally {
    if (null != tx && tx.isOpen()) {
        try { tx.rollback(); } catch (Exception ex) { ... }
    }
}

Major: getNodeWithoutRelations — ClassCastException risk on migrated nodes

The new accumulation logic in JanusGraphNodeUtil (building List<Object> when duplicate property keys exist in JanusGraph) is a sensible backward-compatibility measure for nodes corrupted before this fix. However:

  1. Callers doing (String) node.getMetadata().get("status") will throw ClassCastException on any node that has accumulated duplicate values.
  2. Since new writes now use Cardinality.single (dropping existing before write), this code path only fires for pre-migration corrupted nodes. Please add a comment making this explicit and indicating a cleanup timeline.
  3. The unchecked cast (List<Object>) existing on the accumulation line will produce a compiler warning. Add @SuppressWarnings("unchecked") or restructure to avoid it.

Minor: Object[] case in setPrimitiveData misses primitive arrays

} else if (value instanceof Object[]) {
    value = JsonUtils.serialize(Arrays.asList((Object[]) value));
}

int[], long[], boolean[] are NOT Object[] — they'll pass through unchanged as raw primitive arrays that JanusGraph cannot store. Not a problem for current usage, but worth a comment or explicit handling.


Minor: Removed named catch around tx.commit() reduces debuggability

The old code had explicit telemetry on commit failure (optimistic locking conflicts, constraint violations). The new plain tx.commit() falls through to the generic catch, making these failures harder to diagnose in production logs. Consider restoring the named catch just for commit:

try { tx.commit(); } catch (Exception commitEx) {
    TelemetryManager.error("Commit failed for " + identifier + ": " + commitEx.getMessage(), commitEx);
    throw commitEx;
}

Minor: No regression test for the core cardinality fix

The test suite wasn't extended with a test that upserts the same node twice and asserts the field has exactly one value. This is the direct regression test for the main bug — without it, property accumulation could silently return in a future refactor.


Minor: PR checklist and stack version in description

The PR description checklist is entirely unchecked, and the test configuration lists scala-2.12, play-2.7.2. This project uses Scala 2.13 / Play Framework 3.0.5. Please update the description to confirm the correct stack was tested.


Positive Notes

  • Using Cardinality.single is the correct fix for JanusGraph's default list cardinality behavior.
  • The explicit pre-delete loop before writing (it.next().remove()) is a good belt-and-suspenders measure.
  • Refactoring setPrimitiveData from stream + peek to an explicit loop is a correctness improvement (peek for mutation is an anti-pattern).
  • The finally block in upsertNode is an improvement.
  • TestHierarchyManagerSerialization is a good regression test for the hierarchy read path.
  • Error messages now include e.getMessage() for better debuggability.

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
0.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@sonarqubecloud
Copy link

@github-actions
Copy link

SonarCloud Analysis Results 🔍

Quality Gate Results for Services:

Please review the analysis results for each service. Ensure all quality gates are passing before merging.

@pallakartheekreddy pallakartheekreddy merged commit 1a0200f into develop Mar 11, 2026
14 checks passed
@pallakartheekreddy pallakartheekreddy deleted the janus-cardinality branch March 11, 2026 10:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants