20
20
package org .neo4j .gds .beta .pregel ;
21
21
22
22
import org .neo4j .gds .api .Graph ;
23
+ import org .neo4j .gds .collections .ha .HugeLongArray ;
23
24
import org .neo4j .gds .collections .haa .HugeAtomicDoubleArray ;
24
25
import org .neo4j .gds .core .concurrency .ParallelUtil ;
25
- import org .neo4j .gds .termination . TerminationFlag ;
26
+ import org .neo4j .gds .core . utils . paged . ParallelDoublePageCreator ;
26
27
import org .neo4j .gds .mem .MemoryEstimation ;
27
28
import org .neo4j .gds .mem .MemoryEstimations ;
28
- import org .neo4j .gds .core .utils .paged .ParallelDoublePageCreator ;
29
+ import org .neo4j .gds .termination .TerminationFlag ;
30
+
31
+ import java .util .OptionalLong ;
29
32
30
33
/**
31
34
* A messenger implementation that is backed by two double arrays used
32
35
* to send and receive messages. The messenger can only be applied in
33
36
* combination with a {@link Reducer}
34
37
* which atomically reduces all incoming messages into a single one.
35
38
*/
36
- public class ReducingMessenger implements Messenger <ReducingMessenger .SingleMessageIterator > {
39
+ class ReducingMessenger implements Messenger <ReducingMessenger .SingleMessageIterator > {
37
40
38
41
private final Graph graph ;
39
42
private final PregelConfig config ;
40
- private final Reducer reducer ;
43
+ final Reducer reducer ;
41
44
42
- private HugeAtomicDoubleArray sendArray ;
43
- private HugeAtomicDoubleArray receiveArray ;
45
+ HugeAtomicDoubleArray sendArray ;
46
+ HugeAtomicDoubleArray receiveArray ;
44
47
45
- ReducingMessenger (Graph graph , PregelConfig config , Reducer reducer ) {
46
- assert !Double .isNaN (reducer .identity ()): "identity element must not be NaN" ;
48
+ static ReducingMessenger create (Graph graph , PregelConfig config , Reducer reducer ) {
49
+ return config .trackSender ()
50
+ ? new WithSender (graph , config , reducer )
51
+ : new ReducingMessenger (graph , config , reducer );
52
+ }
53
+
54
+ private ReducingMessenger (Graph graph , PregelConfig config , Reducer reducer ) {
55
+ assert !Double .isNaN (reducer .identity ()) : "identity element must not be NaN" ;
47
56
48
57
this .graph = graph ;
49
58
this .config = config ;
50
59
this .reducer = reducer ;
51
60
52
- this .receiveArray = HugeAtomicDoubleArray .of (graph .nodeCount (), ParallelDoublePageCreator .passThrough (config .concurrency ()));
53
- this .sendArray = HugeAtomicDoubleArray .of (graph .nodeCount (), ParallelDoublePageCreator .passThrough (config .concurrency ()));
61
+ this .receiveArray = HugeAtomicDoubleArray .of (
62
+ graph .nodeCount (),
63
+ ParallelDoublePageCreator .passThrough (config .concurrency ())
64
+ );
65
+ this .sendArray = HugeAtomicDoubleArray .of (
66
+ graph .nodeCount (),
67
+ ParallelDoublePageCreator .passThrough (config .concurrency ())
68
+ );
54
69
}
55
70
56
- static MemoryEstimation memoryEstimation () {
57
- return MemoryEstimations .builder (ReducingMessenger .class )
71
+ static MemoryEstimation memoryEstimation (boolean withSender ) {
72
+ var builder = MemoryEstimations .builder (ReducingMessenger .class )
58
73
.perNode ("send array" , HugeAtomicDoubleArray ::memoryEstimation )
59
- .perNode ("receive array" , HugeAtomicDoubleArray ::memoryEstimation )
74
+ .perNode ("receive array" , HugeAtomicDoubleArray ::memoryEstimation );
75
+
76
+ if (withSender ) {
77
+ builder
78
+ .perNode ("send sender array" , HugeLongArray ::memoryEstimation )
79
+ .perNode ("receive sender array" , HugeLongArray ::memoryEstimation );
80
+ }
81
+ return builder
60
82
.build ();
61
83
}
62
84
63
85
@ Override
64
86
public void initIteration (int iteration ) {
65
- // Swap arrays
66
87
var tmp = receiveArray ;
67
88
this .receiveArray = sendArray ;
68
89
this .sendArray = tmp ;
@@ -96,7 +117,7 @@ public void initMessageIterator(
96
117
boolean isInitialIteration
97
118
) {
98
119
var message = receiveArray .getAndReplace (nodeId , reducer .identity ());
99
- messageIterator .init (message , message != reducer .identity ());
120
+ messageIterator .init (message , message != reducer .identity (), OptionalLong . empty () );
100
121
}
101
122
102
123
@ Override
@@ -105,14 +126,73 @@ public void release() {
105
126
receiveArray .release ();
106
127
}
107
128
129
+ static class WithSender extends ReducingMessenger {
130
+ private HugeLongArray sendSenderArray ;
131
+ private HugeLongArray receiveSenderArray ;
132
+
133
+ WithSender (Graph graph , PregelConfig config , Reducer reducer ) {
134
+ super (graph , config , reducer );
135
+ this .sendSenderArray = HugeLongArray .newArray (graph .nodeCount ());
136
+ this .receiveSenderArray = HugeLongArray .newArray (graph .nodeCount ());
137
+ }
138
+
139
+ @ Override
140
+ public void initIteration (int iteration ) {
141
+ super .initIteration (iteration );
142
+ // Swap sender arrays
143
+ var tmp = receiveSenderArray ;
144
+ this .receiveSenderArray = sendSenderArray ;
145
+ this .sendSenderArray = tmp ;
146
+ }
147
+
148
+ @ Override
149
+ public void initMessageIterator (
150
+ ReducingMessenger .SingleMessageIterator messageIterator ,
151
+ long nodeId ,
152
+ boolean isInitialIteration
153
+ ) {
154
+ var message = receiveArray .getAndReplace (nodeId , reducer .identity ());
155
+ var sender = receiveSenderArray .get (nodeId );
156
+ messageIterator .init (message , message != reducer .identity (), OptionalLong .of (sender ));
157
+ }
158
+
159
+ @ Override
160
+ public void sendTo (long sourceNodeId , long targetNodeId , double message ) {
161
+ sendArray .update (
162
+ targetNodeId ,
163
+ currentMessage -> {
164
+ var reducedMessage = reducer .reduce (currentMessage , message );
165
+ if (Double .compare (reducedMessage , currentMessage ) != 0 ) {
166
+ sendSenderArray .set (targetNodeId , sourceNodeId );
167
+ }
168
+ return reducedMessage ;
169
+ }
170
+ );
171
+ }
172
+
173
+ @ Override
174
+ public OptionalLong sender (long nodeId ) {
175
+ return OptionalLong .of (receiveSenderArray .get (nodeId ));
176
+ }
177
+
178
+ @ Override
179
+ public void release () {
180
+ sendSenderArray .release ();
181
+ receiveSenderArray .release ();
182
+ super .release ();
183
+ }
184
+ }
185
+
108
186
static class SingleMessageIterator implements Messages .MessageIterator {
109
187
110
188
boolean hasNext ;
111
189
double message ;
190
+ OptionalLong sender ;
112
191
113
- void init (double value , boolean hasNext ) {
192
+ void init (double value , boolean hasNext , OptionalLong sender ) {
114
193
this .message = value ;
115
194
this .hasNext = hasNext ;
195
+ this .sender = sender ;
116
196
}
117
197
118
198
@ Override
@@ -130,5 +210,10 @@ public double nextDouble() {
130
210
hasNext = false ;
131
211
return message ;
132
212
}
213
+
214
+ @ Override
215
+ public OptionalLong sender () {
216
+ return this .sender ;
217
+ }
133
218
}
134
219
}
0 commit comments