|
25 | 25 | import org.neo4j.gds.NodeLabel; |
26 | 26 | import org.neo4j.gds.api.BatchNodeIterable; |
27 | 27 | import org.neo4j.gds.api.IdMap; |
| 28 | +import org.neo4j.gds.core.concurrency.RunWithConcurrency; |
28 | 29 |
|
29 | 30 | import java.util.List; |
30 | 31 | import java.util.Random; |
31 | 32 | import java.util.concurrent.atomic.LongAdder; |
32 | 33 | import java.util.function.LongConsumer; |
33 | 34 | import java.util.function.LongUnaryOperator; |
| 35 | +import java.util.stream.LongStream; |
34 | 36 |
|
| 37 | +import static java.util.stream.Collectors.toList; |
35 | 38 | import static org.assertj.core.api.Assertions.assertThat; |
36 | 39 | import static org.assertj.core.api.Assertions.assertThatExceptionOfType; |
37 | 40 | import static org.assertj.core.api.Assertions.assertThatNoException; |
@@ -367,5 +370,28 @@ void shouldAddNodeIdsToLabel() { |
367 | 370 | assertThat(labelInformation.nodeLabelsForNodeId(3L)).contains(NodeLabel.of("B")); |
368 | 371 | } |
369 | 372 |
|
| 373 | + |
| 374 | + @Test |
| 375 | + void shouldAcceptConcurrentInserts() { |
| 376 | + var builder = MultiLabelInformation.Builder.of(110, List.of(), List.of()); |
| 377 | + |
| 378 | + // Create 10 tasks that try to insert overlapping node labels |
| 379 | + List<Runnable> tasks = LongStream |
| 380 | + .range(0, 10) |
| 381 | + .mapToObj(i -> |
| 382 | + (Runnable) () -> LongStream.range(i * 10, i * 10 + 20).forEach(l -> builder.addNodeIdToLabel(NodeLabel.of("" + l), l)) |
| 383 | + ).collect(toList()); |
| 384 | + |
| 385 | + RunWithConcurrency.builder() |
| 386 | + .tasks(tasks) |
| 387 | + .concurrency(4) |
| 388 | + .build() |
| 389 | + .run(); |
| 390 | + |
| 391 | + var map = builder.build(110, i -> i); |
| 392 | + |
| 393 | + LongStream.range(0, 110).forEach(i -> assertThat(map.hasLabel(i, NodeLabel.of("" + i))).isTrue()); |
| 394 | + } |
| 395 | + |
370 | 396 | } |
371 | 397 | } |
0 commit comments