32
32
33
33
import java .util .ArrayList ;
34
34
import java .util .List ;
35
+ import java .util .concurrent .locks .Lock ;
36
+ import java .util .concurrent .locks .ReentrantLock ;
35
37
import java .util .stream .Collectors ;
36
38
37
39
import static org .neo4j .gds .utils .StringFormatting .formatWithLocale ;
@@ -42,6 +44,7 @@ public final class RelationshipIds extends CypherGraphStore.StateVisitor.Adapter
42
44
private final TokenHolders tokenHolders ;
43
45
private final List <RelationshipIdContext > relationshipIdContexts ;
44
46
private final List <UpdateListener > updateListeners ;
47
+ private final Lock lock ;
45
48
46
49
public interface UpdateListener {
47
50
void onRelationshipIdsAdded (RelationshipIdContext relationshipIdContext );
@@ -62,6 +65,7 @@ private RelationshipIds(GraphStore graphStore, TokenHolders tokenHolders, List<R
62
65
this .tokenHolders = tokenHolders ;
63
66
this .relationshipIdContexts = relationshipIdContexts ;
64
67
this .updateListeners = new ArrayList <>();
68
+ this .lock = new ReentrantLock ();
65
69
}
66
70
67
71
public <T > T resolveRelationshipId (long relationshipId , ResolvedRelationshipIdFunction <T > relationshipIdConsumer ) {
@@ -93,20 +97,41 @@ public <T> T resolveRelationshipId(long relationshipId, ResolvedRelationshipIdFu
93
97
}
94
98
95
99
public void registerUpdateListener (UpdateListener updateListener ) {
96
- this .updateListeners .add (updateListener );
100
+ try {
101
+ lock .lock ();
102
+ this .updateListeners .add (updateListener );
103
+ } finally {
104
+ lock .unlock ();
105
+ }
97
106
// replay added relationship id contexts
98
107
relationshipIdContexts .forEach (updateListener ::onRelationshipIdsAdded );
99
108
}
100
109
101
110
public void removeUpdateListener (UpdateListener updateListener ) {
102
- this .updateListeners .remove (updateListener );
111
+ // This is potentially called in parallel by the Cypher runtime
112
+ // and while we are adding new relationship types.
113
+ try {
114
+ lock .lock ();
115
+ this .updateListeners .remove (updateListener );
116
+ } finally {
117
+ lock .unlock ();
118
+ }
103
119
}
104
120
105
121
@ Override
106
122
public void relationshipTypeAdded (String relationshipType ) {
107
- var relationshipIdContext = relationshipIdContextFromRelType (graphStore , tokenHolders , RelationshipType .of (relationshipType ));
123
+ var relationshipIdContext = relationshipIdContextFromRelType (
124
+ graphStore ,
125
+ tokenHolders ,
126
+ RelationshipType .of (relationshipType )
127
+ );
108
128
relationshipIdContexts .add (relationshipIdContext );
109
- updateListeners .forEach (updateListener -> updateListener .onRelationshipIdsAdded (relationshipIdContext ));
129
+ try {
130
+ lock .lock ();
131
+ updateListeners .forEach (updateListener -> updateListener .onRelationshipIdsAdded (relationshipIdContext ));
132
+ } finally {
133
+ lock .unlock ();
134
+ }
110
135
}
111
136
112
137
@ NotNull
0 commit comments