Skip to content

Commit 6382924

Browse files
Initialize cursor caches via update listener
1 parent 8f09af7 commit 6382924

File tree

3 files changed

+112
-48
lines changed

3 files changed

+112
-48
lines changed

cypher/api/storage-engine-adapter/src/main/java/org/neo4j/gds/storageengine/InMemoryRelationshipCursor.java

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@
3535
import org.neo4j.storageengine.api.StorageRelationshipCursor;
3636
import org.neo4j.token.TokenHolders;
3737

38+
import java.util.ArrayList;
3839
import java.util.Arrays;
3940
import java.util.List;
40-
import java.util.stream.Collectors;
4141

4242
public abstract class InMemoryRelationshipCursor extends RelationshipRecord implements RelationshipVisitor<RuntimeException>, StorageRelationshipCursor {
4343

@@ -46,7 +46,7 @@ public abstract class InMemoryRelationshipCursor extends RelationshipRecord impl
4646
private final List<RelationshipIds.RelationshipIdContext> relationshipIdContexts;
4747
private final List<AdjacencyCursor> adjacencyCursorCache;
4848
private final List<PropertyCursor[]> propertyCursorCache;
49-
private final MutableDoubleList propertyValuesCache;
49+
private MutableDoubleList propertyValuesCache;
5050

5151
protected long sourceId;
5252
protected long targetId;
@@ -62,21 +62,12 @@ public InMemoryRelationshipCursor(CypherGraphStore graphStore, TokenHolders toke
6262
super(NO_ID);
6363
this.graphStore = graphStore;
6464
this.tokenHolders = tokenHolders;
65-
this.relationshipIdContexts = this.graphStore.relationshipIds().relationshipIdContexts();
66-
this.adjacencyCursorCache = relationshipIdContexts.stream()
67-
.map(context -> context.adjacencyList().rawAdjacencyCursor())
68-
.collect(Collectors.toList());
69-
70-
this.propertyCursorCache = relationshipIdContexts.stream()
71-
.map(context -> Arrays
72-
.stream(context.adjacencyProperties())
73-
.map(AdjacencyProperties::rawPropertyCursor)
74-
.toArray(PropertyCursor[]::new)
75-
)
76-
.collect(Collectors.toList());
65+
this.relationshipIdContexts = new ArrayList<>();
66+
this.adjacencyCursorCache = new ArrayList<>();
67+
this.propertyCursorCache = new ArrayList<>();
68+
this.propertyValuesCache = new DoubleArrayList();
7769

78-
var maxPropertySize = propertyCursorCache.stream().mapToInt(a -> a.length).max().orElse(0);
79-
this.propertyValuesCache = new DoubleArrayList(new double[maxPropertySize]);
70+
this.graphStore.relationshipIds().registerUpdateListener(this::newRelationshipIdContextAdded);
8071
}
8172

8273
@Override
@@ -161,6 +152,19 @@ public void properties(StoragePropertyCursor propertyCursor, InMemoryPropertySel
161152
inMemoryCursor.initRelationshipPropertyCursor(this.sourceId, propertyIds, propertyValuesCache, selection);
162153
}
163154

155+
private void newRelationshipIdContextAdded(RelationshipIds.RelationshipIdContext relationshipIdContext) {
156+
this.relationshipIdContexts.add(relationshipIdContext);
157+
this.adjacencyCursorCache.add(relationshipIdContext.adjacencyList().rawAdjacencyCursor());
158+
this.propertyCursorCache.add(
159+
Arrays
160+
.stream(relationshipIdContext.adjacencyProperties())
161+
.map(AdjacencyProperties::rawPropertyCursor)
162+
.toArray(PropertyCursor[]::new)
163+
);
164+
var newSize = this.propertyCursorCache.size() + relationshipIdContext.adjacencyProperties().length;
165+
this.propertyValuesCache = new DoubleArrayList(new double[newSize]);
166+
}
167+
164168
private boolean progressToNextContext() {
165169
relationshipContextIndex++;
166170

cypher/cypher-core/src/main/java/org/neo4j/gds/core/cypher/CypherGraphStore.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,5 +107,27 @@ public interface StateVisitor {
107107
void nodeLabelAdded(String nodeLabel);
108108

109109
void relationshipTypeAdded(String relationshipType);
110+
111+
class Adapter implements StateVisitor {
112+
@Override
113+
public void nodePropertyRemoved(String propertyKey) {
114+
115+
}
116+
117+
@Override
118+
public void nodePropertyAdded(String propertyKey) {
119+
120+
}
121+
122+
@Override
123+
public void nodeLabelAdded(String nodeLabel) {
124+
125+
}
126+
127+
@Override
128+
public void relationshipTypeAdded(String relationshipType) {
129+
130+
}
131+
}
110132
}
111133
}

cypher/cypher-core/src/main/java/org/neo4j/gds/core/cypher/RelationshipIds.java

Lines changed: 70 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.neo4j.gds.core.cypher;
2121

2222
import org.immutables.value.Value;
23+
import org.jetbrains.annotations.NotNull;
2324
import org.neo4j.gds.RelationshipType;
2425
import org.neo4j.gds.annotation.ValueClass;
2526
import org.neo4j.gds.api.AdjacencyList;
@@ -37,47 +38,32 @@
3738

3839
import static org.neo4j.gds.utils.StringFormatting.formatWithLocale;
3940

40-
public final class RelationshipIds {
41+
public final class RelationshipIds extends CypherGraphStore.StateVisitor.Adapter {
4142

43+
private final GraphStore graphStore;
44+
private final TokenHolders tokenHolders;
4245
private final List<RelationshipIdContext> relationshipIdContexts;
46+
private final List<UpdateListener> updateListeners;
47+
48+
public interface UpdateListener {
49+
void onRelationshipIdsAdded(RelationshipIdContext relationshipIdContext);
50+
}
4351

4452
static RelationshipIds fromGraphStore(GraphStore graphStore, TokenHolders tokenHolders) {
4553
var relationshipIdContexts = new ArrayList<RelationshipIdContext>(graphStore.relationshipTypes().size());
4654

47-
graphStore.relationshipTypes().forEach(relType -> {
48-
var relCount = graphStore.relationshipCount(relType);
49-
var graph = (CSRGraph) graphStore.getGraph(relType);
50-
var offsets = computeAccumulatedOffsets(graph);
51-
int relTypeId = tokenHolders.relationshipTypeTokens().getIdByName(relType.name);
52-
53-
List<RelationshipProperty> relationshipProperties = graphStore.relationshipPropertyKeys(relType)
54-
.stream()
55-
.map(relProperty -> graphStore.relationshipPropertyValues(relType, relProperty))
56-
.collect(Collectors.toList());
57-
58-
int[] propertyIds = relationshipProperties
59-
.stream()
60-
.mapToInt(relationshipProperty -> tokenHolders
61-
.propertyKeyTokens()
62-
.getIdByName(relationshipProperty.key()))
63-
.toArray();
64-
65-
AdjacencyProperties[] adjacencyProperties = relationshipProperties
66-
.stream()
67-
.map(relationshipProperty -> relationshipProperty.values().propertiesList())
68-
.toArray(AdjacencyProperties[]::new);
69-
70-
relationshipIdContexts.add(ImmutableRelationshipIdContext.of(relType, relTypeId, relCount, graph, offsets, propertyIds, adjacencyProperties));
71-
});
72-
return new RelationshipIds(relationshipIdContexts);
55+
graphStore.relationshipTypes()
56+
.stream()
57+
.map(relType -> relationshipIdContextFromRelType(graphStore, tokenHolders, relType))
58+
.forEach(relationshipIdContexts::add);
59+
return new RelationshipIds(graphStore, tokenHolders, relationshipIdContexts);
7360
}
7461

75-
private RelationshipIds(List<RelationshipIdContext> relationshipIdContexts) {
62+
private RelationshipIds(GraphStore graphStore, TokenHolders tokenHolders, List<RelationshipIdContext> relationshipIdContexts) {
63+
this.graphStore = graphStore;
64+
this.tokenHolders = tokenHolders;
7665
this.relationshipIdContexts = relationshipIdContexts;
77-
}
78-
79-
public List<RelationshipIdContext> relationshipIdContexts() {
80-
return relationshipIdContexts;
66+
this.updateListeners = new ArrayList<>();
8167
}
8268

8369
public <T> T resolveRelationshipId(long relationshipId, ResolvedRelationshipIdFunction<T> relationshipIdConsumer) {
@@ -108,6 +94,58 @@ public <T> T resolveRelationshipId(long relationshipId, ResolvedRelationshipIdFu
10894
throw new IllegalArgumentException(formatWithLocale("No relationship with id %d was found.", relationshipId));
10995
}
11096

97+
public void registerUpdateListener(UpdateListener updateListener) {
98+
this.updateListeners.add(updateListener);
99+
// replay added relationship id contexts
100+
relationshipIdContexts.forEach(updateListener::onRelationshipIdsAdded);
101+
}
102+
103+
@Override
104+
public void relationshipTypeAdded(String relationshipType) {
105+
var relationshipIdContext = relationshipIdContextFromRelType(graphStore, tokenHolders, RelationshipType.of(relationshipType));
106+
relationshipIdContexts.add(relationshipIdContext);
107+
updateListeners.forEach(updateListener -> updateListener.onRelationshipIdsAdded(relationshipIdContext));
108+
}
109+
110+
@NotNull
111+
private static RelationshipIdContext relationshipIdContextFromRelType(
112+
GraphStore graphStore,
113+
TokenHolders tokenHolders,
114+
RelationshipType relType
115+
) {
116+
var relCount = graphStore.relationshipCount(relType);
117+
var graph = (CSRGraph) graphStore.getGraph(relType);
118+
var offsets = computeAccumulatedOffsets(graph);
119+
int relTypeId = tokenHolders.relationshipTypeTokens().getIdByName(relType.name);
120+
121+
List<RelationshipProperty> relationshipProperties = graphStore.relationshipPropertyKeys(relType)
122+
.stream()
123+
.map(relProperty -> graphStore.relationshipPropertyValues(relType, relProperty))
124+
.collect(Collectors.toList());
125+
126+
int[] propertyIds = relationshipProperties
127+
.stream()
128+
.mapToInt(relationshipProperty -> tokenHolders
129+
.propertyKeyTokens()
130+
.getIdByName(relationshipProperty.key()))
131+
.toArray();
132+
133+
AdjacencyProperties[] adjacencyProperties = relationshipProperties
134+
.stream()
135+
.map(relationshipProperty -> relationshipProperty.values().propertiesList())
136+
.toArray(AdjacencyProperties[]::new);
137+
138+
return ImmutableRelationshipIdContext.of(
139+
relType,
140+
relTypeId,
141+
relCount,
142+
graph,
143+
offsets,
144+
propertyIds,
145+
adjacencyProperties
146+
);
147+
}
148+
111149
private static HugeLongArray computeAccumulatedOffsets(Graph graph) {
112150
var offsets = HugeLongArray.newArray(graph.nodeCount());
113151

0 commit comments

Comments
 (0)