-
Notifications
You must be signed in to change notification settings - Fork 31
Introduce Temporal Graph Storage support to NativeStore #349
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
Introduce Temporal Graph Storage support to NativeStore #349
Conversation
…DELETE operations, and improve timestamp resolution for consistency
… and telemetry features
|
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 introduces comprehensive temporal graph storage support to JasminGraph's NativeStore, enabling point-in-time and time-window queries over graph evolution. The implementation adds temporal metadata tracking (creation, update, deletion timestamps and status) to both nodes and edges, integrates temporal filtering into query execution, and provides an event logging system for audit trails.
Key Changes:
- Temporal metadata tracking for nodes and edges with creation/update/deletion timestamps and status fields
- Query-time temporal filtering with AS_OF (point-in-time) and RANGE (time-window) modes
- Event logging system with JSONL-based audit trail, indexing, rotation, and compaction capabilities
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| src/util/kafka/StreamHandler.h | Adds temporal metadata resolution method declarations |
| src/util/kafka/StreamHandler.cpp | Implements operation type and timestamp extraction from Kafka messages |
| src/query/processor/cypher/runtime/OperatorExecutor.cpp | CRITICAL: Contains unresolved merge conflicts - Integrates temporal filtering into all scan operators |
| src/nativestore/temporal/TemporalQueryFilter.h | Defines temporal constraint structures and filtering API |
| src/nativestore/temporal/TemporalQueryFilter.cpp | Implements temporal visibility evaluation with epoch millisecond normalization |
| src/nativestore/temporal/TemporalEventLogger.h | Defines event logging API with indexing, rotation, and compaction |
| src/nativestore/temporal/TemporalEventLogger.cpp | Implements JSONL-based event logging system |
| src/nativestore/temporal/TemporalConstants.h | Defines temporal metadata keys and timestamp utilities |
| src/nativestore/RelationBlock.h | Adds getAllMetaProperties method declaration |
| src/nativestore/RelationBlock.cpp | CRITICAL: Memory leak in getAllMetaProperties - Implements meta properties retrieval |
| src/nativestore/NodeBlock.h | Adds getAllMetaProperties method declaration |
| src/nativestore/NodeBlock.cpp | CRITICAL: Memory leak in getAllMetaProperties - Implements meta properties retrieval |
| src/localstore/incremental/JasmineGraphIncrementalLocalStore.h | Adds temporal operation handlers and event logger integration |
| src/localstore/incremental/JasmineGraphIncrementalLocalStore.cpp | CRITICAL: Unresolved merge conflict - Implements ADD/UPDATE/DELETE operations with temporal metadata attachment |
| TEMPORAL_DATA_FLOW.md | Comprehensive documentation of temporal data flow from ingestion to querying |
| CMakeLists.txt | Adds temporal source files to build (with duplicate entries) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| delete current; | ||
| current = temp; | ||
| } | ||
| delete current; |
Copilot
AI
Dec 31, 2025
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.
Memory leak: double delete of current pointer. At line 877, 'current' is deleted after the loop, but 'current' is already either null (normal loop exit) or points to already-deleted memory (from line 874). This will cause undefined behavior. Remove line 877.
| @@ -0,0 +1,58 @@ | |||
| /** | |||
| Copyright 2024 JasmineGraph Team | |||
Copilot
AI
Dec 31, 2025
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.
Copyright year is 2024, but other files in this PR (TemporalQueryFilter.h, TemporalConstants.h) use 2025. For consistency, this should also be 2025.
| Copyright 2024 JasmineGraph Team | |
| Copyright 2025 JasmineGraph Team |
| src/nativestore/MetaPropertyLink.cpp | ||
| src/nativestore/MetaPropertyEdgeLink.cpp |
Copilot
AI
Dec 31, 2025
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.
Duplicate source file entries in CMakeLists.txt. Lines 207-208 list MetaPropertyLink.cpp and MetaPropertyEdgeLink.cpp, and they are duplicated again at lines 211-212. This duplication should be removed to clean up the build configuration.
| src/nativestore/MetaPropertyLink.cpp | |
| src/nativestore/MetaPropertyEdgeLink.cpp |
| if (edgeJson.contains("operationTimestamp") && edgeJson["operationTimestamp"].is_string()) { | ||
| return edgeJson["operationTimestamp"].get<std::string>(); | ||
| } | ||
| if (edgeJson.contains("timestamp") && edgeJson["timestamp"].is_string()) { | ||
| return edgeJson["timestamp"].get<std::string>(); |
Copilot
AI
Dec 31, 2025
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.
The resolveOperationTimestamp function only accepts string timestamps, but it should also accept numeric timestamps (as mentioned in the documentation and as implemented in JasmineGraphIncrementalLocalStore.cpp). This creates inconsistency in timestamp handling. The function should check for both is_string() and is_number() types and convert numeric values to strings.
| if (edgeJson.contains("operationTimestamp") && edgeJson["operationTimestamp"].is_string()) { | |
| return edgeJson["operationTimestamp"].get<std::string>(); | |
| } | |
| if (edgeJson.contains("timestamp") && edgeJson["timestamp"].is_string()) { | |
| return edgeJson["timestamp"].get<std::string>(); | |
| if (edgeJson.contains("operationTimestamp")) { | |
| const auto &opTs = edgeJson["operationTimestamp"]; | |
| if (opTs.is_string()) { | |
| return opTs.get<std::string>(); | |
| } | |
| if (opTs.is_number_integer() || opTs.is_number_unsigned()) { | |
| return std::to_string(opTs.get<long long>()); | |
| } | |
| if (opTs.is_number_float()) { | |
| return std::to_string(opTs.get<double>()); | |
| } | |
| } | |
| if (edgeJson.contains("timestamp")) { | |
| const auto &ts = edgeJson["timestamp"]; | |
| if (ts.is_string()) { | |
| return ts.get<std::string>(); | |
| } | |
| if (ts.is_number_integer() || ts.is_number_unsigned()) { | |
| return std::to_string(ts.get<long long>()); | |
| } | |
| if (ts.is_number_float()) { | |
| return std::to_string(ts.get<double>()); | |
| } |
| <<<<<<< HEAD | ||
| TemporalConstraints temporalConstraints = TemporalQueryFilter::fromJson(query); | ||
| ======= | ||
| OpenTelemetryUtil::addSpanAttribute("relationship.type", query["relType"].get<std::string>()); | ||
|
|
||
| >>>>>>> master |
Copilot
AI
Dec 31, 2025
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.
Merge conflict markers present in UndirectedRelationshipTypeScan function. The conflict shows both HEAD (temporal constraints) and master (telemetry attribute) code. Both pieces of code should likely be kept, but the merge conflict markers need to be resolved.
| <<<<<<< HEAD | |
| TemporalConstraints temporalConstraints = TemporalQueryFilter::fromJson(query); | |
| ======= | |
| OpenTelemetryUtil::addSpanAttribute("relationship.type", query["relType"].get<std::string>()); | |
| >>>>>>> master | |
| TemporalConstraints temporalConstraints = TemporalQueryFilter::fromJson(query); | |
| OpenTelemetryUtil::addSpanAttribute("relationship.type", query["relType"].get<std::string>()); |
| delete current; | ||
| current = temp; | ||
| } | ||
| delete current; |
Copilot
AI
Dec 31, 2025
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.
Memory leak: double delete of current pointer. At line 440, 'current' is deleted after the loop, but 'current' is already either null (normal loop exit) or points to already-deleted memory (from line 437). This will cause undefined behavior. Remove line 440.
| @@ -0,0 +1,244 @@ | |||
| /** | |||
| Copyright 2024 JasmineGraph Team | |||
Copilot
AI
Dec 31, 2025
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.
Copyright year is 2024, but other files in this PR (TemporalQueryFilter.cpp, TemporalConstants.h) use 2025. For consistency, this should also be 2025.
| Copyright 2024 JasmineGraph Team | |
| Copyright 2025 JasmineGraph Team |
| // Try direct conversion first (for epoch milliseconds) | ||
| try { | ||
| long long value = std::stoll(timestamp); | ||
| // If value is reasonable epoch millis (between 2000 and 2100), use it | ||
| if (value > 946684800000LL && value < 4102444800000LL) { | ||
| return value; | ||
| } | ||
| } catch (...) { | ||
| // Fall through to cleaned version | ||
| } | ||
|
|
Copilot
AI
Dec 31, 2025
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 bug in timestamp normalization: if the direct conversion at line 177 succeeds but the value is outside the reasonable range (not between 2000-2100), the function falls through to clean and parse again. However, if the original timestamp was a valid numeric string outside this range (e.g., "100" for a relative timestamp), it will be parsed twice with potentially different results. Consider either returning kNegativeInfinity for out-of-range values or logging a warning about unexpected timestamp ranges.
| // Try direct conversion first (for epoch milliseconds) | |
| try { | |
| long long value = std::stoll(timestamp); | |
| // If value is reasonable epoch millis (between 2000 and 2100), use it | |
| if (value > 946684800000LL && value < 4102444800000LL) { | |
| return value; | |
| } | |
| } catch (...) { | |
| // Fall through to cleaned version | |
| } | |
| // Try direct conversion first (for epoch milliseconds or numeric relative timestamps) | |
| try { | |
| long long value = std::stoll(timestamp); | |
| // If value is reasonable epoch millis (between 2000 and 2100), use it directly | |
| if (value > 946684800000LL && value < 4102444800000LL) { | |
| return value; | |
| } | |
| // For other numeric values (e.g., relative timestamps), return the parsed value as-is | |
| return value; | |
| } catch (...) { | |
| // Fall through to cleaned version for legacy/non-numeric formats | |
| } |
| static std::pair<std::string, unsigned int> getIDs(std::string edgeString); | ||
| JasmineGraphIncrementalLocalStore(unsigned int graphID = 0, unsigned int partitionID = 0, | ||
| std::string openMode = "trunk", bool embedNode = false); | ||
| ~JasmineGraphIncrementalLocalStore() { delete nm; } |
Copilot
AI
Dec 31, 2025
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.
Incomplete destructor: the destructor only deletes 'nm' but doesn't clean up other dynamically allocated resources. The 'embedding_requests' vector pointer is allocated in the constructor but never freed. If 'embedNode' is true, 'faissStore' and 'textEmbedder' are also allocated but not freed. This causes memory leaks. The destructor should delete all dynamically allocated resources.


No description provided.